:root {
    --orange: #f97315;
    --orange-hover: #fc5f01;
    --orange-dark: #c27431;
    --orange-light: rgba(249,115,21,.08);
    --teal: #1d9e75;
    --teal-light: rgba(29,158,117,.08);
    --bg: #effcf4;
    --bg-gradient-start: #effcf4;
    --bg-gradient-end: #f5f3ee;
    --dark: #1b1c1b;
    --card-bg: #ffffff;
    --card-border: rgba(0,0,0,.06);
    --card-shadow: 0 1px 3px rgba(0,0,0,.04), 0 4px 12px rgba(0,0,0,.03);
    --card-shadow-hover: 0 2px 8px rgba(0,0,0,.06), 0 8px 24px rgba(0,0,0,.06);
    --text-primary: #1b1c1b;
    --text-secondary: #6b6b6b;
    --text-muted: #999;
    --border-color: #e8e8e8;
    --input-bg: #ffffff;
    --input-border: #e0e0e0;
    --green-check: #2ecc40;
    --red-error: #e74c3c;
    --gold: #f0a500;
    --nav-link: #555;
    --nav-link-active: var(--orange);
    /* Navigation-bar strip. Tokenized so a white-labelled facility can own it
       (app/services/branding.py overrides it per tenant); the value here is
       Oskoole's own and is unchanged. */
    --navbar-bg: #F8F3EA;
    --footer-text: #999;
    --modal-bg: #ffffff;
    --modal-border: rgba(0,0,0,.08);
    --sidebar-item-bg: #ffffff;
    --sidebar-item-hover: #f5f5f5;
    --sidebar-item-active: var(--orange-light);
    --sidebar-item-active-text: var(--orange);
    --progress-bg: #e8e8e8;
    --step-badge-bg: var(--orange);
    /* Text/icon colour that sits ON --orange. #ffffff is Oskoole's own choice
       (a known 2.80:1 against #f97315 — pre-existing, unchanged here). For a
       white-labelled facility, app/services/branding.py overrides this with
       whichever of #FFFFFF / #1B1C1B has the higher WCAG contrast against that
       tenant's primary, so button labels stay readable on any brand colour.
       See spec/features/028-white-label-brand-colors/spec.md section 8. */
    --brand-on-primary: #ffffff;
    --step-badge-text: var(--brand-on-primary);
    --audio-bg: #f8f8f8;
    /* Link colour for SMALL body text sitting ON a card/toast surface.
       --orange itself is only safe as a foreground for icons and badges (exempt
       or large): #f97315 on --card-bg #ffffff is 2.80:1, the same failing ratio
       documented for --brand-on-primary just above. Darkened until it clears
       WCAG AA for normal text: #b8460a on #ffffff is 5.36:1, and its hover
       #8f3607 is 7.78:1. The dark block below hands both back to the plain
       orange pair, which already passes on --card-bg #262524 (5.46:1). */
    --link-on-card: #b8460a;
    --link-on-card-hover: #8f3607;

    --game-neu-btn: 5px 5px 14px rgba(249,115,21,.3), -3px -3px 10px rgba(255,255,255,.5), inset 0 1px 0 rgba(255,255,255,.2);
}

[data-theme="dark"] {
    --bg: #1b1c1b;
    --bg-gradient-start: #1e1d1c;
    --bg-gradient-end: #1b1c1b;
    --card-bg: #262524;
    --card-border: rgba(255,255,255,.06);
    --card-shadow: 0 1px 3px rgba(0,0,0,.2), 0 4px 12px rgba(0,0,0,.15);
    --card-shadow-hover: 0 2px 8px rgba(0,0,0,.25), 0 8px 24px rgba(0,0,0,.2);
    --text-primary: #f0ede8;
    --text-secondary: #9a9590;
    --text-muted: #6b6560;
    --border-color: rgba(255,255,255,.08);
    --input-bg: #2a2928;
    --input-border: rgba(255,255,255,.1);
    --nav-link: #9a9590;
    --navbar-bg: rgba(27,28,27,.8);
    --footer-text: #5a5550;
    --modal-bg: #262524;
    --modal-border: rgba(255,255,255,.08);
    --sidebar-item-bg: #2a2928;
    --sidebar-item-hover: #302f2e;
    --sidebar-item-active: rgba(249,115,21,.12);
    --sidebar-item-active-text: var(--orange);
    --progress-bg: rgba(255,255,255,.08);
    --audio-bg: #2a2928;
    /* On the dark card the plain orange pair already clears AA, so small link
       text keeps the brand colour here (see the light values in :root). */
    --link-on-card: var(--orange);
    --link-on-card-hover: var(--orange-hover);

    --game-neu-btn: 4px 4px 12px rgba(249,115,21,.25), -3px -3px 8px rgba(60,55,48,.1), inset 0 1px 0 rgba(255,255,255,.06);
}

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

body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
    background: linear-gradient(135deg, var(--bg-gradient-start) 0%, var(--bg-gradient-end) 100%);
    min-height: 100vh;
    color: var(--text-primary);
    transition: background .3s, color .3s;
}

body::before {
    content: '';
    position: fixed; inset: 0;
    background:
        radial-gradient(ellipse 70% 50% at 0% 0%, rgba(78,160,78,.06) 0%, transparent 60%),
        radial-gradient(ellipse 60% 40% at 100% 0%, rgba(249,115,21,.04) 0%, transparent 50%);
    pointer-events: none; z-index: 0;
}

