/* ================================================================
   SETUSPAIN - PRODUCTION CSS
   Clean, organized, mobile-first approach
   ================================================================ */

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

:root {
    /* --------------------------------------------------------------
       Brand palette sampled directly from the SetuSpain logo:
       navy bridge #011A30, Bangladesh green #02522F
       Spanish red #E3081C, Spanish gold #F9AB0D
       -------------------------------------------------------------- */
    --brand-navy: #0F2C4D;
    --brand-navy-deep: #071A2F;
    --brand-green: #02522F;
    --brand-green-soft: #40705B;
    --brand-red: #E3081C;
    --brand-gold: #F9AB0D;

    --primary-color: #0F2C4D;   /* navy: links, buttons, structure */
    --secondary-color: #02522F; /* green: secondary accents */
    --accent-color: #E3081C;    /* red: highlights, hover */
    --highlight-color: #F9AB0D; /* gold: badges, underlines */

    --text-dark: #16202B;
    --text-light: #EDF1F5;
    --text-muted: #5B6B7C;
    --bg-dark: #0C1826;
    --bg-dark-soft: #132537;
    --bg-light: #ffffff;
    --bg-tint: #F5F8FA;
    --border-color: #DCE3EA;
    --border-dark: #24384D;
    --success-color: #02522F;
    
    --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
    
    --spacing-xs: 0.5rem;
    --spacing-sm: 1rem;
    --spacing-md: 1.5rem;
    --spacing-lg: 2rem;
    --spacing-xl: 3rem;
    
    /* Measured, not guessed: logo 60px + 1.5rem padding top and bottom + 1px
       border. Used by scroll-padding-top and by anything that has to sit clear
       of the header. */
    --nav-h: 109px;

    --radius-sm: 0.375rem;
    --radius-md: 0.5rem;
    --radius-lg: 1rem;
}

html {
    scroll-behavior: smooth;
}

/* The navbar is sticky, so an anchor jump scrolls the target to y=0, which is
   underneath it. scroll-padding-top pushes every anchored scroll down by the
   header height plus a little breathing room, which is what makes "Categories",
   "Latest" and the skip link land where the reader expects. */
html {
    scroll-padding-top: calc(var(--nav-h) + var(--spacing-sm));
}

body {
    font-family: var(--font-sans);
    font-size: 16px;
    line-height: 1.6;
    color: var(--text-dark);
    background-color: var(--bg-light);
    transition: background-color 0.3s, color 0.3s;
}

/* Dark mode */
body.dark-mode {
    background-color: var(--bg-dark);
    color: var(--text-light);
}

/* Container */
.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 var(--spacing-md);
}

/* ================================================================
   NAVBAR
   ================================================================ */

.navbar {
    background: var(--bg-light);
    border-bottom: 1px solid var(--border-color);
    position: sticky;
    top: 0;
    z-index: 1000;
    transition: background-color 0.3s;
}

body.dark-mode .navbar {
    background: var(--bg-dark);
    border-bottom-color: #374151;
}

.nav-container {
    max-width: 1200px;
    margin: 0 auto;
    padding: var(--spacing-md);
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.logo {
    display: flex;
    align-items: center;
    text-decoration: none;
    flex-shrink: 0;
}

.logo-img {
    height: 50px;
    width: auto;
    display: block;
}

/* Navigation Menu */
.nav-menu {
    display: flex;
    list-style: none;
    align-items: center;
    gap: var(--spacing-lg);
    margin: 0;
}

.nav-menu a {
    color: inherit;
    text-decoration: none;
    font-weight: 500;
    transition: color 0.3s;
}

.nav-menu a:hover {
    color: var(--primary-color);
}

/* ================================================================
   NAV DROPDOWN (Categories)

   One toggle, two presentations: a floating panel below the button on a
   wide screen where .nav-menu is a horizontal row, an inline accordion
   that expands in place on a narrow screen where .nav-menu is already a
   vertical stack (a floating panel would run off the edge of a phone
   screen there, or sit disconnected from the button that opened it).
   Both driven by the same .open class toggled in main.js; only the CSS
   differs per breakpoint, not the interaction.
   ================================================================ */

.nav-dropdown-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    background: none;
    border: none;
    padding: 0;
    color: inherit;
    font: inherit;
    font-weight: 500;
    cursor: pointer;
}
.nav-dropdown-toggle:hover { color: var(--primary-color); }

.nav-dropdown-arrow {
    display: inline-block;
    font-size: 0.7em;
    transition: transform 0.2s ease;
}
.nav-dropdown.open .nav-dropdown-arrow { transform: rotate(180deg); }

.nav-submenu {
    list-style: none;
    margin: 0;
    padding: 0;
}

.nav-bn {
    font-size: 0.82em;
    font-weight: 400;
    color: var(--text-muted);
}

@media (min-width: 769px) {
    .nav-dropdown { position: relative; }
    .nav-submenu {
        position: absolute;
        top: calc(100% + 12px);
        left: 50%;
        transform: translateX(-50%);
        min-width: 260px;
        background: var(--bg-light);
        border: 1px solid var(--border-color);
        border-radius: var(--radius-md);
        box-shadow: 0 15px 35px rgba(15, 44, 77, 0.18);
        padding: var(--spacing-sm);
        display: none;
        z-index: 500;
    }
    body.dark-mode .nav-submenu {
        background: var(--bg-dark-soft);
        border-color: var(--border-dark);
    }
    .nav-dropdown.open .nav-submenu { display: block; }
    .nav-submenu li a {
        display: flex;
        align-items: baseline;
        gap: 0.4rem;
        padding: 0.5rem 0.75rem;
        border-radius: var(--radius-sm);
        white-space: nowrap;
    }
    .nav-submenu li a:hover { background: var(--bg-tint); }
    body.dark-mode .nav-submenu li a:hover { background: rgba(255,255,255,0.06); }
}

/* Theme Button */
.theme-btn {
    background: none;
    border: 2px solid var(--primary-color);
    width: 44px;
    height: 44px;
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: 1.2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.3s;
}

.theme-btn:hover {
    background: var(--primary-color);
    color: white;
    transform: scale(1.1);
}

/* Menu Toggle (Mobile) */
.menu-toggle {
    display: none;
    flex-direction: column;
    background: none;
    border: none;
    cursor: pointer;
    gap: 6px;
}

.menu-toggle span {
    width: 25px;
    height: 3px;
    background: var(--text-dark);
    border-radius: 2px;
    transition: all 0.3s;
}

body.dark-mode .menu-toggle span {
    background: var(--text-light);
}

/* ================================================================
   HERO SECTION
   ================================================================ */

/* The original hero block is gone: it centred everything with flex and used
   the pre-brand purple gradient. Its replacement is in the HERO section near
   the end of this file. Leaving both in place meant the new rules were fighting
   a stale text-align: center that the cascade kept winning. */

.hero-content {
    max-width: 700px;
}

.hero h1 {
    font-size: 3rem;
    font-weight: 700;
    margin-bottom: var(--spacing-lg);
    line-height: 1.2;
}

.hero p {
    font-size: 1.25rem;
    color: #666;
    margin-bottom: var(--spacing-lg);
    line-height: 1.6;
}

body.dark-mode .hero p {
    color: #9ca3af;
}

.hero-buttons {
    display: flex;
    gap: var(--spacing-md);
    justify-content: center;
    flex-wrap: wrap;
}

/* ================================================================
   BUTTONS
   ================================================================ */

.btn {
    padding: var(--spacing-sm) var(--spacing-lg);
    border: none;
    border-radius: var(--radius-md);
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.3s;
    text-decoration: none;
    display: inline-block;
}

.btn-primary {
    background: var(--primary-color);
    color: white;
}

.btn-primary:hover {
    background: #1d4ed8;
    transform: translateY(-2px);
    box-shadow: 0 10px 20px rgba(37, 99, 235, 0.2);
}

.btn-secondary {
    background: transparent;
    color: var(--primary-color);
    border: 2px solid var(--primary-color);
}

.btn-secondary:hover {
    background: var(--primary-color);
    color: white;
}

/* ================================================================
   CATEGORIES
   ================================================================ */

.categories {
    padding: var(--spacing-xl) var(--spacing-md);
    background: var(--bg-light);
}

body.dark-mode .categories {
    background: #111827;
}

.categories h2,
.latest h2,

.category-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: var(--spacing-lg);
}

.category-card {
    background: var(--bg-light);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: var(--spacing-lg);
    text-decoration: none;
    color: inherit;
    transition: transform 0.3s, box-shadow 0.3s, border-color 0.3s, opacity 0.5s ease;
    text-align: center;
}

body.dark-mode .category-card {
    background: #1f2937;
    border-color: #374151;
}

.category-card:hover {
    transform: translateY(-5px);
    box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
    border-color: var(--primary-color);
}

body.dark-mode .category-card:hover {
    box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
}

/* A quick scale-down on touch, the tactile "this responded to me" feedback
   a hover-only effect can't give on a phone, since there is no hover
   there to begin with. */
.category-card:active { transform: scale(0.96); }

/* Cards fade and slide up into place as CategoryReveal (main.js) adds
   .in-view once each one scrolls into the viewport, staggered slightly
   per card via the --reveal-delay custom property it sets. Scoped to
   .js specifically (added to <html> before first paint, see head() in
   build.mjs) so a visitor without JavaScript, or JS that fails to load,
   sees every card immediately rather than permanently hidden -- this is
   a visual entrance, not something the content should ever depend on to
   become visible at all. */
.js .category-card {
    opacity: 0;
    transform: translateY(20px);
    transition: opacity 0.5s ease, transform 0.5s ease, box-shadow 0.3s, border-color 0.3s;
    transition-delay: var(--reveal-delay, 0s);
}
.js .category-card.in-view { opacity: 1; transform: translateY(0); }
.js .category-card.in-view:hover { transform: translateY(-5px); }
.js .category-card.in-view:active { transform: scale(0.96); }

.category-icon {
    font-size: 2.5rem;
    margin-bottom: var(--spacing-md);
    display: inline-block;
    transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
    transition-delay: var(--reveal-delay, 0s);
}
.js .category-card:not(.in-view) .category-icon { transform: scale(0.4); }

.category-card h3 {
    font-size: 1.25rem;
    margin-bottom: var(--spacing-sm);
}

.category-card p {
    color: #666;
    font-size: 0.95rem;
}

body.dark-mode .category-card p {
    color: #9ca3af;
}

/* ================================================================
   ARTICLES SECTION
   ================================================================ */

.latest {
    padding: var(--spacing-xl) var(--spacing-md);
    background: #f9fafb;
}

body.dark-mode .latest {
    background: #1f2937;
}

.articles-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: var(--spacing-lg);
}

.article-card {
    background: var(--bg-light);
    border-radius: var(--radius-lg);
    padding: var(--spacing-lg);
    transition: all 0.3s;
}

body.dark-mode .article-card {
    background: #111827;
}

.article-card:hover {
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
    transform: translateY(-5px);
}

.article-card:active { transform: scale(0.97); }

/* Same entrance-animation treatment as .category-card above, and the
   same reasoning: scoped to .js so a visitor without JavaScript sees
   every card immediately, never depending on a script to become visible
   at all. */
.js .article-card {
    opacity: 0;
    transform: translateY(20px);
    transition: opacity 0.5s ease, transform 0.5s ease, box-shadow 0.3s;
    transition-delay: var(--reveal-delay, 0s);
}
.js .article-card.in-view { opacity: 1; transform: translateY(0); }
.js .article-card.in-view:hover { transform: translateY(-5px); }
.js .article-card.in-view:active { transform: scale(0.97); }

body.dark-mode .article-card:hover {
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
}

.article-card h3 {
    font-size: 1.25rem;
    margin-bottom: var(--spacing-sm);
}

.article-meta {
    color: #666;
    font-size: 0.9rem;
    margin-bottom: var(--spacing-md);
}

body.dark-mode .article-meta {
    color: #9ca3af;
}

.article-card p {
    margin-bottom: var(--spacing-md);
    line-height: 1.6;
}

.read-more {
    color: var(--primary-color);
    text-decoration: none;
    font-weight: 600;
    transition: all 0.3s;
}

.read-more:hover {
    color: var(--secondary-color);
}

/* ================================================================
   FOOTER
   ================================================================ */

.footer {
    background: var(--bg-dark);
    color: var(--text-light);
    padding: var(--spacing-xl) var(--spacing-md);
}

.footer-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: var(--spacing-xl);
    margin-bottom: var(--spacing-xl);
}

.footer-section h4 {
    font-size: 1.1rem;
    margin-bottom: var(--spacing-md);
}

/* Looks and behaves like the plain h4 it wraps until the mobile+JS scope
   further down turns it into a real accordion control -- reset here so
   desktop and no-JS visitors see no visual or functional difference at
   all from before this existed. */
.footer-toggle {
    display: block;
    width: 100%;
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    text-align: left;
    color: inherit;
    font: inherit;
    cursor: default;
}

.footer-toggle h4 { margin-bottom: var(--spacing-md); }

.footer-chevron { display: none; }

.footer-panel { display: block; }

/* Below this width, with JS available to actually drive the toggle: the
   three link-list sections become real accordions, collapsed by default,
   and sit as an explicit 3-column grid rather than each stacking full-
   width -- the two changes reported together (the footer reading as one
   long, undifferentiated scroll). About is deliberately excluded: it has
   no list to hide behind a tap, so it keeps spanning full width above
   the row of three as its own, non-interactive section. Scoped to .js
   specifically so a no-JS visitor -- who would have no way to open a
   collapsed panel -- instead sees every link already expanded, same as
   before this existed. */
