
    /* ============================ HEADER / NAVIGATION ============================ */
    /* Scope to the top-level SITE header only. A bare `header{}` selector also
       matched every inner <header> in the app (.rx-hero, .exam-appbar, .sb-hero,
       .gr-cat-head, .wsread-header, and any takeover top-bar), handing each its
       own sticky z-index:50 stacking context + backdrop/background. A later
       inner bar (same z-index:50) could then paint ON TOP of the site header's
       Writing-AI dropdown, bleeding through the open menu. `body > header`
       matches the site header exactly (it's always a direct child of <body>,
       same convention already used by body>header rules elsewhere). */
    body > header{
      position:sticky; top:0; z-index:50;
      backdrop-filter:blur(18px) saturate(140%);
      -webkit-backdrop-filter:blur(18px) saturate(140%);
      background:var(--header-bg);
      border-bottom:1px solid var(--glass-line);
      transition:background .3s, border-color .3s;
    }
    .nav{ display:flex; align-items:center; justify-content:space-between; padding:14px 0; gap:22px; }
    .logo{
      font-family:'Bricolage Grotesque', 'Native Emoji', sans-serif; font-weight:800; font-size:22px;
      letter-spacing:-0.5px; display:flex; align-items:center; gap:11px; white-space:nowrap;
      text-decoration:none; color:var(--text);
      transition:opacity .15s;
    }
    .logo:hover{ opacity:.85; }
    .logo .mark{
      width:34px; height:34px; border-radius:10px;
      background:linear-gradient(135deg,var(--lime),var(--cyan));
      display:grid; place-items:center; color:var(--on-lime); font-weight:800; font-size:18px;
      box-shadow:
        0 8px 20px -6px rgba(198,242,78,0.45),
        inset 0 1px 0 rgba(255,255,255,.30),
        inset 0 -1px 0 rgba(0,0,0,.10);
      position:relative;
    }
    .logo .mark::before{
      content:""; position:absolute; inset:1px; border-radius:9px;
      background:linear-gradient(180deg, rgba(255,255,255,.22), transparent 55%);
      pointer-events:none;
    }
    .logo b{ color:var(--lime); }

    .menu{
      display:flex; align-items:center; gap:2px;
      background:var(--glass); border:1px solid var(--glass-line);
      padding:5px; border-radius:14px;
    }
    .menu a, .menu .drop-trigger{
      color:var(--muted); text-decoration:none; font-weight:600; font-size:14px;
      padding:8px 13px; border-radius:10px; transition:color .2s, background .2s;
      display:inline-flex; align-items:center; gap:6px; white-space:nowrap;
    }
    .menu a:hover, .menu .drop-trigger:hover{ color:var(--text); background:var(--glass); }
    .menu a.active,
    .menu .drop-trigger.active{
      color:var(--text);
      background:
        linear-gradient(135deg, rgba(198,242,78,0.10), rgba(139,109,255,0.08)),
        var(--bg-soft);
      box-shadow:
        inset 0 0 0 1px rgba(198,242,78,0.32),
        0 0 0 1px rgba(198,242,78,0.10),
        0 6px 22px -8px rgba(198,242,78,0.45);
    }
    :root[data-theme="light"] .menu a.active,
    :root[data-theme="light"] .menu .drop-trigger.active{
      background:
        linear-gradient(135deg, rgba(101,163,13,0.10), rgba(109,40,217,0.08)),
        var(--bg-soft);
      box-shadow:
        inset 0 0 0 1px rgba(101,163,13,0.40),
        0 0 0 1px rgba(101,163,13,0.12),
        0 6px 18px -8px rgba(101,163,13,0.40);
    }

    /* "Soon" features: tinted violet so they read as future, with a hover tooltip */
    .menu a.soon-item{ color:#b9aaff; position:relative; }
    .menu a.soon-item:hover{ color:#fff; background:rgba(139,109,255,.14); }
    .menu a.soon-item::after{
      content:attr(data-tip); position:absolute; top:118%; left:50%;
      transform:translateX(-50%) translateY(4px);
      background:var(--violet); color:#fff; font-size:11px; font-weight:700;
      padding:5px 10px; border-radius:8px; white-space:nowrap;
      opacity:0; pointer-events:none; transition:opacity .2s, transform .2s;
    }
    .menu a.soon-item:hover::after{ opacity:1; transform:translateX(-50%) translateY(0); }

    /* ---- Writing AI dropdown ---- */
    .dropdown{ position:relative; }
    .drop-trigger{
      color:#b9aaff; text-decoration:none; font-weight:600; font-size:14.5px;
      padding:8px 12px; border-radius:10px; cursor:pointer; display:inline-flex; align-items:center; gap:6px;
      transition:color .2s, background .2s; white-space:nowrap;
      background:none; border:none; font-family:inherit;
    }
    .dropdown:hover .drop-trigger,
    .dropdown[data-open="true"] .drop-trigger{ color:#fff; background:rgba(139,109,255,.14); }
    .drop-trigger .caret{ font-size:10px; transition:transform .25s; }
    .dropdown:hover .caret,
    .dropdown[data-open="true"] .caret{ transform:rotate(180deg); }
    /* ===== Premium Writing-AI mega-menu =====================================
       Gradient-hairline glass panel, per-item accent icon chips (no raw emoji),
       a labelled header, status badges and a trailing chevron that slides in.
       Accents live on each .dm-item via [data-ic] so both themes stay crisp. */
    .drop-menu{
      --dm-panel:rgba(15,17,25,.94);
      position:absolute; top:calc(100% + 13px); right:0; width:344px;
      padding:10px; border:1px solid transparent; border-radius:20px;
      background:
        linear-gradient(var(--dm-panel), var(--dm-panel)) padding-box,
        linear-gradient(135deg, rgba(198,242,78,.55), rgba(139,109,255,.42) 48%, rgba(78,224,242,.55)) border-box;
      -webkit-backdrop-filter:blur(22px) saturate(1.4); backdrop-filter:blur(22px) saturate(1.4);
      box-shadow:
        0 34px 80px -30px rgba(0,0,0,.9),
        0 6px 20px -10px rgba(0,0,0,.55),
        inset 0 1px 0 rgba(255,255,255,.07);
      opacity:0; transform:translateY(12px) scale(.97); transform-origin:top right; pointer-events:none;
      transition:opacity .26s cubic-bezier(.2,.8,.2,1), transform .32s cubic-bezier(.2,.8,.2,1); z-index:70;
    }
    /* little notch that ties the panel to its trigger */
    .drop-menu::before{
      content:""; position:absolute; top:-6px; right:30px; width:12px; height:12px;
      background:var(--dm-panel); border-radius:3px 0 0 0;
      border-left:1px solid rgba(198,242,78,.5); border-top:1px solid rgba(139,109,255,.42);
    }
    .dropdown:hover .drop-menu,
    .dropdown[data-open="true"] .drop-menu{ opacity:1; transform:translateY(0) scale(1); pointer-events:auto; }

    .dm-head{ display:flex; flex-direction:column; gap:1px; padding:6px 12px 11px; margin-bottom:5px;
      border-bottom:1px solid var(--glass-line); }
    .dm-head-eyebrow{ font-size:10px; font-weight:800; letter-spacing:1.8px; text-transform:uppercase;
      background:linear-gradient(90deg,var(--lime),var(--cyan)); -webkit-background-clip:text; background-clip:text;
      -webkit-text-fill-color:transparent; }
    .dm-head-label{ font-size:11.5px; font-weight:500; color:var(--muted); }

    /* per-item accent pair (dark theme). Every row needs one: with --a unset
       `color:var(--a)` falls back to the body text colour and the tile tint
       resolves to transparent, so the icon renders as a flat near-black glyph
       with no plate behind it — which is how the flagship row used to look. */
    .dm-item[data-ic="practice"] { --a:#8b6dff; --b:#4ee0f2; }
    .dm-item[data-ic="sprint"]   { --a:#fbbf24; --b:#fb8a3c; }
    .dm-item[data-ic="samples"] { --a:#c6f24e; --b:#4ee0f2; }
    .dm-item[data-ic="check"]   { --a:#fbbf24; --b:#fb8a3c; }
    .dm-item[data-ic="topics"]  { --a:#8b6dff; --b:#4e9af2; }
    .dm-item[data-ic="guides"]  { --a:#4ee0f2; --b:#4e9af2; }
    .dm-item[data-ic="feedback"]{ --a:#a78bfa; --b:#ff5a8a; }

    .dm-item{
      display:flex; align-items:center; gap:13px; padding:10px 11px; border-radius:14px;
      text-decoration:none; position:relative; overflow:hidden;
      opacity:0; transform:translateY(8px);
      transition:opacity .4s ease, transform .45s cubic-bezier(.2,.8,.2,1);
    }
    .dropdown:hover .dm-item,
    .dropdown[data-open="true"] .dm-item{ opacity:1; transform:none;
      transition-delay:calc(var(--i,0) * .055s + .05s); }
    /* accent wash that fades in on hover */
    .dm-item::before{
      content:""; position:absolute; inset:0; border-radius:inherit; opacity:0;
      background:linear-gradient(90deg, color-mix(in srgb, var(--a) 16%, transparent), transparent 78%);
      transition:opacity .25s ease;
    }
    .dm-item:hover::before{ opacity:1; }
    /* flagship row keeps a faint permanent tint */
    .dm-feature{ background:linear-gradient(90deg, color-mix(in srgb, var(--a) 9%, transparent), transparent 72%); }

    .dm-ic{
      flex:0 0 auto; width:40px; height:40px; border-radius:12px; display:grid; place-items:center;
      color:var(--a); position:relative; z-index:1;
      background:color-mix(in srgb, var(--a) 15%, transparent);
      box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--a) 24%, transparent);
      transition:transform .3s cubic-bezier(.34,1.56,.64,1), box-shadow .3s ease, background .3s ease, color .2s ease;
    }
    .dm-ic svg{ width:20px; height:20px; }

    /* The flagship row writes itself: the nib rocks into its stroke while the
       ink underneath draws left to right — the same swoosh that sits under
       "exam day" on the page this opens. Runs once when the menu opens, and
       again on hover, so the row is alive before the pointer ever reaches it.
       19 ≈ the path's own length (18.3) — pad it much further and the stroke
       spends the first third of the animation still off-screen.
       DRAWN is the resting state: hiding the stroke until the animation runs
       left the row as nothing but a thin nib for the first second the menu was
       open, which is exactly when you look at it. The keyframe starts it hidden
       and hands it back, so it still writes itself but can never be the reason
       the icon isn't there. */
    .dm-item[data-ic="practice"] .dm-ink{
      stroke-dasharray:19; stroke-dashoffset:0;
    }
    .dm-item[data-ic="practice"] .dm-nib{
      transform-box:fill-box; transform-origin:12% 88%;
      transition:transform .35s cubic-bezier(.34,1.56,.64,1);
    }
    .dropdown:hover .dm-item[data-ic="practice"] .dm-ink,
    .dropdown[data-open="true"] .dm-item[data-ic="practice"] .dm-ink{
      animation:dmInk .75s cubic-bezier(.4,0,.2,1) .34s;
    }
    .dm-item[data-ic="practice"]:hover .dm-nib{ transform:rotate(-11deg) translate(-.6px,-.6px); }
    @keyframes dmInk{ from{ stroke-dashoffset:19 } to{ stroke-dashoffset:0 } }
    .dm-item:hover .dm-ic{
      color:#0a0b10; background:linear-gradient(135deg,var(--a),var(--b));
      box-shadow:0 10px 22px -8px color-mix(in srgb, var(--a) 65%, transparent), inset 0 1px 0 rgba(255,255,255,.4);
      transform:translateY(-2px) scale(1.05) rotate(-3deg);
    }

    .dm-tx{ display:flex; flex-direction:column; gap:1px; min-width:0; position:relative; z-index:1; }
    .dm-t{ display:flex; align-items:center; gap:7px; font-size:14px; font-weight:700; letter-spacing:-.1px; color:var(--text); }
    /* the nav sets white-space:nowrap, which cascades here — a long description
       would then overflow the fixed-width panel and make its row wider than the
       others. Let descriptions wrap so every item stays the panel's width. */
    .dm-d{ font-size:11.5px; font-weight:500; color:var(--muted); white-space:normal; line-height:1.35; }

    .dm-go{ width:17px; height:17px; margin-left:auto; flex:0 0 auto; color:var(--muted);
      opacity:0; transform:translateX(-7px); position:relative; z-index:1;
      transition:opacity .25s ease, transform .25s ease, color .2s ease; }
    .dm-item:hover .dm-go{ opacity:1; transform:translateX(0); color:var(--a); }

    .dm-badge{ font-size:9px; font-weight:800; letter-spacing:.6px; text-transform:uppercase;
      padding:2px 6px; border-radius:6px; line-height:1.45; }
    .dm-badge.live{ color:#08110a; background:linear-gradient(135deg,var(--lime),var(--cyan));
      box-shadow:0 2px 10px -3px color-mix(in srgb, var(--lime) 70%, transparent); }
    .dm-badge.soon-b{ color:#fff; background:linear-gradient(135deg,#8b6dff,#6d28d9); }

    /* ---- light theme: white panel, deeper accents so chips read on white ---- */
    :root[data-theme="light"] .drop-menu{
      --dm-panel:#ffffff;
      background:
        linear-gradient(#fff,#fff) padding-box,
        linear-gradient(135deg, rgba(101,163,13,.4), rgba(109,40,217,.32) 48%, rgba(8,145,178,.4)) border-box;
      box-shadow:
        0 34px 70px -30px rgba(30,40,80,.3),
        0 6px 18px -10px rgba(30,40,80,.16),
        inset 0 1px 0 rgba(255,255,255,.7);
    }
    :root[data-theme="light"] .drop-menu::before{
      border-left-color:rgba(101,163,13,.4); border-top-color:rgba(109,40,217,.3);
    }
    :root[data-theme="light"] .dm-item[data-ic="practice"] { --a:#6d28d9; --b:#0891b2; }
    :root[data-theme="light"] .dm-item[data-ic="sprint"]   { --a:#d97706; --b:#ea580c; }
    :root[data-theme="light"] .dm-item[data-ic="samples"] { --a:#65a30d; --b:#0891b2; }
    :root[data-theme="light"] .dm-item[data-ic="check"]   { --a:#d97706; --b:#ea580c; }
    :root[data-theme="light"] .dm-item[data-ic="topics"]  { --a:#6d28d9; --b:#2563eb; }
    :root[data-theme="light"] .dm-item[data-ic="guides"]  { --a:#0891b2; --b:#2563eb; }
    :root[data-theme="light"] .dm-item[data-ic="feedback"]{ --a:#7c3aed; --b:#db2777; }
    :root[data-theme="light"] .dm-item:hover .dm-ic{ color:#fff; }
    :root[data-theme="light"] .dm-badge.live{ color:#fff; background:linear-gradient(135deg,#65a30d,#0891b2); }

    @media (prefers-reduced-motion: reduce){
      .drop-menu, .dm-item, .dm-ic, .dm-go{ transition-duration:.001s !important; }
      .dm-item{ transition-delay:0s !important; }
      /* the ink still has to end up drawn — it is the icon, not decoration */
      .dm-item[data-ic="practice"] .dm-ink{ stroke-dashoffset:0; animation:none !important; }
      .dm-item[data-ic="practice"] .dm-nib{ transition:none !important; }
    }

    /* ---- scroll-reveal: elements fade up as they enter the screen ----
       The base state MUST be visible. This used to be `opacity:0` with `.in`
       (added by JS) as the only way back to visible — which means ANY failure to
       run that JS strands EVERY [data-reveal] element invisible, and since this
       selector is global that renders as a completely blank page with only the
       background showing. A hung/slow module, an IntersectionObserver that never
       fires, or a JS error was enough to do it.
       The entrance is now opt-IN: nothing is hidden by default, and `.in` merely
       PLAYS an animation whose hidden start lives in the keyframes (`both` keeps
       the end state). Worst case the animation never plays and the content is
       simply there — never a blank screen. */
    [data-reveal]{ opacity:1; transform:none; }
    [data-reveal].in{ animation:revealRise .7s cubic-bezier(.2,.7,.2,1) both; }
    @keyframes revealRise{ from{ opacity:0; transform:translateY(26px); } to{ opacity:1; transform:none; } }
    @media (prefers-reduced-motion: reduce){ [data-reveal].in{ animation:none; } }

    /* ---- richer hover micro-animations ---- */
    .logo .mark{ transition:transform .3s ease; }
    .logo:hover .mark{ transform:rotate(8deg) scale(1.08); }
    /* sheen sweep across the primary button on hover */
    .btn-primary{ position:relative; overflow:hidden; }
    .btn-primary::after{
      content:""; position:absolute; top:0; left:-120%; width:60%; height:100%;
      background:linear-gradient(120deg,transparent,rgba(255,255,255,.5),transparent);
      transform:skewX(-20deg); transition:left .55s ease;
    }
    .btn-primary:hover::after{ left:140%; }
    .soon{
      font-size:9.5px; font-weight:700; letter-spacing:.5px; text-transform:uppercase;
      background:var(--violet); color:#fff; padding:2px 6px; border-radius:6px;
    }

    .actions{ display:flex; align-items:center; gap:8px; }

    /* ---- icon-button (theme toggle, etc.) ---- */
    .icon-btn{
      width:40px; height:40px; border-radius:12px;
      background:var(--glass); border:1px solid var(--glass-line); color:var(--text);
      cursor:pointer; display:inline-grid; place-items:center;
      transition:background .25s, transform .15s, border-color .25s, color .25s;
      position:relative; overflow:hidden;
    }
    .icon-btn:hover{ background:var(--bg-soft); border-color:var(--glass-line); transform:translateY(-1px); }
    .icon-btn svg{ width:18px; height:18px; }
    /* Theme toggle: both icons overlap in the same cell, opacity + rotation cross-fade */
    .theme-toggle{ position:relative; }
    .theme-toggle .ico-sun, .theme-toggle .ico-moon{
      position:absolute; inset:0; margin:auto;
      transition:opacity .35s ease, transform .45s cubic-bezier(.34,1.56,.64,1);
    }
    /* dark theme: moon visible, sun hidden (rotated out) */
    .theme-toggle .ico-moon{ opacity:1; transform:rotate(0)   scale(1); }
    .theme-toggle .ico-sun { opacity:0; transform:rotate(90deg) scale(.4); }
    /* light theme: swap */
    :root[data-theme="light"] .theme-toggle .ico-moon{ opacity:0; transform:rotate(-90deg) scale(.4); }
    :root[data-theme="light"] .theme-toggle .ico-sun { opacity:1; transform:rotate(0)     scale(1); color:#f59e0b; }
    .theme-toggle:hover{ color:var(--lime); }

    /* ---- header Profile button (signed-in only) ----
       Inherits .icon-btn, so it is the same 40px round control as the theme
       toggle beside it — nothing new to lay out, and no animation of any kind:
       colour on hover is the whole effect, so it costs the compositor nothing
       and can never contribute to the idle repaint problem the rest of this
       stylesheet was just cleaned up for.

       [hidden] needs the !important. .icon-btn sets `display:inline-grid`, and a
       class selector beats the UA stylesheet's `[hidden]{display:none}` — so
       without this the button would sit in the header for signed-OUT visitors
       too, linking them to a page they cannot open. */
    .profile-go[hidden]{ display:none !important; }
    .profile-go:hover{ color:var(--cyan); border-color:rgba(var(--ca),.45); }
    /* On /profile the button reads as the current page rather than a way to it. */
    .profile-go.is-here{
      color:var(--cyan);
      background:rgba(var(--ca),.12);
      border-color:rgba(var(--ca),.45);
    }

    /* ===== Premium day/night orb (header theme toggle) =======================
       A miniature sky inside the 40px button: sun & moon slide vertically past
       each other, the sun's rays turn, stars twinkle at night, and the sky
       gradient shifts dawn↔dusk. Uses its own .tt-* classes so the admin/exam
       toggles (which keep .ico-sun/.ico-moon) are untouched. Reacts to
       :root[data-theme]; no JS beyond the shared [data-theme-toggle] flip. */
    .theme-toggle:has(.tt-sky){ overflow:hidden; padding:0; border-color:var(--glass-line); }
    .tt-sky{
      position:absolute; inset:0; border-radius:inherit; overflow:hidden;
      background:linear-gradient(165deg,#2b2a63 0%,#0b1020 100%);      /* night (default) */
      transition:background .6s ease;
    }
    :root[data-theme="light"] .tt-sky{
      background:linear-gradient(165deg,#bfe6ff 0%,#ffe6a3 100%);      /* dawn */
    }
    .tt-sun, .tt-moon{
      position:absolute; inset:0; display:grid; place-items:center;
      transition:transform .6s cubic-bezier(.5,1.5,.5,1), opacity .45s ease;
    }
    .tt-sun svg, .tt-moon svg{ width:19px; height:19px; }
    .tt-sun{ color:#f9b233; filter:drop-shadow(0 0 6px rgba(249,178,51,.75)); }
    .tt-moon{ color:#eaf0ff; filter:drop-shadow(0 0 5px rgba(190,205,255,.6)); }
    .tt-sun svg{ animation:ttSpin 16s linear infinite; }
    @keyframes ttSpin{ to{ transform:rotate(360deg); } }
    /* default = night: moon centred, sun tucked above */
    .tt-sun{ transform:translateY(-140%); opacity:0; }
    .tt-moon{ transform:translateY(0); opacity:1; }
    /* light = day: sun centred, moon dropped below */
    :root[data-theme="light"] .tt-sun{ transform:translateY(0); opacity:1; }
    :root[data-theme="light"] .tt-moon{ transform:translateY(140%); opacity:0; }
    .tt-star{
      position:absolute; left:var(--x); top:var(--y); width:2px; height:2px; border-radius:50%;
      background:#fff; box-shadow:0 0 4px #fff; opacity:.3;
      animation:ttTwinkle 2.6s ease-in-out infinite; animation-delay:var(--d);
    }
    @keyframes ttTwinkle{ 0%,100%{ opacity:.25; } 50%{ opacity:1; } }
    :root[data-theme="light"] .tt-star{ opacity:0 !important; animation:none; }
    .theme-toggle:has(.tt-sky):hover{ box-shadow:0 8px 20px -6px rgba(139,109,255,.5); transform:translateY(-1px); }
    :root[data-theme="light"] .theme-toggle:has(.tt-sky):hover{ box-shadow:0 8px 20px -6px rgba(249,178,51,.55); }
    @media (prefers-reduced-motion: reduce){
      .tt-sun svg{ animation:none; }
      .tt-star{ animation:none; opacity:.7; }
      .tt-sun, .tt-moon, .tt-sky{ transition-duration:.001s; }
    }

    /* Admin top bar version: uses the warm admin border/background */
    .adm-theme-toggle{
      background:transparent; border:1px solid var(--adm-border); color:var(--adm-muted);
    }
    .adm-theme-toggle:hover{ color:var(--adm-accent); border-color:var(--adm-border-hi); background:rgba(255,120,73,.06); }
    :root[data-theme="light"] .adm-theme-toggle .ico-sun{ color:#ea580c; }

    /* ---- user chip (replaces the long "Log out (...)" button) ---- */
    .user-chip{
      display:none; align-items:center; gap:8px;
      /* Lets the name's ellipsis actually engage: the shrink has to travel
         .actions → .user-wrap → here → .user-chip-name, and any link in that
         chain keeping its default min-width:auto stops it dead. */
      /* 68px = avatar + caret + padding, i.e. the chip with no name at all.
         Without the floor the box itself kept shrinking past its own children
         and the 30px avatar spilled out of a 19px pill. Flooring here turns the
         worst case into a deliberate avatar-only chip instead. */
      min-width:68px; max-width:100%;
      padding:5px 12px 5px 5px; border-radius:99px;
      background:var(--glass); border:1px solid var(--glass-line); cursor:pointer;
      transition:background .2s, border-color .2s;
    }
    /* Floor. The name is the ONLY part allowed to give ground; the avatar and
       caret keep their size, so the worst case degrades to a neat avatar-only
       chip instead of a 19px sliver with the avatar itself squashed (which is
       what an admin with a long name got, since that row also carries the
       Admin-panel pill). */
    .user-chip > *{ flex-shrink:0; }
    .user-chip .user-chip-name{ flex-shrink:1; }
    .user-chip.show{ display:inline-flex; }
    .user-chip:hover{ background:var(--bg-soft); border-color:var(--glass-line); }
    .user-avatar{
      width:30px; height:30px; border-radius:50%;
      background:linear-gradient(135deg, var(--violet), var(--cyan));
      display:grid; place-items:center; color:#fff; font-weight:800; font-size:12.5px;
      letter-spacing:-.5px; text-transform:uppercase;
      flex-shrink:0;
    }
    .user-avatar.admin{ background:linear-gradient(135deg, #ff7849, #fbbf24); color:#14080d; }
    /* A name is USER DATA. Telegram allows far more of it than this row can
       spend, and without a cap the chip grew without limit and pushed the
       primary menu into its clip — so the header's layout depended on how long
       the signed-in user's name happened to be ("IELTS BANDLY SUPPORT" clipped
       the Quiz link off the nav; "Abdulloh" did not). Bounded here, and
       shrinkable via the flex chain in 13-responsive.css, so the row now looks
       the same whoever is signed in. `min-width:0` is load-bearing: a flex item
       will not shrink below its content without it, which is what made the
       ellipsis impossible in the first place. */
    .user-chip-name{
      font-weight:700; font-size:13.5px; color:var(--text);
      max-width:140px; min-width:0;
      white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
    }
    .user-chip-caret{ font-size:9px; color:var(--muted); margin-left:-2px; }

    /* user dropdown menu */
    .user-menu{
      position:absolute; top:calc(100% + 10px); right:0;
      min-width:240px;
      background:var(--bg-soft); border:1px solid var(--glass-line); border-radius:14px;
      padding:6px; box-shadow:var(--shadow-lg);
      opacity:0; transform:translateY(8px); pointer-events:none;
      transition:opacity .2s, transform .2s; z-index:80;
    }
    .user-wrap{ position:relative; }
    .user-wrap.open .user-menu{ opacity:1; transform:translateY(0); pointer-events:auto; }
    .user-menu-head{
      padding:11px 14px 12px; border-bottom:1px solid var(--glass-line); margin-bottom:5px;
    }
    .user-menu-name{ font-weight:700; font-size:14.5px; color:var(--text); }
    .user-menu-id{ font-size:12px; color:var(--muted); margin-top:1px; }
    .user-menu-badge{
      display:inline-block; margin-top:7px; padding:2px 8px; border-radius:6px;
      font-size:10px; font-weight:800; letter-spacing:.5px; text-transform:uppercase;
      background:linear-gradient(135deg, #ff7849, #fbbf24); color:#14080d;
    }
    /* The base display:inline-block above defeats the UA [hidden] rule, so
       updateAuthUI()'s `badge.hidden = !isAdmin` never actually hid the pill —
       that's what showed ADMIN to every logged-in account. Make [hidden] win. */
    .user-menu-badge[hidden]{ display:none !important; }
    .user-menu a, .user-menu button{
      display:flex; align-items:center; gap:10px;
      padding:9px 13px; border-radius:9px; cursor:pointer;
      background:transparent; border:none; width:100%; text-align:left;
      color:var(--text); font-weight:600; font-size:13.5px; text-decoration:none;
      font-family:'Hanken Grotesk', 'Native Emoji', sans-serif;
      transition:background .15s;
    }
    .user-menu a:hover, .user-menu button:hover{ background:var(--glass); }
    .user-menu .ico{ width:18px; height:18px; opacity:.7; flex-shrink:0; }
    .user-menu .danger{ color:#fb7185; }
    .user-menu .danger:hover{ background:rgba(251,113,133,.10); }

    /* (The definition-language picker was moved out of the account menu — it now
       lives as language pills inside the word popup itself.) */

    /* ---- Floating Action Button: persistent admin ↔ site switcher ----
       Bottom-right, always reachable while scrolling. Toggles based on whether
       admin is currently active. */
    .admin-fab{
      position:fixed; bottom:24px; right:24px; z-index:60;
      display:none; align-items:center; gap:9px;
      padding:12px 20px; border-radius:99px;
      background:linear-gradient(135deg, #ff7849, #fbbf24);
      color:#14080d; font-weight:800; font-size:14.5px;
      border:none; cursor:pointer; text-decoration:none;
      font-family:'Hanken Grotesk', 'Native Emoji', sans-serif; white-space:nowrap;
      box-shadow:0 14px 36px -10px rgba(255,120,73,.55),
                 0 0 0 4px rgba(255,255,255,.03),
                 inset 0 1px 0 rgba(255,255,255,.18);
      transition:transform .2s ease, box-shadow .2s, filter .15s;
      animation:fabIn .4s ease backwards;
    }
    .admin-fab.show{ display:inline-flex; }
    /* Walled-off admin: when inside /admin/* we don't offer a "go to site" shortcut.
       The admin must log out (or open a new tab) to view the public site. */
    body.admin-mode .admin-fab{ display:none !important; }
    .admin-fab:hover{ transform:translateY(-3px); filter:brightness(1.06); box-shadow:0 20px 44px -10px rgba(255,120,73,.7), inset 0 1px 0 rgba(255,255,255,.18); }
    .admin-fab:active{ transform:translateY(-1px); }
    .admin-fab svg{ width:18px; height:18px; }
    .admin-fab .fab-arrow{ width:0; height:0; overflow:hidden; opacity:0; transition:width .25s, opacity .25s; margin-left:-9px; }
    .admin-fab:hover .fab-arrow{ width:18px; opacity:1; margin-left:0; }
    /* Gentle attention pulse so admins notice it the first time */
    .admin-fab::before{
      content:""; position:absolute; inset:-2px; border-radius:99px;
      background:linear-gradient(135deg, #ff7849, #fbbf24);
      opacity:.35; z-index:-1; filter:blur(8px);
      animation:fabPulse 2.6s ease-in-out infinite;
    }
    @keyframes fabPulse{ 0%,100%{ opacity:.25; transform:scale(1); } 50%{ opacity:.5; transform:scale(1.04); } }
    @keyframes fabIn   { from{ transform:translateY(24px); opacity:0; } to{ transform:none; opacity:1; } }
    /* When on admin page, the FAB flips to "back to site" with a calmer style */
    body.admin-mode .admin-fab{
      background:rgba(255,255,255,.05);
      color:var(--adm-text);
      border:1px solid var(--adm-border);
      box-shadow:0 10px 30px -10px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.06);
    }
    body.admin-mode .admin-fab::before{ display:none; }
    body.admin-mode .admin-fab:hover{ border-color:var(--adm-border-hi); background:rgba(255,255,255,.08); }

    @media (max-width:680px){
      .admin-fab{ bottom:16px; right:16px; padding:11px 18px; font-size:13.5px; }
    }
    @media (max-width:420px){
      .admin-fab .fab-label{ display:none; }
      .admin-fab{ padding:13px; }
    }

    /* Prominent "Admin" pill in the header — shown only when admin is logged in */
    .admin-go{
      display:none; align-items:center; gap:6px;
      padding:7px 14px; border-radius:99px;
      background:linear-gradient(135deg, #ff7849, #fbbf24);
      color:#14080d; font-weight:800; font-size:13px;
      text-decoration:none; cursor:pointer; border:none; white-space:nowrap;
      font-family:'Hanken Grotesk', 'Native Emoji', sans-serif;
      transition:transform .15s, box-shadow .2s, filter .15s;
      box-shadow:0 4px 14px -4px rgba(255,120,73,.5);
    }
    .admin-go.show{ display:inline-flex; }
    .admin-go:hover{ transform:translateY(-1px); filter:brightness(1.06); box-shadow:0 8px 22px -6px rgba(255,120,73,.65); }
    .admin-go svg{ width:14px; height:14px; }
    .btn{
      font-family:'Hanken Grotesk', 'Native Emoji', sans-serif; font-weight:700; font-size:14.5px;
      padding:10px 18px; border-radius:11px; cursor:pointer; border:none;
      transition:transform .15s, box-shadow .2s, background .2s; white-space:nowrap;
      /* .btn is worn by <button> AND by ~55 <a> elements across the site. Nothing
         here ever reset the anchor's UA underline, so every link-shaped button
         (Message @handle, View my profile, …) rendered with a stripe under the
         label — it read as a link wearing a button rather than a button. */
      text-decoration:none;
    }
    .btn-ghost{ background:transparent; color:var(--text); border:1px solid var(--glass-line); }
    .btn-ghost:hover{ background:var(--glass); }
    /* Ink follows the accent. Hardcoding #0a0b10 broke on pages that re-theme
       --lime (e.g. #profile-page swaps it for indigo), leaving dark-on-dark. */
    .btn-primary{ background:var(--lime); color:var(--on-lime, #0a0b10); }
    .btn-primary:hover{ transform:translateY(-1px); box-shadow:0 8px 26px -8px rgba(198,242,78,.6); }

    /* The hamburger and the mobile drawer it opens both live in
       css/parts/core/36-mobile-nav.css — they grew past what belongs inline in
       the header sheet (full-height sheet, grouped icon rows, stagger, morphing
       burger). 13-responsive.css still owns the breakpoint that shows them. */