[data-theme="dark"] body::before {
    background:
        radial-gradient(ellipse 70% 50% at 0% 0%, rgba(249,115,21,.06) 0%, transparent 60%),
        radial-gradient(ellipse 60% 40% at 100% 100%, rgba(58,175,169,.04) 0%, transparent 50%);
}

.navbar {
    position: sticky; top: 0; z-index: 100;
    background: var(--navbar-bg);
    backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
    border-bottom: 1px solid var(--border-color);
    padding: 0 2rem;
    transition: background .3s, border-color .3s;
}

.navbar-inner {
    max-width: 1280px; margin: 0 auto;
    display: flex; align-items: center; height: 60px; gap: 2rem;
}

/* Super-admin "view as" banner. FIXED and above every overlay in the app, which
   a sticky bar in normal flow is not: .modal-backdrop (10000), .terms-overlay
   (9999), the tutorial progress banner (19000), the video help player (19500),
   the step editor (19800), .lightbox (20000) and the toast container (20001)
   all painted straight over it, so opening any modal while viewing as someone
   took the bar AND its Exit button off the screen — exactly what the partial's
   "NOT DISMISSIBLE" design forbids. 21000 clears the highest of them.

   `fixed` leaves the flow, so the height has to come back from somewhere: the
   partial renders a sibling SPACER of the same height, which reproduces the
   old sticky layout byte for byte and keeps the promise that no page needs a
   body class or a padding-top of its own (19 standalone templates, none
   sharing a <body> tag, make a class-based approach unworkable). Pages with a
   fixed overlay of their own still pad it by hand — see auth/terms.html.
   The general sibling combinator then pins the (sticky) navbar below the bar;
   both are children of <body> and the banner always precedes the navbar.
   Pages with no banner are byte-identical. */
.impersonation-banner { position: fixed; top: 0; left: 0; right: 0; z-index: 21000; height: 44px; }
/* flex-shrink: 0 because two of the pages that render this have a flex-column
   <body> (auth/wrong-residence.html), where a shrinkable spacer would collapse. */
.impersonation-banner-spacer { height: 44px; flex-shrink: 0; }
.impersonation-banner ~ .navbar { top: 44px; }

/* Deliberately NOT tokenized against --brand-*. A white-labelled facility can
   repaint every other surface on the page; this one bar must keep reading as
   FOREIGN chrome even on a home whose own palette happens to be amber. Hence
   literal values, scoped to this component so they cannot leak. Amber/orange
   is the repo's warning register (cf. --gold, .toast--warning), turned up to a
   solid fill because nothing else on the page announces "you are inside
   someone else's account". #1c1917 on #f59e0b is 8.1:1. */