@media (max-width: 768px) {
    .js .footer-grid {
        grid-template-columns: repeat(3, 1fr);
        gap: var(--spacing-md);
    }

    .js .footer-grid > .footer-section:not(.footer-fold) {
        grid-column: 1 / -1;
    }

    .js .footer-toggle {
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--spacing-xs);
    }

    .js .footer-toggle h4 {
        font-size: 0.92rem;
        margin-bottom: 0;
    }

    .js .footer-chevron {
        display: block;
        flex-shrink: 0;
        width: 9px;
        height: 9px;
        border-right: 2px solid currentColor;
        border-bottom: 2px solid currentColor;
        transform: rotate(45deg);
        transition: transform 0.2s ease;
        margin-top: -3px;
    }

    .js .footer-toggle[aria-expanded="true"] .footer-chevron {
        transform: rotate(-135deg);
        margin-top: 3px;
    }

    .js .footer-panel {
        display: none;
        margin-top: var(--spacing-sm);
    }

    .js .footer-panel.open {
        display: block;
    }

    .js .footer-section.footer-fold ul li {
        font-size: 0.88rem;
    }
}

.footer-section ul {
    list-style: none;
}

.footer-section ul li {
    margin-bottom: var(--spacing-sm);
}

.footer-section a {
    color: #d1d5db;
    text-decoration: none;
    transition: color 0.3s;
}

.footer-section a:hover {
    color: var(--primary-color);
}

.footer-bottom {
    text-align: center;
    padding-top: var(--spacing-lg);
    border-top: 1px solid #374151;
    color: #9ca3af;
}

/* ================================================================
   RESPONSIVE DESIGN - MOBILE
   ================================================================ */

@media (max-width: 768px) {
    :root { --nav-h: 89px; }

    .logo-img {
        height: 40px;
    }

    .nav-menu {
        gap: var(--spacing-md);
    }

    .menu-toggle {
        display: flex;
    }

    /* top: 100% pins the panel to the bottom edge of the navbar whatever its
       height turns out to be. The previous value was a hard-coded 70px against
       an 89px navbar, so the panel sat 19px too high and covered the logo. */
    .nav-menu {
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        background: var(--bg-light);
        flex-direction: column;
        align-items: stretch;
        padding: 0 var(--spacing-lg);
        border-bottom: 1px solid var(--border-color);
        box-shadow: 0 10px 24px rgba(15, 44, 77, 0.12);
        max-height: 0;
        overflow: hidden;
        transition: max-height 0.3s ease, padding 0.3s ease;
        gap: 0;
    }

    body.dark-mode .nav-menu {
        background: var(--bg-dark);
        border-bottom-color: #374151;
    }

    /* A fixed pixel cap silently clips whatever is added last. This menu grew
       from three items to six and the theme button, 56px past the old 300px
       limit, ended up cut in half. Bounded by the viewport instead, and
       scrollable if it ever outgrows even that. */
    .nav-menu.open {
        max-height: min(75vh, 520px);
        overflow-y: auto;
        padding: var(--spacing-sm) var(--spacing-lg);
        overscroll-behavior: contain;
    }

    /* Full-width rows give a proper touch target rather than a text-sized one.
       A hairline divider between rows replaces what used to be a 24px gap on
       top of an already-generous 44px-tall row: the row height alone already
       meets the touch-target guidance (WCAG 2.5.5, Apple HIG), so that gap
       was pure dead space between items, not anything doing real work, and
       reads as broken rather than spacious once there are six of them. */
    .nav-menu li { width: 100%; border-bottom: 1px solid var(--border-color); }
    .nav-menu li:last-child { border-bottom: none; }
    body.dark-mode .nav-menu li { border-bottom-color: #374151; }

    .nav-menu a {
        display: block;
        padding: 0;
        min-height: 44px;
        line-height: 44px;
    }

    .nav-menu .theme-btn { margin: var(--spacing-xs) 0; }

    /* Mobile: the submenu expands in place, an accordion within the
       already-vertical menu, rather than the floating panel used at
       desktop width (see the min-width: 769px block above) -- a floating
       panel would either run off the edge of the screen here or sit
       disconnected from the button that opened it. */
    .nav-dropdown-toggle {
        display: flex;
        width: 100%;
        justify-content: space-between;
        min-height: 44px;
        line-height: 44px;
    }
    .nav-submenu {
        max-height: 0;
        overflow: hidden;
        transition: max-height 0.3s ease;
    }
    .nav-dropdown.open .nav-submenu { max-height: 600px; }
    .nav-submenu li { border-bottom: none; padding-left: var(--spacing-md); }
    .nav-submenu li:not(:last-child) { border-bottom: 1px solid var(--border-color); }
    body.dark-mode .nav-submenu li:not(:last-child) { border-bottom-color: #374151; }
    .nav-submenu a { display: flex; align-items: baseline; gap: 0.4rem; flex-wrap: wrap; }
    .nav-search span { display: inline; }

    .hero {
        padding: var(--spacing-lg) var(--spacing-md);
        min-height: 400px;
    }

    .hero h1 {
        font-size: 2rem;
    }

    .hero p {
        font-size: 1rem;
    }

    .hero-buttons {
        flex-direction: column;
    }

    .btn {
        width: 100%;
    }

    .category-grid {
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
        gap: var(--spacing-md);
    }

    .categories h2,
    .latest h2,
    .contribute h2 {
        font-size: 1.75rem;
    }
}

@media (max-width: 480px) {
    :root { --nav-h: 84px; }

    .logo-img {
        height: 35px;
    }

    .hero h1 {
        font-size: 1.5rem;
    }

    .hero p {
        font-size: 0.95rem;
    }

    .category-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--spacing-sm);
    }

    .category-card {
        padding: var(--spacing-sm) var(--spacing-xs);
    }

    .category-icon {
        font-size: 1.8rem;
        margin-bottom: 0.35rem;
    }

    .category-card h3 {
        font-size: 0.88rem;
        line-height: 1.25;
        margin-bottom: 0.2rem;
    }

    /* The blurb sentence wraps to several lines at this width and makes
       cards tall and uneven side by side; icon, title and count alone
       read as a clean, scannable grid tile instead. */
    .category-card p { display: none; }

    .category-count { font-size: 0.7rem; }

    .articles-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--spacing-sm);
    }

    .article-card {
        padding: var(--spacing-sm) var(--spacing-xs);
    }

    .article-card h3 {
        font-size: 0.92rem;
        line-height: 1.3;
        margin-bottom: 0.3rem;
    }

    .article-meta {
        font-size: 0.72rem;
        margin-bottom: 0.4rem;
    }

    /* The description is a full sentence that wraps to several lines at
       this width and makes cards tall and uneven side by side, the same
       reasoning as hiding .category-card p above; title, meta and the
       read-more link alone read as a clean, scannable tile. */
    .article-card p { display: none; }

    .read-more { font-size: 0.85rem; }

    .footer-grid {
        grid-template-columns: 1fr;
    }

    .categories h2,
    .latest h2,
    .contribute h2 {
        font-size: 1.5rem;
    }
}

/* ================================================================
   COOKIE BANNER
   ================================================================ */

.cookie-banner {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--bg-dark);
    color: var(--text-light);
    padding: var(--spacing-lg);
    z-index: 9999;
    box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.3);
    animation: slideUp 0.3s ease-out;
}

@keyframes slideUp {
    from {
        transform: translateY(100%);
    }
    to {
        transform: translateY(0);
    }
}

.cookie-content {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--spacing-lg);
    flex-wrap: wrap;
}

.cookie-notice {
    flex: 1;
    min-width: 300px;
}

.cookie-notice a {
    color: var(--primary-color);
    text-decoration: none;
}

.cookie-notice a:hover {
    text-decoration: underline;
}

.cookie-actions {
    display: flex;
    gap: var(--spacing-md);
    white-space: nowrap;
}

.cookie-close {
    background: transparent;
    color: var(--text-light);
    border-color: var(--text-light);
}

.cookie-close:hover {
    background: var(--text-light);
    color: var(--bg-dark);
}

@media (max-width: 768px) {
    .cookie-content {
        flex-direction: column;
        align-items: stretch;
    }

    .cookie-actions {
        width: 100%;
    }

    .cookie-actions button {
        flex: 1;
    }

    .cookie-banner {
        padding: var(--spacing-md);
    }
}

/* ================================================================
   LOGO VARIATIONS & STYLING
   ================================================================ */

.logo {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    transition: opacity 0.3s ease;
}

.logo:hover {
    opacity: 0.9;
}

.logo-img {
    height: 60px;
    width: auto;
    display: block;
    object-fit: contain;
    object-position: center left;
    transition: filter 0.3s ease, transform 0.2s ease, opacity 0.3s ease;
}

.logo-img:hover {
    transform: scale(1.05);
}

/* The wordmark is real text, not baked into the image: it stays crisp at
   any zoom level, follows the theme's colours automatically instead of
   needing a second raster asset, and gives the link a real accessible name
   (the icon itself is alt="", decorative, so a screen reader announces
   "SetuSpain" once, not the icon's description and then the visible text
   again). */
.logo-wordmark {
    margin-left: 10px;
    font-family: system-ui, sans-serif;
    font-weight: 800;
    font-size: 1.5rem;
    line-height: 1;
    white-space: nowrap;
    letter-spacing: -0.01em;
}

.logo-setu { color: var(--brand-navy); }
.logo-spain { color: var(--brand-red); }

body.dark-mode .logo-setu { color: var(--text-light); }
body.dark-mode .logo-spain { color: #ff5468; } /* brand-red brightened; the
    base red reads muddy against a dark background at text size, where the
    icon's red (much larger and outlined) does not have the same problem. */

/* Responsive logo sizing */
@media (max-width: 768px) {
    .logo-img {
        height: 50px;
    }
    .logo-wordmark {
        font-size: 1.25rem;
        margin-left: 8px;
    }
}

@media (max-width: 480px) {
    .logo-img {
        height: 40px;
    }
    .logo-wordmark {
        font-size: 1.05rem;
        margin-left: 6px;
    }
}

/* Below this, the wordmark plus the hamburger button plus the search icon
   no longer fit on one line without wrapping. The icon alone still reads as
   the site mark; the wordmark reappears the moment there is room again. */
@media (max-width: 360px) {
    .logo-wordmark { display: none; }
}

/* ================================================================
   NAVBAR LOGO CONTAINER
   ================================================================ */

/* Smooth transitions */
* {
    transition-property: background-color, color, border-color;
    transition-duration: 0.3s;
}

/* Skip transitions for specific elements to avoid flickering */
.theme-btn,
.btn,
.category-card,
.article-card {
    transition-property: all;
    transition-duration: 0.3s;
}

/* Accessibility */
@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* Focus visible for keyboard navigation */
button:focus-visible,
a:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}

/* ================================================================
   LANGUAGE HANDLING
   Interface chrome stays English; only content marked lang="bn"
   uses the Bangla font stack.
   ================================================================ */

[lang="bn"] {
    font-family: 'Noto Sans Bengali', 'Hind Siliguri', 'SolaimanLipi',
                 'Nirmala UI', 'Shonar Bangla', system-ui, sans-serif;
    line-height: 1.9;
}

.navbar, .footer, .breadcrumb, .cookie-banner,
.article-meta, .article-item-meta, .article-disclaimer, .article-nav {
    font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
}

/* ================================================================
   BREADCRUMB
   ================================================================ */

.breadcrumb {
    border-bottom: 1px solid var(--border-color);
    font-size: 0.9rem;
}

.breadcrumb-inner {
    max-width: 1200px;
    margin: 0 auto;
    padding: var(--spacing-sm) var(--spacing-md);
    display: flex;
    gap: var(--spacing-xs);
    align-items: center;
    flex-wrap: wrap;
    color: #6b7280;
}

.breadcrumb a { color: var(--primary-color); text-decoration: none; }
.breadcrumb a:hover { text-decoration: underline; }
body.dark-mode .breadcrumb-inner { color: #9ca3af; }

/* ================================================================
   CATEGORY PAGES
   ================================================================ */

.category-header {
    background: linear-gradient(135deg, rgba(37,99,235,0.08), rgba(124,58,237,0.08));
    padding: var(--spacing-xl) 0;
    margin-bottom: var(--spacing-xl);
}

.category-header h1 { font-size: 2.25rem; margin-bottom: var(--spacing-sm); }
.category-header p { color: #4b5563; font-size: 1.05rem; margin: 0; }
body.dark-mode .category-header p { color: #9ca3af; }

.category-main { padding-bottom: var(--spacing-xl); }
.category-main h2 { font-size: 1.4rem; margin-bottom: var(--spacing-lg); }
.category-main .count { color: #6b7280; font-weight: 400; }

.category-count {
    display: inline-block;
    margin-top: var(--spacing-xs);
    font-size: 0.85rem;
    color: var(--primary-color);
    font-weight: 600;
}

.articles-list { display: grid; gap: var(--spacing-md); }

/* The exams hub used to list every quiz from every category on one page,
   reported as having grown too large as content deepened. Each category
   now has its own dedicated page (exams/{category-slug}.html); this hub
   just links out via one card per category, styled close to the
   existing article-card look (background, radius, hover lift) but as a
   single clickable link like category-card, since the whole card should
   navigate, not just a "read more" line inside it. */
.exams-hub-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: var(--spacing-lg);
}

.exams-hub-card {
    display: block;
    background: var(--bg-light);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: var(--spacing-lg);
    text-decoration: none;
    color: inherit;
    transition: transform 0.3s, box-shadow 0.3s, border-color 0.3s;
}

body.dark-mode .exams-hub-card {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
}

.exams-hub-card:hover {
    transform: translateY(-5px);
    box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
    border-color: var(--primary-color);
}

body.dark-mode .exams-hub-card:hover {
    box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
}

.exams-hub-card:active { transform: scale(0.97); }

.exams-hub-card h2 { font-size: 1.3rem; margin-bottom: var(--spacing-sm); }
.exams-hub-card p { margin-bottom: var(--spacing-sm); line-height: 1.5; }
.exams-hub-card .exams-hub-stats { color: var(--text-muted); font-size: 0.88rem; margin-bottom: var(--spacing-md); }

/* These cards lost their description paragraph specifically so they could
   go compact and sit several to a row -- unlike the plain .articles-list
   cards elsewhere (regular category listings, search results), which
   keep a full description and stay single-column since a grid of tall,
   uneven text blocks reads worse than a clean list. Reuses the exact
   auto-fit pattern already proven on .articles-grid rather than a new one. */
.articles-list.quiz-grid {
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.quiz-grid .article-item { padding: var(--spacing-md); }
.quiz-grid .article-item h4 { font-size: 1.05rem; }
.quiz-grid .article-item-meta { font-size: 0.78rem; gap: var(--spacing-sm); }

/* Placed here, right after the base rule, deliberately: this selector has
   the same specificity as the one above, so with an earlier media query
   the base rule (being later in the file) would keep winning regardless
   of viewport width. Source order after the rule it overrides is what
   actually makes the override take effect, not the media query alone. */
@media (max-width: 480px) {
    .articles-list.quiz-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--spacing-sm);
    }

    .quiz-grid .article-item { padding: var(--spacing-sm) var(--spacing-xs); }
    .quiz-grid .article-item h4 { font-size: 0.88rem; line-height: 1.3; }
    .quiz-grid .article-item-meta { font-size: 0.7rem; gap: 0.35rem; }
    .quiz-grid .quiz-number { font-size: 0.85em; }
}

.article-item {
    display: block;
    padding: var(--spacing-lg);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: inherit;
    transition: border-color 0.25s ease, transform 0.2s ease, box-shadow 0.25s ease;
}

.article-item:hover {
    border-color: var(--primary-color);
    transform: translateY(-2px);
    box-shadow: 0 4px 14px rgba(37, 99, 235, 0.12);
}

.article-item h3 { font-size: 1.3rem; margin: 0 0 var(--spacing-sm); }
/* Same visual treatment for a card title one level deeper in the
   hierarchy: used specifically when the card sits under a subsection
   heading (category h2 > subsection h3 > card h4) rather than directly
   under the category itself, so heading levels nest correctly instead of
   reusing h3 for two different levels of the same page. */
.article-item h4 { font-size: 1.3rem; margin: 0 0 var(--spacing-sm); font-weight: 700; }

.article-item-meta {
    display: flex;
    gap: var(--spacing-md);
    flex-wrap: wrap;
    color: #6b7280;
    font-size: 0.85rem;
    margin-bottom: var(--spacing-sm);
}
body.dark-mode .article-item-meta { color: #9ca3af; }

.article-item-desc { margin: 0 0 var(--spacing-sm); }
.read-more-btn { color: var(--primary-color); font-weight: 600; }

.no-articles {
    text-align: center;
    padding: var(--spacing-xl);
    border: 1px dashed var(--border-color);
    border-radius: var(--radius-md);
    color: #6b7280;
}
body.dark-mode .no-articles { color: #9ca3af; }

/* ================================================================
   ARTICLE PAGES
   ================================================================ */

.article-container {
    max-width: 820px;
    margin: 0 auto;
    padding: var(--spacing-xl) var(--spacing-md);
}

.article-header {
    border-bottom: 2px solid var(--border-color);
    padding-bottom: var(--spacing-lg);
    margin-bottom: var(--spacing-xl);
}

.article-title { font-size: 2rem; line-height: 1.4; margin-bottom: var(--spacing-md); }

.article-meta {
    display: flex;
    gap: var(--spacing-md);
    flex-wrap: wrap;
    color: #6b7280;
    font-size: 0.9rem;
}
body.dark-mode .article-meta { color: #9ca3af; }

.article-body h2 { font-size: 1.5rem; margin: var(--spacing-xl) 0 var(--spacing-md); }
.article-body h3 { font-size: 1.2rem; margin: var(--spacing-lg) 0 var(--spacing-sm); }
.article-body p { margin-bottom: var(--spacing-md); }
.article-body ul, .article-body ol { margin: 0 0 var(--spacing-lg) var(--spacing-lg); }
.article-body li { margin-bottom: var(--spacing-xs); }

.info-box, .tip-box, .warning-box {
    padding: var(--spacing-md);
    border-radius: var(--radius-md);
    border-left: 4px solid;
    margin: var(--spacing-lg) 0;
}

.info-box { background: #eff6ff; border-color: #2563eb; }
.tip-box { background: #f0fdf4; border-color: #16a34a; }
.warning-box { background: #fef2f2; border-color: #dc2626; }

.info-box p:last-child,
.tip-box p:last-child,
.warning-box p:last-child { margin-bottom: 0; }

body.dark-mode .info-box { background: rgba(37, 99, 235, 0.12); }
body.dark-mode .tip-box { background: rgba(22, 163, 74, 0.12); }
body.dark-mode .warning-box { background: rgba(220, 38, 38, 0.12); }

.article-source {
    margin-top: var(--spacing-xl);
    padding-top: var(--spacing-md);
    border-top: 1px solid var(--border-color);
    font-size: 0.95rem;
}

.article-disclaimer {
    margin-top: var(--spacing-md);
    padding: var(--spacing-md);
    background: rgba(107, 114, 128, 0.08);
    border-radius: var(--radius-md);
    font-size: 0.85rem;
    color: #4b5563;
}
body.dark-mode .article-disclaimer { color: #9ca3af; }

.article-nav {
    display: flex;
    gap: var(--spacing-sm);
    flex-wrap: wrap;
    margin-top: var(--spacing-xl);
}

.article-nav .btn { text-decoration: none; display: inline-block; }

@media (max-width: 768px) {
    .article-title { font-size: 1.5rem; }
    .category-header h1 { font-size: 1.75rem; }
}

/* ================================================================
   BRAND THEME OVERRIDES  (logo-derived)
   Loaded last so it wins over earlier generic rules.
   ================================================================ */

/* --- Dark mode surfaces tuned to the navy in the logo --- */
body.dark-mode {
    --primary-color: #7FB0E0;
    --secondary-color: #5FA97F;
    --accent-color: #FF5A63;
    --border-color: var(--border-dark);
    --text-muted: #93A5B8;
    /* Never redefined for dark mode anywhere before this: every one of
       its ~16 uses site-wide (search-box hover, card backgrounds, and
       figures such as nuss-vs-alta.svg already shipped) stayed at its
       light-mode value regardless of theme. Reusing --bg-dark-soft since
       that's already the established "light background area" colour for
       dark mode elsewhere (see .fig's own dark-mode override). */
    --bg-tint: var(--bg-dark-soft);
    background-color: var(--bg-dark);
}

body.dark-mode .navbar,
body.dark-mode .footer,
body.dark-mode .breadcrumb {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
}

body.dark-mode .category-card,
body.dark-mode .article-card,
body.dark-mode .article-item {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
}

/* --- Navbar: gold hairline echoes the ribbon in the logo --- */
.navbar {
    border-bottom: 1px solid var(--border-color);
    box-shadow: 0 1px 0 rgba(249, 171, 13, 0.35);
}

.nav-menu a {
    color: var(--text-dark);
    font-weight: 500;
}

body.dark-mode .nav-menu a { color: var(--text-light); }
.nav-menu a:hover { color: var(--accent-color); }

/* --- Buttons --- */
.btn {
    display: inline-block;
    text-decoration: none;
    text-align: center;
    cursor: pointer;
    font-weight: 600;
    border-radius: var(--radius-md);
    transition: background-color 0.2s ease, color 0.2s ease,
                border-color 0.2s ease, transform 0.15s ease;
}

.btn:active { transform: translateY(1px); }

.btn-primary {
    background: var(--brand-navy);
    color: #fff;
    border: 2px solid var(--brand-navy);
}

.btn-primary:hover {
    background: var(--brand-red);
    border-color: var(--brand-red);
    color: #fff;
}

.btn-secondary {
    background: transparent;
    color: var(--brand-navy);
    border: 2px solid var(--brand-navy);
}

.btn-secondary:hover {
    background: var(--brand-navy);
    color: #fff;
}

body.dark-mode .btn-primary {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: var(--bg-dark);
}

body.dark-mode .btn-secondary {
    color: var(--primary-color);
    border-color: var(--primary-color);
}

body.dark-mode .btn-secondary:hover {
    background: var(--primary-color);
    color: var(--bg-dark);
}

/* --- Section headings get a gold underline --- */
.categories h2,
.latest h2,
.category-main h2 {
    position: relative;
    padding-bottom: var(--spacing-xs);
}

.categories h2::after,
.latest h2::after,
.category-main h2::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 56px;
    height: 3px;
    background: var(--brand-gold);
    border-radius: 2px;
}

/* --- Cards --- */
.category-card,
.article-card {
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    border-top: 3px solid var(--brand-navy);
    background: var(--bg-light);
    transition: transform 0.2s ease, box-shadow 0.25s ease, border-color 0.2s ease;
}

.category-card:hover,
.article-card:hover {
    transform: translateY(-3px);
    border-top-color: var(--brand-red);
    box-shadow: 0 8px 22px rgba(15, 44, 77, 0.12);
}

body.dark-mode .category-card:hover,
body.dark-mode .article-card:hover {
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.45);
}

.article-item { border-left: 3px solid var(--brand-green); }
.article-item:hover { border-left-color: var(--brand-red); }

/* --- Category header banner --- */
.category-header {
    background: linear-gradient(135deg,
        rgba(2, 82, 47, 0.10), rgba(15, 44, 77, 0.10) 55%, rgba(227, 8, 28, 0.10));
    border-bottom: 1px solid var(--border-color);
}

body.dark-mode .category-header {
    background: linear-gradient(135deg,
        rgba(2, 82, 47, 0.28), rgba(15, 44, 77, 0.28) 55%, rgba(227, 8, 28, 0.20));
}

.category-header h1 { color: var(--brand-navy); }
body.dark-mode .category-header h1 { color: var(--text-light); }

/* --- Content boxes recoloured to brand --- */
.info-box   { background: rgba(15, 44, 77, 0.06);  border-color: var(--brand-navy); }
.tip-box    { background: rgba(2, 82, 47, 0.07);   border-color: var(--brand-green); }
.warning-box{ background: rgba(227, 8, 28, 0.06);  border-color: var(--brand-red); }

body.dark-mode .info-box    { background: rgba(127, 176, 224, 0.12); border-color: var(--primary-color); }
body.dark-mode .tip-box     { background: rgba(95, 169, 127, 0.12);  border-color: var(--secondary-color); }
body.dark-mode .warning-box { background: rgba(255, 90, 99, 0.12);   border-color: var(--accent-color); }

/* --- Footer --- */
.footer {
    background: var(--brand-navy-deep);
    color: var(--text-light);
    border-top: 3px solid var(--brand-gold);
    padding: var(--spacing-xl) 0 var(--spacing-lg);
}

.footer h4 { color: #fff; margin-bottom: var(--spacing-sm); }
.footer p, .footer li { color: #C4D0DC; }
.footer ul { list-style: none; }
.footer a { color: #C4D0DC; text-decoration: none; }
.footer a:hover { color: var(--brand-gold); text-decoration: underline; }

.footer-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--spacing-lg);
}

.footer-bottom {
    margin-top: var(--spacing-lg);
    padding-top: var(--spacing-md);
    border-top: 1px solid rgba(255, 255, 255, 0.14);
    text-align: center;
    font-size: 0.9rem;
}

/* --- Cookie banner --- */
.cookie-banner { background: var(--brand-navy-deep); color: var(--text-light); }
.cookie-banner a { color: var(--brand-gold); }

/* --- Focus visibility (accessibility) --- */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
    outline: 3px solid var(--brand-gold);
    outline-offset: 2px;
    border-radius: 3px;
}

/* --- Skip link --- */
.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    background: var(--brand-navy);
    color: #fff;
    padding: 0.75rem 1rem;
    z-index: 2000;
    border-radius: 0 0 var(--radius-md) 0;
}

.skip-link:focus { left: 0; }

/* --- Print --- */
@media print {
    .navbar, .footer, .cookie-banner, .article-nav,
    .contribute, .breadcrumb, .menu-toggle { display: none !important; }
    body { color: #000; background: #fff; }
    .article-container { max-width: 100%; }
}

/* Print watermark: a real <img>, not a CSS background-image, since many
   browsers suppress background images by default in print output unless
   the reader specifically enables "background graphics" in the print
   dialog, which most people never touch. An actual image element is
   real content as far as the print engine is concerned, so it renders
   regardless of that setting. Hidden on screen always; only shown, and
   only positioned, inside the print media query below. position: fixed
   is the only way to place it independent of document flow across a
   print engine, but fixed elements repeating on every printed page
   (rather than only the first) is a real, browser-dependent limitation
   of CSS print rendering, not something this rule alone controls. */
.print-watermark { display: none; }

@media print {
    .print-watermark {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 0.5rem;
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%) rotate(-30deg);
        opacity: 0.08;
        z-index: 9999;
        pointer-events: none;
    }
    .print-watermark img { width: 260px; height: 260px; }
    .print-watermark span {
        font-family: system-ui, sans-serif;
        font-size: 1.4rem;
        font-weight: 800;
        color: #0F2C4D;
        letter-spacing: 0.05em;
    }
}

/* --- Reduced motion --- */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ================================================================
   ARTICLE COVER IMAGE (used by posts made in the composer)
   ================================================================ */

.article-cover {
    width: 100%;
    max-height: 420px;
    object-fit: cover;
    border-radius: var(--radius-md);
    margin-bottom: var(--spacing-lg);
    display: block;
    border-bottom: 3px solid var(--brand-gold);
}

@media (max-width: 768px) {
    .article-cover { max-height: 260px; }
}

/* Screen-reader-only utility */
.visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0);
    white-space: nowrap; border: 0;
}

/* ================================================================
   CONTRIBUTE / COMPOSE ENTRY POINTS
   ================================================================ */

.contribute {
    background: linear-gradient(135deg,
        rgba(2, 82, 47, 0.10), rgba(15, 44, 77, 0.10) 55%, rgba(227, 8, 28, 0.08));
    padding: var(--spacing-xl) 0;
    text-align: center;
    border-top: 1px solid var(--border-color);
}

body.dark-mode .contribute {
    background: linear-gradient(135deg,
        rgba(2, 82, 47, 0.25), rgba(15, 44, 77, 0.25) 55%, rgba(227, 8, 28, 0.16));
    border-color: var(--border-dark);
}

.contribute h2 { margin-bottom: var(--spacing-xs); }
.contribute p {
    color: var(--text-muted);
    max-width: 560px;
    margin: 0 auto var(--spacing-md);
}
body.dark-mode .contribute p { color: #B6C4D2; }

.footer-cta {
    margin-top: var(--spacing-lg);
    padding-top: var(--spacing-md);
    border-top: 1px solid rgba(255, 255, 255, 0.14);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-sm);
    flex-wrap: wrap;
    text-align: center;
}

.footer-cta p { margin: 0; color: #C4D0DC; }

.btn-compose {
    background: var(--brand-gold);
    color: #1a1205;
    border: 2px solid var(--brand-gold);
    padding: 0.6rem 1.2rem;
    font-weight: 700;
    text-decoration: none;
    border-radius: var(--radius-md);
    display: inline-block;
    transition: background-color 0.2s ease, color 0.2s ease, transform 0.15s ease;
}

.btn-compose:hover {
    background: #fff;
    border-color: #fff;
    color: var(--brand-navy-deep);
}

.btn-compose:active { transform: translateY(1px); }

/* ================================================================
   POLICY TABLES
   ================================================================ */

.policy-table {
    width: 100%;
    border-collapse: collapse;
    margin: var(--spacing-md) 0 var(--spacing-lg);
    font-size: 0.9rem;
}

.policy-table th,
.policy-table td {
    border: 1px solid var(--border-color);
    padding: 0.6rem 0.7rem;
    text-align: left;
    vertical-align: top;
}

.policy-table th {
    background: var(--bg-tint);
    font-weight: 700;
}

body.dark-mode .policy-table th { background: var(--bg-dark-soft); }
body.dark-mode .policy-table th,
body.dark-mode .policy-table td { border-color: var(--border-dark); }

.policy-table code {
    font-size: 0.85em;
    background: rgba(15, 44, 77, 0.08);
    padding: 0.1rem 0.3rem;
    border-radius: 3px;
    word-break: break-all;
}

body.dark-mode .policy-table code { background: rgba(255, 255, 255, 0.1); }

/* Tables scroll rather than overflow on small screens */
@media (max-width: 640px) {
    .policy-table { display: block; overflow-x: auto; white-space: nowrap; }
}

/* ================================================================
   AD SLOTS
   Reserved height prevents the page jumping when an ad loads, which
   is both a Core Web Vitals problem and an accidental-click problem.
   ================================================================ */

.ad-slot {
    display: block;
    margin: var(--spacing-xl) 0;
    padding: var(--spacing-sm) 0;
    min-height: 100px;
    text-align: center;
    border-top: 1px solid var(--border-color);
    border-bottom: 1px solid var(--border-color);
    overflow: hidden;
}

.ad-label {
    display: block;
    font-size: 0.68rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: var(--spacing-xs);
}

.ad-slot .adsbygoogle { min-height: 90px; }

/* Keep a clear gap from real links so no one taps an ad by accident */
.ad-slot + *, * + .ad-slot { margin-top: var(--spacing-xl); }

/* ================================================================
   ABOUT / CONTACT / AUTHOR
   ================================================================ */

.author-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: var(--spacing-md);
    margin: var(--spacing-md) 0 var(--spacing-lg);
}

.author-card {
    border: 1px solid var(--border-color);
    border-left: 3px solid var(--brand-green);
    border-radius: var(--radius-md);
    padding: var(--spacing-md);
}

body.dark-mode .author-card { border-color: var(--border-dark); border-left-color: var(--secondary-color); }

.author-card h3 { margin-bottom: 0.15rem; font-size: 1.05rem; }

.author-role {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    margin-bottom: var(--spacing-xs);
}

.author-box {
    margin-top: var(--spacing-xl);
    padding: var(--spacing-md);
    border: 1px solid var(--border-color);
    border-left: 3px solid var(--brand-gold);
    border-radius: var(--radius-md);
    font-size: 0.92rem;
}

body.dark-mode .author-box { border-color: var(--border-dark); border-left-color: var(--brand-gold); }

.author-box h2 {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--text-muted);
    margin-bottom: var(--spacing-xs);
}

.author-box p { margin-bottom: var(--spacing-xs); }

.contact-email {
    font-size: 1.3rem;
    font-weight: 700;
    margin: var(--spacing-md) 0 var(--spacing-lg);
    word-break: break-all;
}

.policy-table .table-section {
    background: var(--bg-tint);
    font-weight: 700;
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

body.dark-mode .policy-table .table-section { background: var(--bg-dark-soft); }

.policy-table .muted, .muted-note { color: var(--text-muted); font-size: 0.85rem; }

.linklike {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: #C4D0DC;
    cursor: pointer;
    text-decoration: none;
}

.linklike:hover { color: var(--brand-gold); text-decoration: underline; }

@media print { .ad-slot { display: none !important; } }

/* Transparent PNG logos: nothing behind them, so no background bleed */
.logo-img {
    background: transparent;
    image-rendering: -webkit-optimize-contrast;
}

.big-404 {
    font-size: 4rem;
    line-height: 1;
    margin-bottom: 0.5rem;
    color: var(--brand-navy);
}

body.dark-mode .big-404 { color: var(--primary-color); }

.legal-content .big-404 + h2 { margin-top: 0; }

.legal-content.text-center { text-align: center; }

/* ================================================================
   ARTICLE AUDIO PLAYER
   ================================================================ */

.listen {
    --played: 0%;
    margin: var(--spacing-lg) 0 var(--spacing-xl);
    padding: var(--spacing-md);
    border: 1px solid var(--border-color);
    border-left: 3px solid var(--brand-gold);
    border-radius: var(--radius-md);
    background: var(--bg-tint);
}

body.dark-mode .listen {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
    border-left-color: var(--brand-gold);
}

.listen-head {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    margin-bottom: var(--spacing-sm);
    font-size: 0.92rem;
}

.listen-icon { font-size: 1.1rem; }
.listen-title { font-weight: 600; }

.listen-time {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* Three states, in order of how the page can actually fail:

   no `js` class          scripting is off or blocked before paint, so the
                          browser's own controls stay visible
   `js`                   scripting is alive, hide the native controls before
                          first paint so they never flash
   `js player-fallback`   main.js never initialised within 4 seconds, or the
                          file failed to load, so put the native controls back  */

.listen-audio { width: 100%; display: block; }
.js .listen-audio { display: none; }
.js.player-fallback .listen-audio { display: block; }

.listen-controls {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    flex-wrap: nowrap;
}

.listen-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 1px;
    min-width: 40px;
    height: 40px;
    padding: 0 0.5rem;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-light);
    color: var(--text-dark);
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

body.dark-mode .listen-btn {
    background: var(--bg-dark);
    color: var(--text-light);
    border-color: var(--border-dark);
}

.listen-btn:hover {
    background: var(--brand-navy);
    border-color: var(--brand-navy);
    color: #fff;
}

body.dark-mode .listen-btn:hover {
    background: var(--primary-color);
    color: var(--bg-dark);
    border-color: var(--primary-color);
}

.listen-btn.play {
    min-width: 48px;
    height: 48px;
    background: var(--brand-navy);
    border-color: var(--brand-navy);
    color: #fff;
    font-size: 1rem;
}

.listen-btn.play:hover { background: var(--brand-red); border-color: var(--brand-red); }

body.dark-mode .listen-btn.play {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: var(--bg-dark);
}

.btn-num { font-size: 0.62rem; font-weight: 700; }

/* Seek bar. The filled portion is driven by --played from the script. */
.listen-seek {
    flex: 1 1 auto;
    min-width: 60px;
    height: 6px;
    appearance: none;
    -webkit-appearance: none;
    border-radius: 3px;
    background: linear-gradient(to right,
        var(--brand-red) 0%, var(--brand-red) var(--played),
        var(--border-color) var(--played), var(--border-color) 100%);
    cursor: pointer;
}

body.dark-mode .listen-seek {
    background: linear-gradient(to right,
        var(--primary-color) 0%, var(--primary-color) var(--played),
        var(--border-dark) var(--played), var(--border-dark) 100%);
}

.listen-seek::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--brand-navy);
    border: 2px solid #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    cursor: grab;
}

.listen-seek::-moz-range-thumb {
    width: 16px;
    height: 16px;
    border: 2px solid #fff;
    border-radius: 50%;
    background: var(--brand-navy);
    cursor: grab;
}

body.dark-mode .listen-seek::-webkit-slider-thumb { background: var(--primary-color); border-color: var(--bg-dark); }
body.dark-mode .listen-seek::-moz-range-thumb { background: var(--primary-color); border-color: var(--bg-dark); }

.listen-btn.rate { font-variant-numeric: tabular-nums; font-size: 0.82rem; }
.listen-btn.dl { font-size: 1.05rem; }

.listen.is-playing { border-left-color: var(--brand-red); }
body.dark-mode .listen.is-playing { border-left-color: var(--accent-color); }

.listen-error { margin: 0; color: var(--brand-red); font-size: 0.88rem; }

/* On narrow screens drop the least essential buttons rather than wrapping
   into a cramped second row. Speed and download stay reachable from the
   native player if anyone needs them. */
@media (max-width: 560px) {
    .listen-btn.dl { display: none; }
    .listen-btn { min-width: 36px; height: 36px; padding: 0 0.35rem; }
    .listen-btn.play { min-width: 44px; height: 44px; }
}

@media (max-width: 400px) {
    .listen-btn.mute { display: none; }
}

@media print { .listen { display: none !important; } }

/* ================================================================
   SEARCH
   ================================================================ */

.search-main { padding-bottom: var(--spacing-xl); }
.search-hint { color: var(--text-muted); margin-bottom: var(--spacing-md); }

.search-box {
    position: relative;
    display: flex;
    align-items: center;
    max-width: 620px;
    margin-bottom: var(--spacing-sm);
}

.search-box input {
    width: 100%;
    padding: 0.85rem 2.6rem 0.85rem 1rem;
    font-size: 1.05rem;
    font-family: inherit;
    border: 2px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-light);
    color: var(--text-dark);
}

body.dark-mode .search-box input {
    background: var(--bg-dark-soft);
    color: var(--text-light);
    border-color: var(--border-dark);
}

.search-box input:focus { outline: none; border-color: var(--brand-navy); }
body.dark-mode .search-box input:focus { border-color: var(--primary-color); }

.search-box input::-webkit-search-cancel-button { display: none; }

.search-box button {
    position: absolute;
    right: 0.5rem;
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: var(--text-muted);
    font-size: 1.3rem;
    line-height: 1;
    cursor: pointer;
}

.search-box button:hover { background: var(--bg-tint); color: var(--brand-red); }
body.dark-mode .search-box button:hover { background: var(--bg-dark); }

.search-count {
    color: var(--text-muted);
    font-size: 0.88rem;
    margin-bottom: var(--spacing-md);
}

.nav-search { display: inline-flex; align-items: center; gap: 0.3rem; }

@media (min-width: 769px) {
    .nav-search span { display: none; }
    .nav-search { font-size: 1.05rem; }
}

/* ================================================================
   RELATED ARTICLES
   ================================================================ */

.related {
    margin-top: var(--spacing-xl);
    padding-top: var(--spacing-md);
    border-top: 1px solid var(--border-color);
}

body.dark-mode .related { border-color: var(--border-dark); }

.related h2 {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--text-muted);
    margin-bottom: var(--spacing-sm);
}