.impersonation-banner {
    background: #f59e0b;
    color: #1c1917;
    border-bottom: 2px solid #b45309;
    /* Own font stack, not the page's: a facility's brand font must not make
       this look like part of their product. */
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
.impersonation-banner-inner {
    max-width: 1280px; margin: 0 auto; height: 100%;
    padding: 0 2rem;
    display: flex; align-items: center; gap: .65rem;
}
.impersonation-banner-icon { flex-shrink: 0; }
.impersonation-banner-text {
    flex: 1; min-width: 0;
    display: flex; align-items: baseline; gap: .5rem;
    font-size: .85rem; line-height: 1.2;
}
/* The NAME is the variable-length half — and the user-controlled one — so it is
   the half that truncates. Wrapping to a second row is not on offer: the bar's
   44px is what the navbar offset above is hardcoded to, and a taller banner
   would slide the whole page up underneath the navbar. */
.impersonation-banner-text strong {
    font-weight: 700;
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.impersonation-banner-admin {
    flex-shrink: 0; white-space: nowrap;
    /* 6.2:1 on the amber even after the blend — this is .78rem body text. */
    font-size: .78rem; opacity: .85;
}
.impersonation-banner-exit {
    flex-shrink: 0;
    padding: .3rem 1rem; border: 0; border-radius: 8px;
    background: #1c1917; color: #fef3c7;
    font-family: inherit; font-size: .8rem; font-weight: 700;
    cursor: pointer; transition: background .2s;
}
.impersonation-banner-exit:hover { background: #44403c; }
.impersonation-banner-exit:disabled { opacity: .6; cursor: progress; }
.impersonation-banner-exit:focus-visible {
    outline: 2px solid #1c1917; outline-offset: 2px;
}

/* Dark theme keeps the amber — the point is that it does NOT blend in — but
   drops a step so it does not glare on a dark page. #1c1917 on #d97706 is
   5.5:1. */
[data-theme="dark"] .impersonation-banner {
    background: #d97706;
    border-bottom-color: #92400e;
}

@media (max-width: 960px) {
    /* The mobile notification sheet is `position: fixed` under the bar, so it
       is the one thing that does not inherit the navbar's push (61px = the
       bar's 60px + its 1px border) and has to be offset by hand. */
    .impersonation-banner ~ .navbar .nav-notif-panel { top: 105px; }
}

@media (max-width: 600px) {
    .impersonation-banner-inner { padding: 0 1rem; gap: .5rem; }
    /* Phones cannot hold both, and the email does not shrink. Dropping it here
       is what leaves the NAME room to be read — which is the half being
       checked. The email identifies the operator's own account, so it is the
       recoverable one: they are signed into it. */
    .impersonation-banner-admin { display: none; }
}

.nav-logo {
    display: flex; align-items: center;
    text-decoration: none; flex-shrink: 0; height: 36px;
}
.nav-logo img { height: 150px; width: auto; max-width: 200px; object-fit: contain; pointer-events: none; }

.nav-links { display: flex; align-items: center; gap: 1.75rem; list-style: none; }
.nav-links a {
    font-size: .875rem; font-weight: 500; color: var(--nav-link);
    text-decoration: none; transition: color .2s;
}
.nav-links a:hover, .nav-links a.active { color: var(--nav-link-active); }

/* Theme-aware "Back" pill (see partials/back_link.html) */
.back-pill {
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .55rem 1.05rem; border-radius: 9999px;
    background: var(--card-bg); border: 1px solid var(--border-color);
    color: var(--text-primary); font-family: inherit; font-size: .875rem; font-weight: 600;
    cursor: pointer; box-shadow: var(--card-shadow);
    transition: transform .15s, color .15s, border-color .15s;
}
.back-pill:hover { transform: translateX(-2px); color: var(--orange); border-color: var(--orange); }
.back-pill svg { width: 16px; height: 16px; }

.nav-dropdown { position: relative; }
.nav-dropdown-trigger {
    display: flex; align-items: center; gap: .3rem; cursor: pointer;
}
.nav-dropdown-trigger .chevron {
    transition: transform .2s; font-size: .6rem; margin-top: 1px;
}
.nav-dropdown:hover .chevron { transform: rotate(180deg); }
.nav-dropdown-menu {
    position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
    min-width: 520px; padding: 1.5rem 1.75rem;
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: 12px;
    box-shadow: 0 8px 32px rgba(0,0,0,.10), 0 2px 8px rgba(0,0,0,.04);
    display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem;
    opacity: 0; visibility: hidden;
    transition: opacity .2s, visibility .2s, transform .2s;
    transform: translateX(-50%) translateY(8px);
    z-index: 200;
}
/* Guides mega-menu. COUPLED to NAVBAR_SECTION_SLUGS in app/categories.py: the
   column count below is hardcoded, but the number of columns actually rendered
   comes from that tuple. Adding a 5th slug REQUIRES updating repeat(4, 1fr) and
   the width — otherwise the 5th column wraps onto a second grid row and pushes
   the full-width .dropdown-more footer (grid-column: 1 / -1) below it. */
.nav-dropdown-menu--wide {
    min-width: 0;
    width: min(620px, calc(100vw - 32px));
    padding: 1.25rem 1.5rem;
    grid-template-columns: repeat(4, 1fr); gap: 1.25rem;
}
.nav-dropdown-menu--simple {
    min-width: 200px; padding: .85rem 1rem;
    display: block;
}
.nav-dropdown-menu--simple .dropdown-group-items { gap: .25rem; }
.nav-dropdown-menu--simple .dropdown-group-items a {
    font-size: .8rem; padding: .35rem .25rem;
}
/* White-label dropdown: group headings (matches the Guides mega-menu titles). */
.nav-wl-group-label {
    font-size: .65rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .06em; color: var(--orange);
    padding: .5rem .25rem .2rem;
}
.nav-wl-group-label + li a { padding-top: .15rem; }
.nav-wl-group-label:not(:first-child) {
    margin-top: .3rem; border-top: 1px solid var(--border-color);
}
.nav-dropdown-menu--wide .dropdown-group-title {
    font-size: .65rem; margin-bottom: .55rem;
    letter-spacing: .05em;
}
.nav-dropdown-menu--wide .dropdown-group-items { gap: .2rem; }
.nav-dropdown-menu--wide .dropdown-group-items a {
    font-size: .72rem; padding: .2rem 0; line-height: 1.3;
}
.nav-dropdown:hover .nav-dropdown-menu {
    opacity: 1; visibility: visible;
    transform: translateX(-50%) translateY(0);
}
.nav-dropdown-menu::before {
    content: ''; position: absolute; top: -10px; left: 0; right: 0; height: 10px;
}
.dropdown-group-title {
    display: flex; align-items: center; gap: .4rem;
    font-size: .7rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .06em; margin-bottom: .6rem; color: var(--orange);
}
.dropdown-group-title svg { flex-shrink: 0; }
.dropdown-group-items { list-style: none; display: flex; flex-direction: column; gap: .25rem; }
.dropdown-group-items a {
    font-size: .8rem; font-weight: 400; color: var(--text-secondary);
    text-decoration: none; padding: .25rem 0; display: block;
    transition: color .15s;
}
.dropdown-group-items a:hover { color: var(--orange); }

/* Guides mega-menu footer: spans the full grid width so it sits below all
   four category columns, with the link pinned bottom-right. */
.dropdown-more {
    grid-column: 1 / -1;
    display: flex; justify-content: flex-end;
    padding-top: .6rem;
    border-top: 1px solid var(--border-color);
}
.dropdown-more-link {
    display: inline-flex; align-items: center; gap: .3rem;
    font-size: .72rem; font-weight: 600; color: var(--orange);
    text-decoration: none; transition: color .15s;
}
.dropdown-more-link svg { flex-shrink: 0; transition: transform .15s; }
.dropdown-more-link:hover { color: var(--orange-hover); text-decoration: underline; }
.dropdown-more-link:hover svg { transform: translateX(2px); }

.nav-right { margin-left: auto; display: flex; align-items: center; gap: 1rem; }

.nav-history-btn {
    display: flex; align-items: center; gap: .4rem;
    font-size: .875rem; font-weight: 500; color: var(--nav-link);
    background: none; border: none; cursor: pointer;
    transition: color .2s; padding: .4rem .6rem; border-radius: 8px;
    font-family: inherit;
}
.nav-history-btn:hover { color: var(--text-primary); }

/* Subscribe CTA: a SOLID pill that INVERTS the theme, on purpose — it is the
   one conversion action in the bar. Among the signed-in controls (History, the
   theme toggle, the user chip — all ghost or outlined) the FILL is what makes
   it read as a button rather than a fourth nav link. It is NOT always the only
   filled control: anonymous on the apex, can_subscribe is true and
   partials/header.html also renders .nav-sign-in-btn, a solid --orange. That
   pairing is deliberate and is told apart by shape and by KIND of contrast — a
   999px tonal pill beside a 10px-radius chromatic one. Orange is this bar's
   standing brand furniture (links, badges, the sign-in affordance), so the
   tonal pill is the one that reads as "act here".

   It does not track the theme, it opposes it: --text-primary is the background
   (near-black on light, near-white on dark) and --card-bg is the label. Both
   tokens already flip between the two roots, so this single rule inverts
   correctly in both themes — no [data-theme="dark"] override, no new token.

   The label is --card-bg and NOT --bg: app/services/branding.py white-labels a
   tenant by injecting a `:root:root` block that overrides --bg, --navbar-bg
   and the --orange family, but never --text-primary or --card-bg. So this pair
   holds its contrast on every tenant — 17.1:1 light (#1b1c1b on #ffffff) and
   13.1:1 dark (#f0ede8 on #262524) — whereas var(--bg) would hand the label a
   tenant's own surface colour and could fall under AA.

   What a tenant CAN repaint is --navbar-bg, the bar this pill sits on, and
   only in the light theme (build_brand_css restores Oskoole's own --navbar-bg
   inside the dark block it injects). Nearly moot — but NOT because "Subscribe
   is hidden on tenant hosts": it is kept for a signed-in trialist on a
   facility subdomain, because the predicate follows the ACCOUNT, not the Host
   (tests/test_navbar_subscribe.py). The real reason is that a viewer who can
   see this button never receives a facility's palette. Signed in,
   can_subscribe requires is_personal_account(), i.e. membership of the
   public-users org, and branding follows user.geriatric rather than the host
   (app/main.py); anonymous, brand CSS requires a resolved tenant while
   can_subscribe requires no slug, and a tenant is only ever resolved from one.
   So the exposure that survives is a single row: a super-admin setting a dark
   `surface` on the public-users org would darken the light-theme bar under
   this near-black pill, and branding.py's contrast band only warns about it
   ("Nothing here blocks a save").

   The 1.5px border stays, set to the fill colour, so the pill's box is exactly
   the size it has always been and hover/focus can recolour just the ring. */
.nav-subscribe-btn {
    display: flex; align-items: center;
    font-size: .875rem; font-weight: 600; color: var(--card-bg);
    background: var(--text-primary); border: 1.5px solid var(--text-primary);
    border-radius: 999px; text-decoration: none;
    transition: color .2s, background .2s, border-color .2s, box-shadow .2s, transform .15s;
    padding: .35rem .9rem;
}
/* Hover/focus keep the inverted fill: filling with --orange would put the
   label on --brand-on-primary, the 2.80:1 pair documented in :root as failing
   AA for normal text — and this label is .875rem/600, i.e. normal text. The
   brand colour goes into the RING instead, where it is decorative and exempt.

   One ratio cannot describe that ring. The border separates two surfaces that
   swap with the theme: the fill (--text-primary) inside and --navbar-bg
   outside. --orange is 6.10:1 against #1b1c1b, and #1b1c1b is the FILL in
   light and the BAR in dark — so the flip lands one 6.10:1 edge in EITHER
   theme, read against the pill's inside in light and against the bar in dark.
   The opposite edge is the weak one both times (2.54:1 vs the light bar
   #F8F3EA, 2.40:1 vs the dark fill #f0ede8). The bloom is not the backup it
   looks like: --orange-light is 8% alpha with no dark redeclaration, so it
   composites to ~1.1:1 against the bar in both themes — atmosphere, not
   signal. Call the border flip legible rather than unmistakable; the outline
   below is the state change that cannot be missed. The 1px lift matches
   .nav-sign-in-btn beside it. */
.nav-subscribe-btn:hover,
.nav-subscribe-btn:focus-visible {
    border-color: var(--orange);
    box-shadow: 0 0 0 3px var(--orange-light);
    transform: translateY(-1px);
}
/* Keyboard focus gets everything hover gets PLUS a real outline, drawn in
   --text-primary rather than --orange. Orange against --navbar-bg swings with
   the theme (2.54:1 light, 6.10:1 dark), while --text-primary is high in both
   (15.5:1 light, 14.6:1 dark), so the outline does not depend on which theme
   the user picked. An outline also survives forced-colors mode, where
   box-shadow is dropped. */
.nav-subscribe-btn:focus-visible {
    outline: 3px solid var(--text-primary);
    outline-offset: 2px;
}

.theme-toggle-btn {
    width: 36px; height: 36px;
    display: flex; align-items: center; justify-content: center;
    background: none; border: 1px solid var(--border-color);
    border-radius: 10px; cursor: pointer; font-size: 1rem;
    color: var(--text-secondary); transition: all .2s;
}
.theme-toggle-btn:hover { background: var(--card-bg); border-color: var(--text-muted); }

/* ── Notification bell ──────────────────────────────────────────────────────
   Markup + behavior live in partials/header.html (signed-in users only).
   The bell button reuses .theme-toggle-btn for its 36px icon-family sizing. */
.nav-notif { position: relative; }
.nav-notif-bell { position: relative; }
.nav-notif-badge {
    position: absolute; top: -6px; right: -6px;
    min-width: 18px; height: 18px; padding: 0 4px;
    box-sizing: border-box;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px;
    background: var(--orange); color: var(--brand-on-primary);
    /* Ring matches the page background so the bubble pops on both themes. */
    border: 2px solid var(--bg);
    font-size: .65rem; font-weight: 700; line-height: 1;
}
.nav-notif-badge[hidden] { display: none; }
.nav-notif-panel {
    position: absolute; right: 0; top: calc(100% + 8px);
    width: 340px; max-height: 420px; overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: 14px;
    box-shadow: var(--card-shadow-hover);
    /* Above the hover dropdowns (200); same layer as the mobile nav panel. */
    z-index: 300;
}
.nav-notif-panel[hidden] { display: none; }
.nav-notif-head {
    padding: .7rem .9rem;
    font-size: .8rem; font-weight: 700; color: var(--text-primary);
    border-bottom: 1px solid var(--card-border);
}
/* Keeps the panel body from collapsing while "Loading…" swaps to results. */
.nav-notif-list { min-height: 60px; }
.nav-notif-item {
    display: flex; gap: .6rem; padding: .7rem .9rem;
    border-bottom: 1px dashed var(--card-border);
}
.nav-notif-item:last-child { border-bottom: none; }
.nav-notif-item--unread { background: var(--orange-light); }
.nav-notif-item--streak { background: var(--orange-light); }
.nav-notif-item--streak .nav-notif-item-icon { color: var(--orange); }
.nav-notif-item--important { border-left: 3px solid var(--gold); }
.nav-notif-item-icon {
    flex-shrink: 0; display: inline-flex; margin-top: 2px;
    color: var(--text-secondary);
}
.nav-notif-item-text { min-width: 0; flex: 1; }
.nav-notif-item-title {
    font-weight: 700; font-size: .875rem; line-height: 1.35;
    color: var(--text-primary);
}
.nav-notif-item-body {
    font-size: .85rem; color: var(--text-secondary); line-height: 1.45;
    margin-top: .15rem;
    display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
    overflow: hidden;
}
.nav-notif-item-date { font-size: .72rem; color: var(--text-muted); margin-top: .25rem; }
.nav-notif-item-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--orange);
    flex-shrink: 0; align-self: flex-start; margin-top: 6px;
}
/* Per-item dismiss (×). 22px hit target, quiet until hovered/focused. */
.nav-notif-item-x {
    flex-shrink: 0; align-self: flex-start;
    width: 22px; height: 22px; padding: 0; margin: -1px -4px 0 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: none; border: none; border-radius: 6px;
    color: var(--text-muted); cursor: pointer;
    transition: background .15s, color .15s;
}
.nav-notif-item-x:hover,
.nav-notif-item-x:focus-visible {
    background: var(--border-color);
    color: var(--text-primary);
}
.nav-notif-chip {
    display: inline-block; margin-left: .4rem; padding: .12rem .45rem;
    border-radius: 999px; vertical-align: middle;
    background: var(--gold); color: #fff;
    font-size: .62rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .04em;
}
.nav-notif-empty {
    text-align: center; padding: 1.5rem;
    color: var(--text-muted); font-size: .85rem;
}
.nav-notif-empty svg { display: block; margin: 0 auto .4rem; color: var(--teal); }

.nav-sign-in-btn {
    display: inline-flex; align-items: center;
    background: var(--orange); color: var(--brand-on-primary);
    font-size: .875rem; font-weight: 600;
    padding: .5rem .95rem; border-radius: 10px;
    text-decoration: none; transition: filter .15s, transform .15s;
}
.nav-sign-in-btn:hover { filter: brightness(1.05); transform: translateY(-1px); }

.nav-user-menu .nav-user-trigger {
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .3rem .6rem; border-radius: 999px;
    color: var(--text-primary); text-decoration: none;
    font-size: .875rem; font-weight: 600;
    border: 1px solid var(--border-color); background: transparent;
    transition: background .15s, border-color .15s;
}
.nav-user-menu .nav-user-trigger:hover { background: var(--card-bg); border-color: var(--text-muted); }
.nav-user-avatar {
    width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0;
    background: var(--orange); color: var(--brand-on-primary);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: .85rem; font-weight: 700;
}
.nav-user-name {
    max-width: 9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nav-user-menu-panel {
    right: 0; left: auto; min-width: 220px;
    transform: translateY(8px);
}
.nav-user-menu:hover .nav-user-menu-panel {
    transform: translateY(0);
}
.nav-user-meta {
    padding: .25rem .25rem .65rem;
    border-bottom: 1px solid var(--border-color);
    margin-bottom: .5rem;
}
.nav-user-meta-name { font-weight: 600; font-size: .875rem; color: var(--text-primary); }
.nav-user-meta-email { font-size: .75rem; color: var(--text-muted); margin-top: .15rem; }
.nav-user-meta-role {
    margin-top: .35rem; font-size: .7rem; text-transform: uppercase; letter-spacing: .05em;
    color: var(--teal); font-weight: 600;
}

.site-footer {
    text-align: center; padding: 3rem 1.5rem 2rem;
    color: var(--footer-text); font-size: .8rem; position: relative; z-index: 1;
}
.footer-brand {
    font-weight: 600; font-size: .9rem; color: var(--text-secondary);
    margin-bottom: .3rem; display: flex; align-items: center; justify-content: center; gap: .35rem;
}
.footer-legal {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
    gap: .35rem .6rem;
}
.footer-sep { color: var(--border-color); }
.footer-link {
    color: var(--footer-text); text-decoration: none; font-weight: 600;
    transition: color .15s;
}
.footer-link:hover { color: var(--orange); text-decoration: underline; }
/* Release number (partials/app-version.html): last line of the footer, bottom
   right. Tabular digits so v1.9.0 → v1.10.0 does not shift the text. */
.footer-version { text-align: right; margin-top: .9rem; }
.app-version {
    font-size: .7rem; color: var(--text-muted);
    font-variant-numeric: tabular-nums; letter-spacing: .02em;
    white-space: nowrap;
}

.modal-backdrop {
    position: fixed; inset: 0;
    background: rgba(0,0,0,.4); backdrop-filter: blur(4px);
    display: flex; align-items: center; justify-content: center; z-index: 10000;
}
.modal-backdrop.hidden { display: none !important; }
.modal {
    background: var(--modal-bg); border: 1px solid var(--modal-border);
    border-radius: 20px; padding: 2rem 2.25rem;
    width: 90%; max-width: 480px; color: var(--text-primary);
    position: relative; box-shadow: 0 24px 64px rgba(0,0,0,.2);
    animation: modalIn .25s ease both;
    /* Cap tall forms to the viewport and scroll inside the modal instead of
       letting the page behind scroll (which hid the action buttons). */
    max-height: 90vh; overflow-y: auto;
}
@keyframes modalIn { from { opacity:0; transform:scale(.96) translateY(8px); } to { opacity:1; transform:scale(1) translateY(0); } }
.modal-close {
    position: absolute; top: 1rem; right: 1.25rem;
    background: none; border: none; color: var(--text-muted);
    font-size: 1.2rem; cursor: pointer; transition: color .15s;
}
.modal-close:hover { color: var(--text-primary); }
.modal h3 { font-size: 1.15rem; font-weight: 700; margin-bottom: .4rem; }
.modal p { color: var(--text-secondary); font-size: .88rem; margin-bottom: 1.5rem; }

.modal-actions { display: flex; gap: .75rem; }
.modal-submit {
    flex: 1; padding: .75rem; background: var(--orange); color: var(--brand-on-primary);
    border: none; border-radius: 10px; font-size: .95rem; font-weight: 600;
    cursor: pointer; transition: opacity .2s; font-family: inherit;
}
.modal-submit:hover { opacity: .88; }
.modal-submit:disabled { opacity: .4; cursor: not-allowed; }
.modal-cancel {
    padding: .75rem 1.25rem; background: none; color: var(--text-muted);
    border: none; border-radius: 10px; font-size: .95rem;
    cursor: pointer; transition: color .15s; font-family: inherit;
}
.modal-cancel:hover { color: var(--text-primary); }

.share-option {
    display: flex; align-items: center; gap: 1rem;
    padding: .75rem 1rem; border-radius: 12px;
    color: var(--text-primary); text-decoration: none;
    font-weight: 500; transition: background .2s;
}
.share-option:hover { background: var(--orange-light); }
.share-icon { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; }
.share-icon svg { width: 22px; height: 22px; }
.copy-link-box {
    margin-top: 1rem; background: var(--input-bg);
    border: 1px solid var(--input-border); border-radius: 12px;
    display: flex; align-items: center; padding: .4rem .4rem .4rem 1rem; gap: .5rem;
}
.copy-link-box input {
    flex: 1; background: transparent; border: none;
    color: var(--text-primary); outline: none;
    font-size: .85rem; font-family: inherit; min-width: 0;
}
.copy-link-box button {
    background: var(--orange); color: var(--brand-on-primary); border: none;
    padding: .55rem 1rem; border-radius: 8px; cursor: pointer;
    font-size: .8rem; font-weight: 600; font-family: inherit; transition: background .2s;
}
.copy-link-box button:hover { background: var(--orange-hover); }

.stars { display: flex; gap: .5rem; justify-content: center; margin-bottom: .6rem; }
.star { font-size: 2.4rem; cursor: pointer; color: var(--progress-bg); transition: color .15s, transform .1s; user-select: none; }
.star.active { color: var(--gold); }
.star:hover { transform: scale(1.18); color: var(--gold); }
.star-hint { text-align: center; font-size: .82rem; color: var(--text-muted); min-height: 1.2em; margin-bottom: 1rem; font-style: italic; }
.comment-box {
    width: 100%; background: var(--input-bg); border: 1px solid var(--input-border);
    border-radius: 10px; color: var(--text-primary); padding: .75rem;
    font-size: .9rem; resize: vertical; min-height: 80px; margin-bottom: 1rem;
    font-family: inherit; transition: background .3s, color .3s;
}
.comment-box::placeholder { color: var(--text-muted); }
.comment-box:focus { outline: none; border-color: var(--orange); }

.history-modal-inner { max-height: 70vh; display: flex; flex-direction: column; }
.history-header { display: flex; align-items: center; gap: .75rem; margin-bottom: 1.25rem; }
.history-icon {
    width: 42px; height: 42px; border-radius: 12px;
    background: var(--orange-light); display: flex;
    align-items: center; justify-content: center; flex-shrink: 0;
}
.history-icon svg { width: 22px; height: 22px; stroke: var(--orange); fill: none; stroke-width: 2; }
.history-search {
    width: 100%; padding: .7rem 1rem .7rem 2.5rem;
    background: var(--input-bg); border: 1px solid var(--input-border);
    border-radius: 12px; font-size: .9rem; font-family: inherit;
    color: var(--text-primary); outline: none; transition: border-color .2s;
    margin-bottom: 1rem;
}
.history-search:focus { border-color: var(--orange); }
.history-search-wrapper { position: relative; }
.history-search-wrapper svg {
    position: absolute; left: .85rem; top: 50%; transform: translateY(-50%);
    width: 16px; height: 16px; stroke: var(--text-muted); fill: none; stroke-width: 2;
}
.history-list {
    flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: .5rem;
    max-height: 400px; scrollbar-width: thin;
}
.history-item {
    display: flex; align-items: center; gap: .75rem;
    padding: .85rem 1rem; background: var(--card-bg);
    border: 1px solid var(--card-border); border-radius: 14px;
    text-decoration: none; color: var(--text-primary); transition: all .2s;
}
.history-item:hover { border-color: var(--orange); background: var(--orange-light); }
.history-item-icon {
    width: 40px; height: 40px; border-radius: 10px;
    background: var(--input-bg); display: flex;
    align-items: center; justify-content: center; flex-shrink: 0;
}
.history-item-icon svg { width: 18px; height: 18px; stroke: var(--text-muted); fill: none; stroke-width: 1.5; }
.history-item-text { flex: 1; min-width: 0; }
.history-item-title { font-weight: 600; font-size: .9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.history-item-meta { font-size: .75rem; color: var(--text-muted); display: flex; align-items: center; gap: .4rem; margin-top: .15rem; }
.history-item-meta .star-small { color: var(--orange); }
.history-item-arrow { color: var(--text-muted); flex-shrink: 0; font-size: 1rem; }

/* Own-tutorial controls on each compact history row: favorite star + delete.
   Both live inside the row's <a>, so their handlers stop the click from
   navigating. Colours come from theme variables so dark mode flips for free. */
.history-item-actions { display: flex; align-items: center; gap: .25rem; flex-shrink: 0; }
.history-item-fav, .history-item-del-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; padding: 0;
    background: transparent; border: 1px solid transparent; border-radius: 8px;
    cursor: pointer; color: var(--text-muted);
    transition: color .15s, background .15s, border-color .15s;
}
.history-item-fav svg, .history-item-del-btn svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; }
.history-item-fav:hover { color: var(--orange); background: var(--orange-light); }
.history-item-fav.is-fav { color: var(--orange); }
.history-item-fav.is-fav svg { fill: var(--orange); stroke: var(--orange); }
.history-item-del-btn:hover { color: var(--red-error); background: rgba(231,76,60,.08); border-color: rgba(231,76,60,.25); }

/* Inline two-step delete confirm (mirrors the announcements askDelete pattern). */
.history-confirm { display: inline-flex; align-items: center; gap: .25rem; }
.history-confirm-yes, .history-confirm-no {
    display: inline-flex; align-items: center; justify-content: center;
    height: 30px; padding: 0 .6rem; border-radius: 8px;
    font-size: .72rem; font-weight: 700; font-family: inherit; cursor: pointer;
    border: 1px solid transparent;
}
.history-confirm-yes { background: var(--red-error); color: #fff; }
.history-confirm-yes:hover { filter: brightness(1.05); }
.history-confirm-no { background: transparent; color: var(--text-secondary); border-color: var(--border-color); }
.history-confirm-no:hover { color: var(--text-primary); border-color: var(--text-muted); }

/* "Favorites only" filter chip below the search box. */
.history-fav-chip {
    display: inline-flex; align-items: center; gap: .4rem;
    padding: .45rem .9rem; margin-bottom: 1rem;
    background: var(--card-bg); border: 1px solid var(--card-border); border-radius: 999px;
    font-size: .8rem; font-weight: 600; font-family: inherit; color: var(--text-secondary);
    cursor: pointer; transition: color .2s, border-color .2s, background .2s;
}
.history-fav-chip svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; }
.history-fav-chip:hover { border-color: var(--orange); color: var(--orange); }
.history-fav-chip.is-active { background: var(--orange-light); color: var(--orange); border-color: var(--orange); }
.history-fav-chip.is-active svg { fill: var(--orange); stroke: var(--orange); }

@media (max-width: 500px) {
    .history-item-fav, .history-item-del-btn { width: 36px; height: 36px; }
    .history-confirm-yes, .history-confirm-no { height: 36px; }
}

.history-close-btn {
    width: 100%; margin-top: 1rem; padding: .85rem;
    background: var(--card-bg); border: 1px solid var(--border-color);
    border-radius: 14px; font-size: .95rem; font-weight: 500;
    color: var(--text-secondary); cursor: pointer; font-family: inherit; transition: all .2s;
}
.history-close-btn:hover { border-color: var(--text-muted); color: var(--text-primary); }

.hidden { display: none !important; }

.lightbox {
    position: fixed; inset: 0; z-index: 20000;
    background: rgba(0,0,0,.85); backdrop-filter: blur(8px);
    display: flex; align-items: center; justify-content: center;
    cursor: zoom-out; animation: fadeIn .2s ease;
}
.lightbox.hidden { display: none !important; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.lightbox img {
    max-width: 92vw; max-height: 90vh;
    border-radius: 12px; box-shadow: 0 8px 40px rgba(0,0,0,.4);
    object-fit: contain;
}
.lightbox-close {
    position: absolute; top: 1.5rem; right: 1.5rem;
    background: rgba(255,255,255,.15); border: none;
    color: #fff; width: 40px; height: 40px; border-radius: 50%;
    font-size: 1.2rem; cursor: pointer; display: flex;
    align-items: center; justify-content: center; transition: background .2s;
}
.lightbox-close:hover { background: rgba(255,255,255,.3); }

/* ── Avatars ────────────────────────────────────────────────────────────────
   A picked avatar preset renders as a full-bleed SVG inside the same circle
   the initials use (the SVG carries its own colored circle). */
.avatar img, .nav-user-avatar img {
    width: 100%; height: 100%; border-radius: 50%;
    display: block; object-fit: cover;
}

/* ── Mobile navigation (hamburger) ─────────────────────────────────────────
   Below 960px the inline nav links become a tap-to-open panel under the bar,
   and hover dropdowns become tap-to-open accordions (hover doesn't exist on
   touch). The hamburger button lives in the header partial. */
.nav-hamburger {
    /* Matches .theme-toggle-btn so the icon row reads as one family. */
    width: 36px; height: 36px; flex-shrink: 0;
    display: none; align-items: center; justify-content: center;
    background: none; border: 1px solid var(--border-color);
    border-radius: 10px; cursor: pointer;
    color: var(--text-secondary); transition: all .2s;
}
.nav-hamburger:hover { background: var(--card-bg); border-color: var(--text-muted); color: var(--text-primary); }
.nav-hamburger svg { display: none; }
.nav-hamburger .nav-hamburger-open { display: block; }
.navbar.nav-open .nav-hamburger .nav-hamburger-open { display: none; }
.navbar.nav-open .nav-hamburger .nav-hamburger-close { display: block; }

@keyframes nav-panel-in {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: translateY(0); }
}

@media (max-width: 960px) {
    .nav-hamburger { display: inline-flex; }
    .navbar-inner { gap: 1rem; }
    .nav-right { gap: .5rem; }
    .nav-history-label { display: none; }
    /* .nav-subscribe-btn deliberately stays visible here: it is the one
       conversion CTA, and phones/tablets are this audience's main devices.
       The History label collapses to make room for it. */
    .nav-user-name { display: none; }

    /* Nav links: full-width panel anchored under the (sticky) bar. */
    .navbar .nav-links {
        display: none;
        position: absolute; top: 100%; left: 0; right: 0;
        flex-direction: column; align-items: stretch; gap: 0;
        background: var(--card-bg);
        border-bottom: 1px solid var(--border-color);
        box-shadow: 0 16px 32px rgba(0, 0, 0, .12);
        padding: .25rem 1.25rem .75rem;
        max-height: calc(100vh - 60px); overflow-y: auto;
        overscroll-behavior: contain;
        z-index: 300;
    }
    .navbar.nav-open .nav-links { display: flex; animation: nav-panel-in .18s ease; }
    .navbar .nav-links > li { width: 100%; border-bottom: 1px solid var(--border-color); }
    .navbar .nav-links > li:last-child { border-bottom: none; }
    .navbar .nav-links > li > a {
        display: flex; align-items: center; justify-content: space-between;
        padding: .9rem .25rem; font-size: .95rem;
    }

    /* Dropdowns inside the panel: tap-to-open accordions. */
    .navbar .nav-links .nav-dropdown .nav-dropdown-menu {
        position: static; display: none; opacity: 1; visibility: visible;
        transform: none; min-width: 0; width: auto;
        border: none; border-radius: 0; box-shadow: none; background: transparent;
        padding: 0 0 .9rem .5rem;
    }
    .navbar .nav-links .nav-dropdown.open .nav-dropdown-menu { display: block; }
    .navbar .nav-links .nav-dropdown.open .chevron { transform: rotate(180deg); }
    .navbar .nav-links .nav-dropdown-menu .dropdown-group { margin-bottom: .85rem; }
    .navbar .nav-links .nav-dropdown-menu .dropdown-group-items a { font-size: .85rem; padding: .4rem 0; }
    .navbar .nav-links .nav-dropdown-menu::before { display: none; }
    /* Accordion panel is a plain block here — left-align the footer link so it
       reads as one more tappable row under the categories. */
    .navbar .nav-links .nav-dropdown-menu .dropdown-more { justify-content: flex-start; }
    .navbar .nav-links .nav-dropdown-menu .dropdown-more-link { font-size: .85rem; padding: .2rem 0; }

    /* Avatar menu: stays anchored to the bar, right-aligned, tap-to-open. */
    .navbar .nav-user-menu .nav-dropdown-menu {
        left: auto; right: 0; transform: none;
        display: none; opacity: 1;
    }
    .navbar .nav-user-menu.open .nav-dropdown-menu { display: block; visibility: visible; }

    /* Notification panel: full-width sheet just under the sticky bar.
       The bar is .navbar-inner's 60px + the navbar's 1px bottom border.
       (The navbar's backdrop-filter makes it the containing block for
       fixed descendants, but it's pinned full-width at the viewport top,
       so these offsets land in the same place either way.) */
    .nav-notif-panel {
        position: fixed; top: 61px; left: .5rem; right: .5rem;
        width: auto;
        max-height: min(420px, calc(100vh - 76px));
    }
}

@media (max-width: 600px) {
    .navbar { padding: 0 1rem; }
    .nav-logo img { max-width: 140px; }
}