.related-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: var(--spacing-sm);
}

.related-item {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: var(--spacing-sm);
    border: 1px solid var(--border-color);
    border-top: 3px solid var(--brand-green);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: inherit;
    transition: transform 0.2s ease, box-shadow 0.25s ease, border-color 0.2s ease;
}

body.dark-mode .related-item { border-color: var(--border-dark); border-top-color: var(--secondary-color); }

.related-item:hover {
    transform: translateY(-2px);
    border-top-color: var(--brand-red);
    box-shadow: 0 6px 16px rgba(15, 44, 77, 0.1);
}

.related-cat, .related-meta { font-size: 0.75rem; color: var(--text-muted); }
.related-title { font-weight: 600; line-height: 1.5; }

@media print { .related, .search-box { display: none !important; } }

/* ================================================================
   STICKY HEADER CLEARANCE
   ================================================================ */

#main,
#categories,
#latest,
.article-header,
.category-header,
[id^="related"] {
    scroll-margin-top: calc(var(--nav-h) + var(--spacing-sm));
}

/* The skip link moves focus rather than scrolling, so the browser may place
   the target flush against the top. This keeps it clear of the header. */
#main:focus,
#main:target {
    scroll-margin-top: calc(var(--nav-h) + var(--spacing-sm));
    outline: none;
}

/* Sticky panels inside the page must clear the header too, or they slide
   underneath it as you scroll. */
.compose-wrap > .panel[style*="sticky"],
.listen.is-sticky {
    top: calc(var(--nav-h) + var(--spacing-xs));
}

/* ================================================================
   VERIFIED DATE
   Signals to a reader that someone rechecked the government source,
   which is a different claim from "the file was edited".
   ================================================================ */

.verified-line {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    margin-top: var(--spacing-xs);
    font-size: 0.85rem;
    color: var(--text-muted);
}

.verified-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--brand-green);
    flex: 0 0 auto;
}

body.dark-mode .verified-dot { background: var(--secondary-color); }

/* ================================================================
   LEGAL, ABOUT AND CONTACT PAGES

   These had no layout rules at all, so they rendered full-bleed with
   default margins: text ran the entire window width, which on a desktop
   monitor is roughly 200 characters a line. Comfortable reading is
   nearer 65 to 75, and legal text is exactly the kind nobody rereads
   when they lose their place.
   ================================================================ */

.legal-content {
    max-width: 760px;
    margin: 0 auto;
    padding: var(--spacing-xl) var(--spacing-md) var(--spacing-xl);
    font-size: 1.03rem;
    line-height: 1.75;
}

.legal-content h1 {
    font-size: 2.1rem;
    line-height: 1.25;
    margin-bottom: var(--spacing-xs);
}

.legal-content .last-updated {
    color: var(--text-muted);
    font-size: 0.85rem;
    padding-bottom: var(--spacing-md);
    margin-bottom: var(--spacing-lg);
    border-bottom: 2px solid var(--border-color);
}

body.dark-mode .legal-content .last-updated { border-color: var(--border-dark); }

/* Generous space above a heading, tight below it, so each heading reads as
   belonging to the text that follows rather than floating between blocks. */
.legal-content h2 {
    font-size: 1.35rem;
    line-height: 1.35;
    margin: var(--spacing-xl) 0 var(--spacing-sm);
    padding-top: var(--spacing-xs);
    scroll-margin-top: calc(var(--nav-h) + var(--spacing-md));
}

.legal-content h3 {
    font-size: 1.08rem;
    margin: var(--spacing-lg) 0 var(--spacing-xs);
    color: var(--brand-navy);
}

body.dark-mode .legal-content h3 { color: var(--primary-color); }

.legal-content p { margin-bottom: var(--spacing-md); }

.legal-content ul,
.legal-content ol {
    margin: 0 0 var(--spacing-md) 1.35rem;
    padding: 0;
}

.legal-content li { margin-bottom: 0.5rem; }
.legal-content li::marker { color: var(--brand-gold); }

.legal-content a { text-decoration: underline; text-underline-offset: 2px; }

/* First paragraph after the date line carries the summary, so give it weight */
.legal-content .info-box p { font-size: 1.05rem; }

/* --- section anchors --- */

.legal-h2 { position: relative; }

.legal-h2 .anchor {
    position: absolute;
    left: -1.1rem;
    text-decoration: none;
    color: var(--brand-gold);
    opacity: 0;
    transition: opacity 0.2s ease;
    font-weight: 400;
}

.legal-h2:hover .anchor,
.legal-h2 .anchor:focus { opacity: 1; }

/* Never hide the anchor off-screen on narrow viewports */
@media (max-width: 860px) {
    .legal-h2 .anchor { display: none; }
}

/* --- table of contents --- */

.toc {
    margin: var(--spacing-lg) 0 var(--spacing-xl);
    padding: var(--spacing-md) var(--spacing-lg);
    background: var(--bg-tint);
    border-radius: var(--radius-md);
    border-left: 3px solid var(--brand-navy);
}

body.dark-mode .toc {
    background: var(--bg-dark-soft);
    border-left-color: var(--primary-color);
}

.toc h2 {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-muted);
    margin: 0 0 var(--spacing-sm);
    padding: 0;
}

.toc-list {
    list-style: none;
    margin: 0;
    padding: 0;
    columns: 2;
    column-gap: var(--spacing-lg);
}

@media (max-width: 620px) {
    .toc-list { columns: 1; }
    .toc { padding: var(--spacing-md); }
}

.toc-list li {
    margin-bottom: 0.4rem;
    break-inside: avoid;
}

.toc-list a {
    display: flex;
    gap: 0.5rem;
    align-items: baseline;
    text-decoration: none;
    font-size: 0.92rem;
    line-height: 1.45;
    color: var(--text-dark);
}

body.dark-mode .toc-list a { color: var(--text-light); }
.toc-list a:hover { color: var(--brand-red); text-decoration: underline; }
body.dark-mode .toc-list a:hover { color: var(--accent-color); }

.toc-num {
    flex: 0 0 auto;
    font-size: 0.72rem;
    font-variant-numeric: tabular-nums;
    color: var(--brand-gold);
    font-weight: 700;
    padding-top: 0.1rem;
}

/* Highlight the section the reader is currently in */
.toc-list a.current {
    color: var(--brand-red);
    font-weight: 600;
}

body.dark-mode .toc-list a.current { color: var(--accent-color); }

/* --- back to top --- */

.back-to-top {
    margin-top: var(--spacing-xl);
    padding-top: var(--spacing-md);
    border-top: 1px solid var(--border-color);
    text-align: center;
    font-size: 0.88rem;
}

body.dark-mode .back-to-top { border-color: var(--border-dark); }
.back-to-top a { color: var(--text-muted); text-decoration: none; }
.back-to-top a:hover { color: var(--brand-red); text-decoration: underline; }

/* --- 404 is centred and has no contents list --- */

.legal-content.text-center { max-width: 560px; }
.legal-content.text-center ul,
.legal-content.text-center ol { margin-left: 0; list-style-position: inside; }

@media (max-width: 768px) {
    .legal-content {
        padding: var(--spacing-lg) var(--spacing-md);
        font-size: 1rem;
    }
    .legal-content h1 { font-size: 1.7rem; }
    .legal-content h2 { font-size: 1.2rem; }
}

@media print {
    .toc, .back-to-top, .legal-h2 .anchor { display: none !important; }
    .legal-content { max-width: 100%; }
}

/* ================================================================
   ABOUT AND CONTACT SPECIFICS
   ================================================================ */

/* Author cards sit inside the reading column, so a single card should not
   stretch to full width and look like a banner. */
.legal-content .author-grid {
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    margin: var(--spacing-md) 0 var(--spacing-lg);
}

.legal-content .author-card {
    background: var(--bg-tint);
    border-color: transparent;
    border-left-width: 3px;
}

body.dark-mode .legal-content .author-card {
    background: var(--bg-dark-soft);
    border-color: transparent;
    border-left-color: var(--secondary-color);
}

/* The contact address is the whole point of the page, so it gets treated as
   an action rather than a line of body text. */
.contact-email {
    display: block;
    margin: var(--spacing-md) 0 var(--spacing-sm);
    padding: var(--spacing-md) var(--spacing-lg);
    background: linear-gradient(135deg,
        rgba(2, 82, 47, 0.08), rgba(15, 44, 77, 0.08) 60%, rgba(227, 8, 28, 0.06));
    border-radius: var(--radius-md);
    border-left: 3px solid var(--brand-gold);
    text-align: center;
}

body.dark-mode .contact-email {
    background: linear-gradient(135deg,
        rgba(2, 82, 47, 0.22), rgba(15, 44, 77, 0.22) 60%, rgba(227, 8, 28, 0.14));
}

.contact-email a {
    font-size: 1.25rem;
    font-weight: 700;
    text-decoration: none;
    color: var(--brand-navy);
    word-break: break-word;
}

body.dark-mode .contact-email a { color: var(--primary-color); }
.contact-email a:hover { color: var(--brand-red); text-decoration: underline; }
body.dark-mode .contact-email a:hover { color: var(--accent-color); }

@media (max-width: 480px) {
    .contact-email { padding: var(--spacing-md) var(--spacing-sm); }
    .contact-email a { font-size: 1.05rem; }
}

/* On the contact page each h3 introduces a reason to write, so give them a
   marker that reads as a list of options rather than document sections. */
.legal-content h3 {
    position: relative;
    padding-left: 0.9rem;
}

.legal-content h3::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.55em;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--brand-gold);
}

/* Boxes inside the reading column should breathe more than they do in an
   article, where they interrupt a narrative rather than a reference list. */
.legal-content .info-box,
.legal-content .tip-box,
.legal-content .warning-box {
    margin: var(--spacing-lg) 0;
    padding: var(--spacing-md) var(--spacing-lg);
}

/* Tables inside the reading column */
.legal-content .policy-table { font-size: 0.88rem; }

/* ================================================================
   LINK COLOURS

   Links had no colour rule anywhere, so they fell back to the browser
   default #0000EE. Against the dark background that is a contrast ratio
   of 1.9:1, where WCAG AA asks for 4.5:1 on body text. It was close to
   unreadable in dark mode and it affected every page, not just these.
   ================================================================ */

a {
    color: var(--brand-navy);
    text-decoration-color: rgba(15, 44, 77, 0.35);
}

a:hover { color: var(--brand-red); text-decoration-color: currentColor; }

body.dark-mode a {
    color: var(--primary-color);
    text-decoration-color: rgba(127, 176, 224, 0.4);
}

body.dark-mode a:hover { color: var(--accent-color); }

/* Elements that carry their own colour must not be overridden by the above. */
.logo, .btn, .nav-menu a, .footer a, .toc-list a,
.article-item, .related-item, .category-card, .article-card,
.skip-link, .listen-btn, .read-more, .read-more-btn {
    text-decoration-color: currentColor;
}

/* ================================================================
   BUTTON VARIANTS

   btn-ghost is for secondary actions that should be reachable but not
   compete with the primary one. The composer previously showed five
   equally-weighted buttons, which gives no indication of what to do
   first.
   ================================================================ */

.btn-ghost {
    background: transparent;
    color: var(--text-muted);
    border: 1px solid var(--border-color);
    padding: 0.5rem 0.9rem;
    font-size: 0.85rem;
    font-weight: 600;
}

.btn-ghost:hover {
    background: var(--bg-tint);
    color: var(--text-dark);
    border-color: var(--text-muted);
}

body.dark-mode .btn-ghost { border-color: var(--border-dark); }

body.dark-mode .btn-ghost:hover {
    background: var(--bg-dark-soft);
    color: var(--text-light);
}

.btn-ghost.btn-danger:hover {
    background: rgba(227, 8, 28, 0.08);
    color: var(--brand-red);
    border-color: var(--brand-red);
}

body.dark-mode .btn-ghost.btn-danger:hover {
    background: rgba(255, 90, 99, 0.14);
    color: var(--accent-color);
    border-color: var(--accent-color);
}

.btn-block {
    display: block;
    width: 100%;
    text-align: center;
}

/* ================================================================
   COMPOSER SEND STEPS
   ================================================================ */

.send-steps {
    display: grid;
    gap: var(--spacing-md);
    margin-bottom: var(--spacing-sm);
}

.send-step {
    display: grid;
    grid-template-columns: 28px 1fr;
    gap: var(--spacing-sm);
    align-items: start;
}

.send-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin-top: 0.35rem;
    border-radius: 50%;
    background: var(--brand-navy);
    color: #fff;
    font-size: 0.82rem;
    font-weight: 700;
}

body.dark-mode .send-num { background: var(--primary-color); color: var(--bg-dark); }

.send-note {
    margin: 0.4rem 0 0;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.send-note code {
    background: rgba(15, 44, 77, 0.08);
    padding: 0.05rem 0.28rem;
    border-radius: 3px;
}

body.dark-mode .send-note code { background: rgba(255, 255, 255, 0.1); }

.actions-minor {
    margin-top: var(--spacing-md);
    padding-top: var(--spacing-sm);
    border-top: 1px solid var(--border-color);
}

body.dark-mode .actions-minor { border-color: var(--border-dark); }

/* Search result term highlighting */
.article-item mark {
    background: rgba(249, 171, 13, 0.35);
    color: inherit;
    padding: 0 0.12em;
    border-radius: 2px;
    font-weight: 600;
}

body.dark-mode .article-item mark {
    background: rgba(249, 171, 13, 0.3);
    color: var(--text-light);
}

/* ================================================================
   PRONUNCIATION CHIPS
   ================================================================ */

.say {
    display: inline-flex;
    align-items: baseline;
    gap: 0.3rem;
    white-space: nowrap;
}

.say-text {
    font-weight: 700;
    color: var(--brand-navy);
    white-space: normal;
}

body.dark-mode .say-text { color: var(--primary-color); }

.say-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    flex: 0 0 auto;
    align-self: center;
    border: 1px solid var(--border-color);
    border-radius: 50%;
    background: var(--bg-light);
    color: var(--brand-navy);
    font-size: 0.6rem;
    line-height: 1;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease,
                border-color 0.15s ease, transform 0.12s ease;
}

body.dark-mode .say-btn {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
    color: var(--primary-color);
}

.say-btn:hover {
    background: var(--brand-navy);
    border-color: var(--brand-navy);
    color: #fff;
    transform: scale(1.08);
}

body.dark-mode .say-btn:hover {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: var(--bg-dark);
}

.say-btn.speaking {
    background: var(--brand-red);
    border-color: var(--brand-red);
    color: #fff;
    animation: sayPulse 1s ease-in-out infinite;
}

@keyframes sayPulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(227, 8, 28, 0.4); }
    50%      { box-shadow: 0 0 0 6px rgba(227, 8, 28, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .say-btn.speaking { animation: none; }
}

.say-hint {
    font-size: 0.85rem;
    color: var(--text-muted);
    background: var(--bg-tint);
    border-left: 3px solid var(--brand-gold);
    border-radius: var(--radius-sm);
    padding: var(--spacing-xs) var(--spacing-sm);
    margin-bottom: var(--spacing-lg);
}

body.dark-mode .say-hint { background: var(--bg-dark-soft); }

/* A list of vocabulary reads better with room to breathe */
.article-body li .say { margin-right: 0.15rem; }

@media print { .say-btn, .say-hint { display: none !important; } }

/* ================================================================
   HERO

   The old hero said "Your Guide. Your Community. Your Bridge." and
   nothing else. That is a slogan, not an answer: someone landing from a
   WhatsApp group has a specific word in mind, usually NIE or padrón, and
   the page gave them no sign it covered that. This one names the topics,
   states the language, and offers four direct entry points.
   ================================================================ */

.hero {
    position: relative;
    overflow: hidden;
    padding: var(--spacing-xl) var(--spacing-md);
    background:
        radial-gradient(1100px 420px at 12% -10%, rgba(2, 82, 47, 0.10), transparent 60%),
        radial-gradient(900px 420px at 88% 0%, rgba(227, 8, 28, 0.08), transparent 60%),
        var(--bg-light);
    border-bottom: 1px solid var(--border-color);
}

body.dark-mode .hero {
    background:
        radial-gradient(1100px 420px at 12% -10%, rgba(95, 169, 127, 0.16), transparent 60%),
        radial-gradient(900px 420px at 88% 0%, rgba(255, 90, 99, 0.12), transparent 60%),
        var(--bg-dark);
    border-color: var(--border-dark);
}

/* The three-colour bridge ribbon, carried over from the logo */
.hero::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 3px;
    background: linear-gradient(90deg,
        var(--brand-green) 0%, var(--brand-green) 33%,
        var(--brand-navy) 33%, var(--brand-navy) 66%,
        var(--brand-red) 66%, var(--brand-red) 100%);
}

.hero-inner {
    max-width: 1200px;
    margin: 0 auto;
    display: grid;
    /* The stats column used to be auto, sized purely by its own content
       with no ceiling: fine while every line inside it was short, but the
       moment the note text grew to a full sentence, that one line forced
       the whole column wide on a single line, which stole width from the
       first column (minmax(0, 1fr) can shrink to make room for a sibling
       that grows, which is exactly what minmax(0, ...) is for) and
       collapsed the headline down to one word per line. Capping this
       column's width directly, not just the box inside it, is what
       actually stops a future longer note from doing the same thing
       again, rather than only patching the one width that broke this
       time. */
    grid-template-columns: minmax(0, 1fr) minmax(280px, 400px);
    gap: var(--spacing-xl);
    align-items: center;
}

.hero-content { max-width: 640px; margin: 0; text-align: left; }

.hero-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 var(--spacing-sm);
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* Bangladesh green and red, then Spanish red and gold */
.hero-flag {
    width: 34px;
    height: 12px;
    border-radius: 2px;
    background: linear-gradient(90deg,
        var(--brand-green) 0 45%, var(--brand-red) 45% 72%, var(--brand-gold) 72% 100%);
}

.hero h1 {
    font-size: clamp(2rem, 4.4vw, 3.1rem);
    line-height: 1.14;
    letter-spacing: -0.02em;
    margin: 0 0 var(--spacing-sm);
    color: var(--brand-navy);
}

body.dark-mode .hero h1 { color: var(--text-light); }

.hero-bn {
    color: var(--brand-red);
    font-family: 'Noto Sans Bengali', 'Hind Siliguri', 'Nirmala UI', system-ui, sans-serif;
}

body.dark-mode .hero-bn { color: var(--accent-color); }

.hero-sub {
    font-size: 1.05rem;
    line-height: 1.65;
    color: var(--text-muted);
    margin: 0 0 var(--spacing-lg);
    max-width: 54ch;
}

/* Slightly more line-height than the English paragraph above: Bangla
   conjuncts and matras sit taller than Latin letterforms, so the same
   1.65 reads a touch cramped. Tighter top margin than the default
   spacing-lg so this reads as the second half of one intro, not an
   unrelated paragraph. */
.hero-sub-bn {
    line-height: 1.8;
    margin-top: calc(-1 * var(--spacing-md));
}

body.dark-mode .hero-sub { color: #A9BACB; }

.hero-buttons {
    display: flex;
    gap: var(--spacing-sm);
    flex-wrap: wrap;
    margin-bottom: var(--spacing-lg);
}

.hero-buttons .btn { padding: 0.7rem 1.4rem; font-size: 0.98rem; }

.hero-chips {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    flex-wrap: wrap;
}

.hero-chips-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    margin-right: 0.15rem;
}

.hero-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.34rem 0.75rem;
    font-size: 0.85rem;
    font-weight: 600;
    text-decoration: none;
    color: var(--text-dark);
    background: var(--bg-light);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    transition: background-color 0.18s ease, color 0.18s ease,
                border-color 0.18s ease, transform 0.15s ease;
}

body.dark-mode .hero-chip {
    background: var(--bg-dark-soft);
    color: var(--text-light);
    border-color: var(--border-dark);
}

.hero-chip:hover {
    background: var(--brand-navy);
    border-color: var(--brand-navy);
    color: #fff;
    transform: translateY(-1px);
}

body.dark-mode .hero-chip:hover {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: var(--bg-dark);
}

/* --- the at-a-glance panel --- */

.hero-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(64px, auto));
    gap: var(--spacing-md);
    padding: var(--spacing-lg);
    max-width: 400px;
    background: var(--bg-light);
    border: 1px solid var(--border-color);
    border-top: 3px solid var(--brand-gold);
    border-radius: var(--radius-md);
    box-shadow: 0 10px 30px rgba(15, 44, 77, 0.07);
}

body.dark-mode .hero-stats {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
    border-top-color: var(--brand-gold);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
}

.hero-stat { text-align: center; }

.hero-stat-n {
    display: block;
    font-size: 1.85rem;
    font-weight: 800;
    line-height: 1;
    color: var(--brand-navy);
    font-variant-numeric: tabular-nums;
}

body.dark-mode .hero-stat-n { color: var(--primary-color); }

.hero-stat-l {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--text-muted);
}

.hero-stat-note {
    grid-column: 1 / -1;
    margin: 0;
    padding-top: var(--spacing-sm);
    border-top: 1px solid var(--border-color);
    text-align: center;
    font-size: 0.78rem;
    color: var(--text-muted);
}

body.dark-mode .hero-stat-note { border-color: var(--border-dark); }

/* --- responsive --- */

@media (max-width: 900px) {
    .hero-inner { grid-template-columns: 1fr; gap: var(--spacing-lg); }
    .hero-stats {
        grid-template-columns: repeat(3, 1fr);
        padding: var(--spacing-md);
    }
    .hero-stat-n { font-size: 1.5rem; }
}

@media (max-width: 560px) {
    .hero { padding: var(--spacing-lg) var(--spacing-md); }
    .hero-sub { font-size: 0.98rem; }
    /* Full-width buttons: a thumb should not have to aim on a phone. */
    .hero-buttons { flex-direction: column; align-items: stretch; }
    .hero-buttons .btn { width: 100%; }
    .hero-chips-label { width: 100%; margin-bottom: 0.15rem; }
}

/* ================================================================
   SCROLL TO TOP
   ================================================================ */

.to-top {
    position: fixed;
    right: var(--spacing-md);
    bottom: var(--spacing-md);
    z-index: 850;              /* under the notice banner, over the content */
    width: 46px;
    height: 46px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border-color);
    border-radius: 50%;
    background: var(--bg-light);
    color: var(--brand-navy);
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 4px 16px rgba(15, 44, 77, 0.18);

    /* Hidden by default and kept out of hit testing, so it cannot swallow a
       tap meant for whatever sits underneath it. */
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px);
    pointer-events: none;
    transition: opacity 0.22s ease, transform 0.22s ease, visibility 0.22s;
}

body.dark-mode .to-top {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
    color: var(--primary-color);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
}

.to-top.visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    pointer-events: auto;
}

.to-top:hover {
    background: var(--brand-navy);
    border-color: var(--brand-navy);
    color: #fff;
    transform: translateY(-2px);
}

body.dark-mode .to-top:hover {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: var(--bg-dark);
}

.to-top:active { transform: translateY(0); }

/* The notice banner sits along the bottom on the first visit, so lift the
   button clear of it while that is on screen. */
body:has(#cookieBanner[style*="block"]) .to-top { bottom: calc(var(--spacing-md) + 120px); }

@media (max-width: 560px) {
    .to-top {
        width: 42px;
        height: 42px;
        right: var(--spacing-sm);
        bottom: var(--spacing-sm);
    }
}

@media (prefers-reduced-motion: reduce) {
    .to-top { transition: opacity 0.01ms, visibility 0.01ms; transform: none; }
    .to-top.visible { transform: none; }
    .to-top:hover { transform: none; }
}

@media print { .to-top { display: none !important; } }

/* ================================================================
   READ ALONG

   The highlight has to be visible without being loud: it moves every
   few seconds for ten minutes, so anything strong becomes exhausting.
   A soft background and a left edge, nothing that shifts layout.
   ================================================================ */

.article-body .s {
    border-radius: 3px;
    transition: background-color 0.25s ease, box-shadow 0.25s ease;
}

/* Only offer the pointer once a player is present on the page. */
[data-sentences] .s { cursor: pointer; }

[data-sentences] .s:hover {
    background: rgba(249, 171, 13, 0.14);
}

.article-body .s-now {
    background: rgba(249, 171, 13, 0.28);
    box-shadow: -0.35em 0 0 rgba(249, 171, 13, 0.28),
                 0.35em 0 0 rgba(249, 171, 13, 0.28);
}

body.dark-mode .article-body .s-now {
    background: rgba(249, 171, 13, 0.26);
    box-shadow: -0.35em 0 0 rgba(249, 171, 13, 0.26),
                 0.35em 0 0 rgba(249, 171, 13, 0.26);
}

/* Paused keeps the place visible but stops it competing for attention. */
.article-body .s-paused {
    background: rgba(249, 171, 13, 0.14);
    box-shadow: -0.35em 0 0 rgba(249, 171, 13, 0.14),
                 0.35em 0 0 rgba(249, 171, 13, 0.14);
}

.listen-btn.follow { font-size: 0.9rem; opacity: 0.45; }
.listen-btn.follow.is-on { opacity: 1; }

.listen-btn.follow.is-on {
    background: var(--brand-navy);
    border-color: var(--brand-navy);
    color: #fff;
}

body.dark-mode .listen-btn.follow.is-on {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: var(--bg-dark);
}

.icon-wait { letter-spacing: 0.1em; }

.listen-hint {
    margin: var(--spacing-xs) 0 0;
    font-size: 0.78rem;
    color: var(--text-muted);
}

@media (prefers-reduced-motion: reduce) {
    .article-body .s { transition: none; }
}

@media print {
    .article-body .s-now,
    .article-body .s-paused { background: none; box-shadow: none; }
}

/* ================================================================
   FIGURES

   Diagrams are inlined as SVG rather than linked as images, so they
   inherit the page's colour variables and follow dark mode instead of
   sitting on a white rectangle in a dark article.
   ================================================================ */

.fig {
    margin: var(--spacing-lg) 0;
    padding: var(--spacing-md);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-light);
    overflow-x: auto;
}

body.dark-mode .fig {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
}

.fig svg {
    display: block;
    width: 100%;
    height: auto;
    /* Below this the labels stop being readable, so allow a sideways
       scroll rather than shrinking the drawing into illegibility. */
    min-width: 520px;
}

.fig figcaption {
    margin-top: var(--spacing-sm);
    padding-top: var(--spacing-xs);
    border-top: 1px solid var(--border-color);
    font-size: 0.85rem;
    color: var(--text-muted);
    min-width: 0;
}

/* Inlined the same way and for the same reason as .fig above (inherits
   page colour variables, follows dark mode), but framed a step lighter
   since this sits inside a question a reader is actively answering,
   not standing alone as its own figure. */
.quiz-scenario-img {
    margin: var(--spacing-sm) 0 var(--spacing-md);
    padding: var(--spacing-sm);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-light);
    overflow-x: auto;
}

body.dark-mode .quiz-scenario-img {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
}

.quiz-scenario-img svg {
    display: block;
    width: 100%;
    height: auto;
    min-width: 320px;
    max-width: 420px;
    margin: 0 auto;
}

body.dark-mode .fig figcaption { border-color: var(--border-dark); }

@media (max-width: 600px) {
    .fig { padding: var(--spacing-sm); }
    .fig figcaption { font-size: 0.8rem; }
}

@media print {
    .fig { break-inside: avoid; border-color: #999; }
}

/* ================================================================
   EXAMS / QUIZZES

   The base HTML already contains every question, option and explanation:
   nothing here is generated by JavaScript, only progressively revealed by
   it. The .js class is added to <html> before first paint (see head() in
   build.mjs); everything gated on ".js ..." below is therefore invisible
   to a crawler, a JS-disabled browser, or the brief instant before main.js
   runs, and all of those instead see a complete, correct study sheet with
   every answer and explanation already on the page.
   ================================================================ */

.quiz-header {
    background: linear-gradient(135deg, rgba(37,99,235,0.08), rgba(124,58,237,0.08));
    padding: var(--spacing-xl) 0;
    margin-bottom: var(--spacing-lg);
}
.quiz-header .container, .quiz-header { padding-left: var(--spacing-md); padding-right: var(--spacing-md); }
.quiz-header h1 { font-size: 2rem; margin: 0 0 var(--spacing-sm); color: var(--brand-navy); }
body.dark-mode .quiz-header h1 { color: var(--text-light); }
.quiz-intro { color: #4b5563; font-size: 1.05rem; margin: 0 0 var(--spacing-md); max-width: 62ch; }
body.dark-mode .quiz-intro { color: #9ca3af; }

.quiz-meta {
    display: flex;
    gap: var(--spacing-md);
    flex-wrap: wrap;
    font-size: 0.9rem;
    color: var(--text-muted);
}
.quiz-meta a { color: var(--brand-navy); font-weight: 600; text-decoration: none; }
.quiz-meta a:hover { text-decoration: underline; }
body.dark-mode .quiz-meta a { color: var(--primary-color); }

.quiz-page { max-width: 760px; margin: 0 auto; padding: 0 var(--spacing-md) var(--spacing-xl); }

.quiz-scorebar {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    gap: 6px;
    align-items: baseline;
    background: var(--bg-light);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: var(--spacing-sm) var(--spacing-md);
    margin-bottom: var(--spacing-lg);
    font-weight: 700;
    font-size: 1.05rem;
}
body.dark-mode .quiz-scorebar { background: var(--bg-dark-soft); border-color: var(--border-dark); }
.quiz-score-label { font-weight: 500; color: var(--text-muted); margin-right: 2px; }
.quiz-score-n { color: var(--brand-green); font-size: 1.2rem; }
body.dark-mode .quiz-score-n { color: var(--secondary-color); }

.quiz-q {
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: var(--spacing-md) var(--spacing-lg);
    margin-bottom: var(--spacing-md);
}
body.dark-mode .quiz-q { border-color: var(--border-dark); }
.quiz-q fieldset { border: none; margin: 0; padding: 0; }
.quiz-q legend { padding: 0; font-weight: 700; font-size: 1.05rem; margin-bottom: var(--spacing-md); float: left; width: 100%; }

.quiz-options { display: grid; gap: var(--spacing-sm); clear: both; }

.quiz-opt {
    text-align: left;
    padding: var(--spacing-sm) var(--spacing-md);
    border: 2px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-light);
    color: inherit;
    font: inherit;
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease, transform 0.1s ease;
}
body.dark-mode .quiz-opt { background: var(--bg-dark-soft); border-color: var(--border-dark); }
.quiz-opt:hover { border-color: var(--brand-navy); }
body.dark-mode .quiz-opt:hover { border-color: var(--primary-color); }
.quiz-opt:active { transform: translateY(1px); }

/* Feedback colours only make sense once JS has actually judged an answer;
   without JS every option just stays a plain, clickable-looking button,
   which is also the only sensible fallback state. */
.js .quiz-opt.correct {
    border-color: var(--brand-green);
    background: rgba(2, 82, 47, 0.09);
    font-weight: 700;
}
.js .quiz-opt.incorrect {
    border-color: var(--brand-red);
    background: rgba(227, 8, 28, 0.08);
}
body.dark-mode .quiz-opt.correct { background: rgba(95, 169, 127, 0.18); border-color: var(--secondary-color); }
body.dark-mode .quiz-opt.incorrect { background: rgba(255, 90, 99, 0.15); border-color: var(--accent-color); }

/* Marks which option a reader picked, without saying whether it was right:
   correct/incorrect only get added at reveal() time, when Submit is
   clicked, not here. A neutral navy highlight, not the exam-result colours,
   since this state exists specifically before those are known. */
.js .quiz-opt.selected {
    border-color: var(--brand-navy);
    background: rgba(15, 44, 77, 0.07);
    font-weight: 600;
}
body.dark-mode .js .quiz-opt.selected {
    border-color: var(--primary-color);
    background: rgba(127, 176, 224, 0.14);
}

/* Scoped to .quiz.revealed specifically, not just .quiz-q.answered: an
   answered-but-not-yet-submitted question still needs its other options
   to look and behave genuinely clickable, since a reader can change their
   pick right up until Submit (see answer() in main.js). These dimmed,
   non-interactive styles are for the final, scored state after reveal(),
   not the in-progress one. */
.js .quiz.revealed .quiz-q.answered .quiz-opt:not(.correct):not(.incorrect):not(.selected) { opacity: 0.55; }
.js .quiz.revealed .quiz-q.answered .quiz-opt { cursor: default; }

.quiz-explain {
    margin-top: var(--spacing-md);
    padding-top: var(--spacing-sm);
    border-top: 1px solid var(--border-color);
    color: var(--text-muted);
    font-size: 0.95rem;
}
body.dark-mode .quiz-explain { border-color: var(--border-dark); }
.js .quiz-explain { display: none; }
/* Gated on the whole quiz having been submitted, not on the individual
   question having been answered: every explanation appears together at
   Submit, matching how correct/incorrect are revealed together too,
   rather than leaking the answer to a question the moment it is picked. */
.js .quiz.revealed .quiz-explain { display: block; }

.quiz-results {
    border: 2px solid var(--brand-navy);
    border-radius: var(--radius-md);
    padding: var(--spacing-lg);
    text-align: center;
    margin-top: var(--spacing-lg);
}
body.dark-mode .quiz-results { border-color: var(--primary-color); }
.quiz-results h2 { margin: 0 0 var(--spacing-sm); }
.quiz-final-score { font-size: 2rem; font-weight: 800; color: var(--brand-navy); margin: 0 0 var(--spacing-sm); }
body.dark-mode .quiz-final-score { color: var(--primary-color); }
.quiz-final-msg { color: var(--text-muted); margin: 0 0 var(--spacing-md); }
.quiz-results-actions { display: flex; gap: var(--spacing-sm); flex-wrap: wrap; justify-content: center; }

/* Without JS, "results so far" has no meaning (nothing has been marked),
   and "retake" resets state that JS is the only thing tracking. Both stay
   hidden until scripting is confirmed active. */
.js .quiz-results { display: none; }
.js .quiz-results.visible { display: block; }
.quiz-retake { display: none; }
.js .quiz-retake { display: inline-block; }

.quiz-nav { display: flex; gap: var(--spacing-sm); flex-wrap: wrap; margin-top: var(--spacing-xl); }

/* Hub page cards: the existing .article-item styling, with a gold accent
   instead of the article list's green, so exams read as their own family
   at a glance rather than an unlabelled subset of articles. */
.quiz-item { border-left: 3px solid var(--brand-gold); }
.quiz-item:hover { border-left-color: var(--brand-red); }

/* A prominent, self-contained call to action, dropped into an article page
   automatically when that article has a matching quiz -- see relatedBlock's
   neighbour in build.mjs. Distinct from .related and .tip-box so it reads
   as an invitation to do something, not another paragraph to read. */
.quiz-cta {
    border: 2px dashed var(--brand-gold);
    border-radius: var(--radius-md);
    padding: var(--spacing-lg);
    margin: var(--spacing-xl) 0;
    text-align: center;
}
.quiz-cta h2 { margin: 0 0 var(--spacing-xs); font-size: 1.2rem; }
.quiz-cta p { margin: 0 0 var(--spacing-md); color: var(--text-muted); }

@media (max-width: 600px) {
    .quiz-header h1 { font-size: 1.5rem; }
    .quiz-q { padding: var(--spacing-sm) var(--spacing-md); }
    .quiz-scorebar { font-size: 0.95rem; }
    .quiz-results-actions { flex-direction: column; }
    .quiz-results-actions .btn { width: 100%; }
}

/* Submit-gated results: answering a question still gives immediate
   correct/incorrect feedback (the whole point of that design), but the
   score summary and the results panel now only appear after an explicit
   click, both so a reader can review their answers before committing, and
   so the view-count endpoint has one unambiguous moment (this click, never
   an automatic trigger) that means "this person actually finished and
   wanted to see how they did" -- the count is supposed to answer, not
   "how many people started this quiz." */
.quiz-submit-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-md);
    flex-wrap: wrap;
    margin: var(--spacing-lg) 0;
    padding: var(--spacing-md);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
}
body.dark-mode .quiz-submit-row { border-color: var(--border-dark); }
.quiz-progress { margin: 0; color: var(--text-muted); font-weight: 600; }
.quiz-submit:disabled { opacity: 0.5; cursor: not-allowed; }

/* Without scripting the submit button can never do anything useful (there is
   no JS to compute a score from), but every question's explanation and the
   results panel's default text are already visible regardless -- see the
   .js-gated rules above -- so a disabled button here does not hide content,
   it just correctly says "this specific interaction is not available." */

.quiz-count { color: var(--text-muted); }
.quiz-count:empty { display: none; }

.quiz-results { position: relative; overflow: hidden; }
.quiz-results-h2 { margin: 0 0 var(--spacing-sm); }

/* Confetti: a fixed set of coloured rectangles, positioned and animated
   entirely with CSS custom properties set per-piece by JS (left offset,
   fall duration, rotation, colour), so the animation itself needs no
   per-frame JS at all, only the initial spawn. Removed from the DOM when
   the animation ends rather than left to accumulate across retakes. */
.quiz-celebrate { position: absolute; inset: 0; pointer-events: none; overflow: hidden; z-index: 1; }
.confetti-piece {
    position: absolute;
    top: -20px;
    left: var(--x, 50%);
    width: 8px;
    height: 14px;
    background: var(--c, var(--brand-gold));
    opacity: 0.9;
    animation: confetti-fall var(--dur, 2.2s) ease-in var(--delay, 0s) forwards;
}
@keyframes confetti-fall {
    /* --fall defaults to the small in-panel distance; the fullscreen
       overlay below overrides it to clear the whole viewport instead of
       stopping a third of the way down. */
    to { transform: translateY(var(--fall, 340px)) rotate(var(--rot, 360deg)); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .confetti-piece { animation: none; display: none; }
}

.quiz-results.perfect { border-color: var(--brand-gold); border-width: 3px; }
.quiz-results.perfect .quiz-final-score { color: var(--brand-gold); }
body.dark-mode .quiz-results.perfect .quiz-final-score { color: var(--brand-gold); }

@media (max-width: 600px) {
    .quiz-submit-row { flex-direction: column; align-items: stretch; text-align: center; }
    .quiz-submit-row .btn { width: 100%; }
}

/* ================================================================
   FULLSCREEN CELEBRATION

   A separate, bigger moment from the in-panel confetti above (kept as it
   was, untouched): this covers the entire viewport with position:fixed +
   inset:0, which means "the whole screen" on a phone and "the whole
   window" on desktop without needing any device-specific logic at all --
   the same rule produces the right result on both. Hidden by default and
   shown only by JS adding .visible, so a JS-disabled or reduced-motion
   visitor never sees an overlay they have no way to dismiss with an
   animation they didn't ask for.
   ================================================================ */

.quiz-fs-celebrate {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 10000;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    background: radial-gradient(circle at 50% 40%, rgba(90,60,10,0.97), rgba(15,44,77,0.99) 70%);
    opacity: 0;
    transition: opacity 0.3s ease;
}
.quiz-fs-celebrate.visible { display: flex; opacity: 1; }
.quiz-fs-celebrate.closing { opacity: 0; }

.quiz-fs-confetti { position: absolute; inset: 0; pointer-events: none; }
.quiz-fs-confetti .confetti-piece {
    width: 12px;
    height: 20px;
    top: -30px;
    --fall: 120vh;
}

.quiz-fs-message {
    position: relative;
    z-index: 1;
    text-align: center;
    color: #fff;
    padding: var(--spacing-lg);
    transform: scale(0.7);
    opacity: 0;
    animation: quizFsPop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) 0.1s forwards;
}
.quiz-fs-emoji { font-size: 4rem; display: block; margin-bottom: var(--spacing-sm); }
.quiz-fs-message h2 {
    font-size: 3rem;
    margin: 0 0 var(--spacing-sm);
    color: var(--brand-gold);
    text-shadow: 0 2px 12px rgba(0,0,0,0.4);
}
.quiz-fs-message p { font-size: 1.2rem; margin: 0; color: #fff; }

@keyframes quizFsPop {
    to { transform: scale(1); opacity: 1; }
}

.quiz-fs-close {
    position: absolute;
    top: var(--spacing-md);
    right: var(--spacing-md);
    z-index: 2;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: 2px solid rgba(255,255,255,0.6);
    background: rgba(255,255,255,0.1);
    color: #fff;
    font-size: 1.2rem;
    cursor: pointer;
    line-height: 1;
}
.quiz-fs-close:hover { background: rgba(255,255,255,0.25); }

@media (prefers-reduced-motion: reduce) {
    .quiz-fs-message { animation: none; transform: none; opacity: 1; }
    .quiz-fs-confetti { display: none; }
    .quiz-fs-celebrate { transition: none; }
}

@media (max-width: 480px) {
    .quiz-fs-emoji { font-size: 3rem; }
    .quiz-fs-message h2 { font-size: 2rem; }
    .quiz-fs-message p { font-size: 1rem; }
}

/* ================================================================
   QUIZ SERIES: exams hub compact block + article-page pill CTA

   A category with a long numbered series mixed in with standalone quizzes
   used to render every quiz as an identical full-width card, which gets
   repetitive fast once one series alone reaches a dozen entries. These
   rules give a series (grouped by build.mjs, above a size threshold) one
   compact block instead: a single description plus small numbered links,
   so twelve quizzes cost a few lines of layout, not twelve full cards.
   ================================================================ */

.exams-summary {
    font-size: 0.95rem;
    color: var(--text-muted);
    margin-top: var(--spacing-sm);
}

.quiz-series-block {
    padding: var(--spacing-lg);
    margin-bottom: var(--spacing-lg);
    background: var(--bg-light);
    border: 1px solid var(--border-color);
    border-left: 3px solid var(--brand-green);
    border-radius: var(--radius-md);
}
body.dark-mode .quiz-series-block {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
    border-left-color: var(--brand-green);
}
.quiz-series-block h3 { margin: 0 0 var(--spacing-xs); }
.quiz-series-desc { color: var(--text-muted); margin: 0 0 var(--spacing-xs); }
.quiz-series-stats { font-size: 0.85rem; color: var(--text-muted); margin: 0 0 var(--spacing-md); }

.quiz-series-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.quiz-series-item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.4rem;
    height: 2.4rem;
    padding: 0 0.5rem;
    font-weight: 700;
    font-size: 0.95rem;
    text-decoration: none;
    color: var(--text-dark);
    background: var(--bg-tint);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.quiz-series-item:hover {
    background: var(--brand-green);
    color: #fff;
    border-color: var(--brand-green);
    transform: translateY(-1px);
}
body.dark-mode .quiz-series-item {
    color: var(--text-light);
    background: rgba(255,255,255,0.05);
    border-color: var(--border-dark);
}

/* The article-side CTA equivalent: same pill shape, smaller block, used
   when a series is what quizCta() finds instead of one standalone quiz. */
.quiz-cta-series .quiz-cta-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: var(--spacing-sm);
}
.quiz-cta-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.2rem;
    height: 2.2rem;
    padding: 0 0.45rem;
    font-weight: 700;
    font-size: 0.9rem;
    text-decoration: none;
    color: var(--text-dark);
    background: var(--bg-tint);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.quiz-cta-pill:hover { background: var(--brand-gold); color: var(--text-dark); border-color: var(--brand-gold); transform: translateY(-1px); }
body.dark-mode .quiz-cta-pill {
    color: var(--text-light);
    background: rgba(255,255,255,0.05);
    border-color: var(--border-dark);
}

@media (max-width: 600px) {
    .quiz-series-item, .quiz-cta-pill { min-width: 2.1rem; height: 2.1rem; font-size: 0.85rem; }
}

/* ================================================================
   HERO STAT: LIVE VISIT COUNTER

   A small animated SVG sits behind just the visits number, distinguishing
   the one live, updating stat from the two static ones (guides, topics)
   beside it: radiating pings from a centre point out to four corner
   nodes, suggesting the count reaching out and connecting to sources
   rather than just being a static figure. Kept behind the number at low
   opacity throughout, so the number stays the actual focal point.
   ================================================================ */

.hero-stat-live {
    position: relative;
    z-index: 0;
}

.hero-stat-bg {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 100%;
    max-width: 130px;
    z-index: -1;
    overflow: visible;
    pointer-events: none;
}

.hero-stat-bg .hsb-line {
    stroke: var(--brand-gold);
    stroke-width: 0.6;
    opacity: 0.22;
    animation: hsbLineFlow 3.2s ease-in-out infinite;
}
.hero-stat-bg .hsb-line-2 { animation-delay: 0.5s; }
.hero-stat-bg .hsb-line-3 { animation-delay: 1s; }
.hero-stat-bg .hsb-line-4 { animation-delay: 1.5s; }

.hero-stat-bg .hsb-node {
    fill: var(--brand-gold);
    opacity: 0.35;
    animation: hsbNodePulse 3.2s ease-in-out infinite;
}
.hero-stat-bg .hsb-node-2 { animation-delay: 0.5s; }
.hero-stat-bg .hsb-node-3 { animation-delay: 1s; }
.hero-stat-bg .hsb-node-4 { animation-delay: 1.5s; }

.hero-stat-bg .hsb-ping {
    fill: none;
    stroke: var(--brand-navy);
    stroke-width: 1.2;
    opacity: 0;
    transform-origin: 60px 35px;
    animation: hsbPing 2.4s ease-out infinite;
}
body.dark-mode .hero-stat-bg .hsb-ping { stroke: var(--primary-color); }
.hero-stat-bg .hsb-ping-2 { animation-delay: 0.8s; }
.hero-stat-bg .hsb-ping-3 { animation-delay: 1.6s; }

@keyframes hsbPing {
    0%   { transform: scale(0.3); opacity: 0.5; }
    100% { transform: scale(9); opacity: 0; }
}
@keyframes hsbLineFlow {
    0%, 100% { opacity: 0.12; }
    50%      { opacity: 0.32; }
}
@keyframes hsbNodePulse {
    0%, 100% { opacity: 0.25; transform: scale(1); }
    50%      { opacity: 0.6; transform: scale(1.3); }
}

@media (prefers-reduced-motion: reduce) {
    .hero-stat-bg .hsb-ping,
    .hero-stat-bg .hsb-line,
    .hero-stat-bg .hsb-node {
        animation: none;
        opacity: 0.2;
    }
}

/* ================================================================
   QUIZ COMPLETION: per-browser "already done" indicators

   Two pieces. The prior-completion banner (quiz-prior-banner) appears at
   the top of a quiz page this browser has already finished before, with
   the previous score. The .quiz-link-done class (added by
   QuizCompletionBadges in main.js) marks a completed quiz wherever a link
   to it appears elsewhere: a small checkmark badge, styled differently
   for the small square pills (series blocks, article CTAs) than for the
   larger rectangular cards (exams hub standalone list), since a badge
   sized for one looks wrong on the other.
   ================================================================ */

.quiz-prior-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-sm);
    padding: 0.65rem var(--spacing-md);
    margin-bottom: var(--spacing-md);
    background: var(--bg-tint);
    border: 1px solid var(--border-color);
    border-left: 3px solid var(--brand-green);
    border-radius: var(--radius-sm);
    font-size: 0.9rem;
    color: var(--text-dark);
}
body.dark-mode .quiz-prior-banner {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
    border-left-color: var(--brand-green);
    color: var(--text-light);
}
.quiz-prior-banner-close {
    flex-shrink: 0;
    width: 1.6rem;
    height: 1.6rem;
    padding: 0;
    background: transparent;
    border: none;
    color: inherit;
    opacity: 0.6;
    cursor: pointer;
    font-size: 0.9rem;
    line-height: 1;
    border-radius: var(--radius-sm);
}
.quiz-prior-banner-close:hover { opacity: 1; background: rgba(0,0,0,0.06); }
body.dark-mode .quiz-prior-banner-close:hover { background: rgba(255,255,255,0.08); }

/* Small pills: series blocks on the exams hub, and the article-side quiz
   CTA when it renders as a series. A tiny green checkmark badge in the
   top-right corner, overlapping the pill slightly rather than squeezing
   the number to make room, since these pills are already small. */
.quiz-series-item.quiz-link-done,
.quiz-cta-pill.quiz-link-done {
    position: relative;
}
.quiz-series-item.quiz-link-done::after,
.quiz-cta-pill.quiz-link-done::after {
    content: '✓';
    position: absolute;
    top: -6px;
    right: -6px;
    width: 1.05rem;
    height: 1.05rem;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.65rem;
    font-weight: 800;
    color: #fff;
    background: var(--brand-green);
    border: 2px solid var(--bg-light);
    border-radius: 50%;
    line-height: 1;
}
body.dark-mode .quiz-series-item.quiz-link-done::after,
body.dark-mode .quiz-cta-pill.quiz-link-done::after {
    border-color: var(--bg-dark);
}

/* Standalone cards on the exams hub: a small labelled badge in the
   top-right corner of the card, since there is room for the word itself
   here rather than just a checkmark. */
.article-item.quiz-item.quiz-link-done {
    position: relative;
}
.article-item.quiz-item.quiz-link-done::after {
    content: '✓ সম্পন্ন';
    position: absolute;
    top: var(--spacing-md);
    right: var(--spacing-md);
    padding: 0.2rem 0.55rem;
    font-size: 0.72rem;
    font-weight: 700;
    color: #fff;
    background: var(--brand-green);
    border-radius: 999px;
    line-height: 1.4;
}

/* ================================================================
   EXAMS HUB: quick-access TOC, subsection headings, quiz numbering

   The TOC exists specifically because the page grew past the point of
   being reasonably scannable by scrolling: several categories, one of
   them a 12-part series, others now split into named subsections. One
   block at the top, one line per category, each linking straight to
   that category's heading further down.

   Subsection headings (Permiso B, A1) sit one level below the category
   heading and above individual quiz cards, which is why quiz card
   titles inside a subsection are h4 rather than h3 elsewhere on this
   page (see .article-item h4 above): the heading levels need to nest
   correctly, category > subsection > card, not repeat a level.
   ================================================================ */

.exams-toc {
    padding: var(--spacing-lg);
    margin-bottom: var(--spacing-xl);
    background: var(--bg-light);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
}
body.dark-mode .exams-toc {
    background: var(--bg-dark-soft);
    border-color: var(--border-dark);
}
.exams-toc h2 { margin: 0 0 var(--spacing-md); font-size: 1.1rem; }
.exams-toc ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--spacing-sm); }
.exams-toc li {
    padding: var(--spacing-sm) var(--spacing-md);
    background: var(--bg-tint);
    border-radius: var(--radius-sm);
}
body.dark-mode .exams-toc li { background: rgba(255,255,255,0.04); }
.exams-toc a { font-weight: 700; text-decoration: none; }
.exams-toc a:hover { text-decoration: underline; }
.exams-toc-desc {
    display: block;
    margin-top: 0.15rem;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.quiz-subsection-heading { margin-top: var(--spacing-lg); font-size: 1.15rem; }
.quiz-subsection-stats { font-size: 0.85rem; color: var(--text-muted); margin: 0 0 var(--spacing-md); }

.quiz-number {
    display: inline-block;
    color: var(--brand-green);
    font-weight: 800;
}
body.dark-mode .quiz-number { color: var(--brand-gold); }

/* ================================================================
   LEARNING PATH (category pages where every article has pathOrder)

   A vertical timeline rather than the flat list every other category
   uses: read in sequence, not browsed. Three states per step, filled in
   client-side by LearningPath in main.js from localStorage (the same
   per-browser pattern already used for quiz completion): done (a step
   this browser has visited before), next (the first not-yet-visited
   step, the one the reader should actually click), and the plain
   default for everything further down the path. Every step stays a
   real, clickable link regardless of state -- nothing is locked, since
   this is a reference site a reader can jump around in, not a course
   platform that gates progress.
   ================================================================ */

.learning-path-intro {
    max-width: 65ch;
    margin: 0 0 var(--spacing-xl);
    padding: var(--spacing-md) var(--spacing-lg);
    background: var(--bg-tint);
    border-left: 3px solid var(--brand-gold);
    border-radius: var(--radius-sm);
    line-height: 1.7;
}
body.dark-mode .learning-path-intro { background: rgba(255,255,255,0.04); }

.learning-path-steps {
    list-style: none;
    margin: 0;
    padding: 0;
    position: relative;
}

/* The connecting line: one continuous element behind every step rather
   than a border on each list item, so it reads as a single path rather
   than a stack of separately-bordered boxes. */
.learning-path-steps::before {
    content: '';
    position: absolute;
    top: 28px;
    bottom: 28px;
    left: 27px;
    width: 2px;
    background: var(--border-color);
}
body.dark-mode .learning-path-steps::before { background: var(--border-dark); }

.path-step { position: relative; margin-bottom: var(--spacing-md); }

.path-step a {
    display: flex;
    align-items: flex-start;
    gap: var(--spacing-md);
    padding: var(--spacing-md);
    background: var(--bg-light);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: inherit;
    transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;
}
body.dark-mode .path-step a { background: var(--bg-dark-soft); border-color: var(--border-dark); }
.path-step a:hover { box-shadow: 0 8px 20px rgba(15, 44, 77, 0.1); transform: translateY(-2px); }
body.dark-mode .path-step a:hover { box-shadow: 0 8px 20px rgba(0,0,0,0.3); }

.path-step-number {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--bg-tint);
    border: 2px solid var(--border-color);
    font-weight: 800;
    font-size: 1.05rem;
    color: var(--text-dark);
    position: relative;
    z-index: 1;
}
body.dark-mode .path-step-number {
    background: var(--bg-dark);
    border-color: var(--border-dark);
    color: var(--text-light);
}

.path-step-title {
    display: block;
    font-weight: 700;
    font-size: 1.05rem;
    margin-bottom: 0.25rem;
}
.path-step-desc {
    display: block;
    font-size: 0.9rem;
    color: var(--text-muted);
    line-height: 1.5;
}

/* Done: the number circle becomes a green checkmark, the card itself
   very slightly muted so the eye naturally moves past it toward
   whatever comes next, without hiding or graying out the text to the
   point of being hard to read. */
.path-step.done .path-step-number {
    background: var(--brand-green);
    border-color: var(--brand-green);
    color: #fff;
}
.path-step.done a { opacity: 0.75; }

/* Next: the one step actually highlighted, since this is the answer to
   "which one should I read now" the feature exists to give. */
.path-step.next a {
    border-color: var(--brand-gold);
    border-width: 2px;
    box-shadow: 0 4px 16px rgba(249, 171, 13, 0.2);
}
.path-step.next .path-step-number {
    background: var(--brand-gold);
    border-color: var(--brand-gold);
    color: var(--text-dark);
}
.path-step.next .path-step-title::after {
    content: 'পড়ুন এখন';
    display: inline-block;
    margin-left: 0.5rem;
    padding: 0.15rem 0.55rem;
    font-size: 0.68rem;
    font-weight: 800;
    color: var(--text-dark);
    background: var(--brand-gold);
    border-radius: 999px;
    vertical-align: middle;
}

@media (max-width: 480px) {
    .path-step a { padding: var(--spacing-sm); gap: var(--spacing-sm); }
    .path-step-number { width: 34px; height: 34px; font-size: 0.95rem; }
    .learning-path-steps::before { left: 24px; }
    .path-step-title { font-size: 0.95rem; }
    .path-step-desc { font-size: 0.83rem; }
}
