/* =========================================================
   DebateIt — shared UI primitives
   Source of truth for colors, typography, and component styles
   used across landing, high-school, debate-ai, learn.
   Mirrors the main app (app/index.html) aesthetic so every page
   reads as the same product.
   ========================================================= */


/* No decorative italics site-wide. The Crimson Pro/Fraunces italic flourishes
   (red emphasis words, italic nav, slanted pull-quotes) read as
   inconsistent against the upright brand face. Emphasis is weight +
   color, not slant. Neutralizes bare <em>/<i> defaults; explicit
   per-page italic rules were converted to upright in the same pass.
   (2026-06-15) */
em, i { font-style: normal; }

/* ── Tokens — three canonical themes: GREY (dark, default) /
   CRIMSON (red on black) / LIGHT (warm off-white).
   Source of truth lives here; landing.html mirrors the same palette so
   every page reads as one product. Selectors support both conventions:
   landing uses `[data-theme="X"]` on <html>, the older /app + /high-school
   code uses `body.X-theme`. Keeping both lets us migrate page-by-page
   without breaking either side.
   2026-05-10: dropped the bare `body` selector from this default block.
   It was unconditionally setting GREY tokens on every <body>, which
   shadowed `[data-theme="light"]` / `[data-theme="crimson"]` set on
   <html> (body's own scope wins inside body's subtree). Result: light
   theme was rendering dark backdrops with light-theme text colors —
   nearly-black `.tier-name` on a `#111` bg on /pricing, etc. The
   legacy `body.crimson-theme` / `body.light-theme` selectors below
   still work; they each set their OWN tokens explicitly. */
:root,
[data-theme="grey"]{
  --bg:#111;
  --bg-card:rgba(255,255,255,.03);
  --bg-elev:rgba(20,20,24,.55);
  /* Opaque elevation for dropdowns/sheets that float over page content.
     --bg-elev is translucent by design (topbar frosted glass), but a
     descendant of the blurred topbar can't backdrop-blur the page behind
     it (ancestor backdrop root), so menus using --bg-elev let text bleed
     through. Menus use this solid token instead. (2026-07-19) */
  --bg-elev-solid:#17171b;
  --border:rgba(255,255,255,.08);
  --border-strong:rgba(255,255,255,.18);
  --text:#fff;
  --text-dim:rgba(255,255,255,.68);
  --text-ghost:rgba(255,255,255,.38);
  --accent:#ef4444;
  --accent-hover:#f87171;
  --accent-soft:rgba(239,68,68,.08);
  --accent-border:rgba(239,68,68,.25);
  --accent-glow:rgba(200,30,30,.35);
  --accent-glow2:rgba(80,20,20,.25);
  /* Radius scale bumped up to feel less boxy. Old values felt sharp-cornered
     on cards / form rows; new values lean toward "soft / circular" without
     going full pill. Pages that want a rounder vibe should use --radius-lg
     or --radius-xl. */
  --radius-sm:10px;
  --radius:14px;
  --radius-lg:22px;
  --radius-xl:30px;
  --radius-pill:999px;
  --shadow-sm:0 2px 10px rgba(0,0,0,.2);
  --shadow:0 6px 18px rgba(0,0,0,.35);
  --shadow-lg:0 20px 60px rgba(0,0,0,.45);
  --ease:cubic-bezier(.2,.65,.3,.9);
}
[data-theme="light"],
body.light-theme{
  /* Warm off-white instead of pure white so it doesn't glare on retina
     displays; deeper red (#dc2626) reads as a confident link/CTA on
     light backgrounds rather than looking radioactive. Mirrors the
     landing-page light theme exactly. */
  --bg:#fafaf7;
  --bg-card:rgba(0,0,0,.03);
  --bg-elev:rgba(255,255,255,.8);
  --bg-elev-solid:#ffffff;
  --border:rgba(0,0,0,.08);
  --border-strong:rgba(0,0,0,.18);
  --text:#1a1a1f;
  --text-dim:rgba(0,0,0,.68);
  --text-ghost:rgba(0,0,0,.42);
  --accent:#dc2626;
  --accent-hover:#b91c1c;
  --accent-soft:rgba(220,38,38,.08);
  --accent-border:rgba(220,38,38,.25);
  --accent-glow:rgba(220,38,38,.18);
  --accent-glow2:rgba(220,38,38,.10);
}
[data-theme="crimson"],
body.crimson-theme{
  --bg:#000;
  --bg-card:rgba(255,40,40,.03);
  --bg-elev:rgba(30,10,10,.55);
  --bg-elev-solid:#1a0a0a;
  --border:rgba(239,68,68,.12);
  --border-strong:rgba(239,68,68,.28);
  --text:#fff;
  --text-dim:rgba(255,255,255,.68);
  --text-ghost:rgba(239,68,68,.42);
  --accent:#ef4444;
  --accent-hover:#f87171;
  --accent-soft:rgba(239,68,68,.08);
  --accent-border:rgba(239,68,68,.3);
  --accent-glow:rgba(239,68,68,.4);
  --accent-glow2:rgba(239,68,68,.2);
}

/* ── Base ─────────────────────────────────────────────────── */
*{box-sizing:border-box}
/* html background tracks the theme so the cross-page fade
   (page-transition.js drops body to opacity:0) never flashes white
   between a dark and a light page. (2026-06-15) */
html{scroll-behavior:smooth;background:var(--bg);transition:background .4s}
body{
  margin:0;
  /* Crimson Pro is the house face site-wide. Fraunces + Georgia stay
     as the serif fallback chain. (switched from Geist 2026-06-15) */
  font-family:'Crimson Pro','Fraunces',Georgia,"Times New Roman",serif;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  background:var(--bg);color:var(--text);
  font-size:16px;line-height:1.55;
  transition:background .4s,color .4s;
}
a{color:inherit}
::selection{background:var(--accent);color:#fff}

/* ── Beta strip (fixed, top of every page) ───────────────── */
.ui-beta-strip{
  position:fixed;top:0;left:0;right:0;z-index:10000;
  padding:6px 36px 6px 14px;text-align:center;
  font-size:.72rem;color:#fff;font-weight:600;letter-spacing:.02em;
  /* Fully opaque — earlier alpha of `dd` let hero content bleed through when it scrolled under */
  background:#ef4444;
  border-bottom:1px solid #00000040;
  font-family:'Crimson Pro','Inter',system-ui,sans-serif;line-height:1.4;
  box-shadow:0 2px 8px rgba(0,0,0,.35);
}
.ui-beta-strip a{color:#fff;text-decoration:underline;font-weight:800}
.ui-beta-strip-dismiss{
  position:absolute;right:8px;top:50%;transform:translateY(-50%);
  background:transparent;border:none;color:#fff;opacity:.7;
  cursor:pointer;font-size:1rem;line-height:1;padding:4px 6px;
}
.ui-beta-strip-dismiss:hover{opacity:1}
body.has-beta-strip{padding-top:32px}

/* ── Neural constellation canvas (fixed bg) ──────────────── */
.ui-neural-canvas{
  position:fixed;top:0;left:0;width:100vw;height:100vh;
  /* z-index:0 so the constellation sits BEHIND content (which
     defaults to z-index:auto/0 but later in DOM, or explicitly
     z-index:1 in some pages). Was at 1, putting the canvas on
     top of cards/text on the Manage page and elsewhere. */
  z-index:0;pointer-events:none;opacity:.45;
  transition:opacity 1s ease;
}
body.crimson-theme .ui-neural-canvas{opacity:.8}
body.light-theme .ui-neural-canvas{opacity:.35}

/* ── Top bar ─────────────────────────────────────────────── */
.ui-topbar{
  position:fixed;top:32px;left:0;right:0;z-index:1000;
  padding:0 32px;height:52px;
  display:flex;align-items:center;justify-content:space-between;
  background:color-mix(in srgb,var(--bg) 92%,transparent);
  border-bottom:1px solid var(--border);
  /* 2026-05-27 perf: backdrop-filter dropped 16px -> 10px and the
     bg color-mix bumped 88% -> 92% so the slight visual loss from
     the smaller blur is compensated by a more opaque background.
     Chrome's gaussian-blur cost scales roughly with radius squared
     and the topbar's backdrop is re-rasterized every scroll frame.
     Visually indistinguishable on retina; meaningfully cheaper. */
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  /* Transform is not transitioned on purpose. The banner offset
     uses transform so it snaps to position on first paint instead
     of sliding in from y=0. The other listed properties retain
     their existing transitions. */
  transition:top .2s ease,background .4s,border-color .4s;
}
body:not(.has-beta-strip) .ui-topbar{top:0}
/* Push the fixed topbar down by the founding-cohort banner height
   so the banner is actually visible (cohort-banner.js inserts an
   <aside> at the top of <body> in normal flow; the topbar is fixed
   at top:0 and was covering it). Using transform instead of `top`
   because something on this page suppresses inline/!important
   `top` overrides on .ui-topbar (verified in-browser: `top:47px
   !important` computed to 0px; `transform: translateY(47px)` moved
   the bar correctly). cohort-banner.js publishes --cohort-banner-h
   on :root with the banner's offsetHeight; collapses to 0px on
   dismiss, so the topbar slides back up. */
.ui-topbar{transform:translateY(var(--cohort-banner-h,0px))}
.ui-topbar-left{display:flex;align-items:center;gap:0;flex-shrink:0}
/* 2026-05-18: .ui-topbar-beta chip CSS removed alongside the element. */
.ui-topbar-logo{
  font-size:1.4rem;font-weight:900;letter-spacing:-.02em;
  color:var(--text);cursor:pointer;white-space:nowrap;line-height:1;
  text-decoration:none;display:inline-block;
}
.ui-topbar-logo span{color:var(--accent)}
.ui-topbar-right{display:flex;align-items:center;gap:14px;flex-shrink:0}
.ui-topbar-link{
  /* 2026-07-22: px, not rem, and a step up. Pages set their own root
     size (landing runs a 20px root, most others 16px), so the shared nav
     was rendering ~14.4px on one page and ~11.5px on the next off the
     same .72rem. Chrome should be one size everywhere; 15px is legible
     without crowding the 12-item rail. */
  font-size:15px;font-weight:500;line-height:18px;
  /* Ink follows --text, which every theme/lighting block declares
     alongside the --bg that paints this bar — the two can't split.
     The old approach keyed label color on data-lighting and bar bg
     on --bg/data-theme; any out-of-sync attribute combo rendered
     dark-on-dark (the invisible-tabs bug on dark landing). */
  color:color-mix(in srgb, var(--text, #fff) 86%, transparent);letter-spacing:.04em;
  text-decoration:none;background:transparent;border:none;
  padding:0;cursor:pointer;transition:color .2s;
  font-family:inherit;white-space:nowrap;
}
.ui-topbar-link:hover{color:var(--text)}
.ui-topbar-link.accent{color:var(--accent)}
.ui-topbar-link.accent:hover{color:var(--accent-hover)}
/* Some app surfaces intentionally combine data-theme="light" with
   data-lighting="dark": content tokens stay light-mode, while the
   fixed topbar is still a dark glass strip. Keep the bar ink tied to
   the strip, not the page content token. */
[data-lighting="dark"] .ui-topbar .ui-topbar-logo,
[data-lighting="dark"] .ui-topbar .ui-topbar-link{
  color:rgba(255,255,255,.86) !important;
}
[data-lighting="dark"] .ui-topbar .ui-topbar-link:hover{color:#fff !important}
/* Same dark-strip guarantee for the two icon/pill controls that carry
   their ink from theme tokens: the ghost Sign in button and the bell.
   On surfaces that pair light content tokens with a dark bar (e.g.
   /debate-it), both rendered dark-on-dark and vanished. */
[data-lighting="dark"] .ui-topbar .ui-btn-ghost{color:rgba(255,255,255,.78) !important;border-color:rgba(255,255,255,.24) !important}
[data-lighting="dark"] .ui-topbar .ui-btn-ghost:hover{color:#fff !important;border-color:rgba(255,255,255,.5) !important}
[data-lighting="dark"] .ui-topbar .ui-bell{color:rgba(255,255,255,.72) !important;border-color:rgba(255,255,255,.2) !important}
[data-lighting="dark"] .ui-topbar .ui-bell:hover{color:#fff !important}
[data-lighting="dark"] .ui-topbar .ui-bell.has-unread{color:var(--accent,#ef4444) !important;border-color:var(--accent,#ef4444) !important}
/* Light side of the same guarantee: the bell's var(--text-dim,#9aa)
   fallback resolves to #9aa on pages whose light tokens don't define
   it, which is ~2:1 on cream. */
[data-lighting="light"] .ui-topbar .ui-bell:not(.has-unread){color:rgba(0,0,0,.62) !important;border-color:rgba(0,0,0,.16) !important}
[data-lighting="light"] .ui-topbar .ui-bell:not(.has-unread):hover{color:rgba(0,0,0,.9) !important}
.ui-topbar-pill{
  font-size:.7rem;font-weight:500;padding:4px 12px;border-radius:999px;
  border:1px solid var(--border-strong);background:var(--bg-card);
  color:color-mix(in srgb, var(--text, #fff) 86%, transparent);
  cursor:pointer;letter-spacing:.04em;
  text-decoration:none;font-family:inherit;transition:.2s;
}
.ui-topbar-pill:hover{color:var(--text);border-color:var(--text)}
@media(max-width:640px){
  /* Mobile density: 14px root so rem-based sizing scales ~87.5%, fitting more per screen */
  html{font-size:14px}
  .ui-topbar{padding:0 12px;height:46px;top:28px}
  .ui-topbar-logo{font-size:1.15rem}
  .ui-topbar-right{gap:10px}
  .ui-topbar-link{font-size:12.5px}
  /* Keep the theme picker visible on phones so light-mode users can flip
     it on the device they actually browse from (was hidden until the
     three-theme system shipped). Trim the dots a hair so they fit
     beside the CTA without crowding the logo. */
  .ui-topbar .theme-dots{padding:0 2px;gap:4px}
  .ui-topbar .theme-dot{width:12px;height:12px;border-width:1px}
  /* SFX toggle shrinks alongside the theme dots on tablet so the
     topbar doesn't crowd the CTA. */
  .ui-topbar .sfx-toggle{width:24px;height:24px;padding:0}
  .ui-topbar .sfx-toggle svg{width:12px;height:12px}
}

/* SFX mute toggle. Lives in the topbar between page links and the
   theme dots. Inline SVG speaker — strike-through line shown only
   when aria-pressed=true (muted state). Sized to match the cluster
   of theme dots beside it without dominating. Color is currentColor
   so the cascade decides (text-dim by default, text on hover, etc.).
   Defined here in ui.css instead of per-page because topbar.js
   renders to every page that uses the shared topbar; keeps the
   visual identical across surfaces. */
.ui-topbar .sfx-toggle{
  display:inline-flex;align-items:center;justify-content:center;
  width:28px;height:28px;padding:0;border-radius:999px;
  background:transparent;border:1px solid var(--border-strong, rgba(255,255,255,.18));
  color:var(--text-dim, rgba(255,255,255,.62));
  cursor:pointer;font-family:inherit;
  /* 2026-05-26: secondary controls (SFX mute + theme toggle, see
     below) default to 0.55 opacity and reveal to 1.0 on individual
     hover OR when any part of the topbar is hovered. Per Aidan's
     design brief — "auxiliary, not central" + "hide until hover."
     Keyboard focus also restores opacity so the control isn't
     hidden from accessibility tooling. */
  opacity:.55;
  transition:color .15s, background .15s, border-color .15s, opacity .2s;
  margin-right:6px;
}
.ui-topbar:hover .sfx-toggle,
.ui-topbar .sfx-toggle:hover,
.ui-topbar .sfx-toggle:focus-visible,
.ui-topbar .sfx-toggle[aria-pressed="true"]{opacity:1}
.ui-topbar .sfx-toggle:hover{
  color:var(--text, #fff);
  border-color:var(--text, #fff);
  background:rgba(255,255,255,.04);
}
[data-theme="light"] .ui-topbar .sfx-toggle{
  border-color:rgba(0,0,0,.18);
  color:rgba(0,0,0,.55);
}
[data-theme="light"] .ui-topbar .sfx-toggle:hover{
  color:#1a1a1f;border-color:#1a1a1f;background:rgba(0,0,0,.03);
}
.ui-topbar .sfx-toggle svg{width:14px;height:14px;display:block}
/* Strike line hidden in the un-muted (sound-on) state. */
.ui-topbar .sfx-toggle .sfx-strike{opacity:0;transition:opacity .15s}
/* When pressed (muted), show the strike line and dim the wave arcs
   so the icon clearly reads as "sound off." */
.ui-topbar .sfx-toggle[aria-pressed="true"]{
  color:var(--accent, #ef4444);
  border-color:var(--accent, #ef4444);
}
.ui-topbar .sfx-toggle[aria-pressed="true"] .sfx-strike{opacity:1}
.ui-topbar .sfx-toggle[aria-pressed="true"] .sfx-wave{opacity:.25}

/* Theme toggle — sun in dark themes, moon in light. Matches the
   .sfx-toggle shape (circle, 28px, 1px border, currentColor SVG)
   so the two icons read as a paired cluster in the topbar.
   The sun/moon swap is purely a CSS visibility flip keyed off
   the [data-theme] attribute on <html>; topbar.js doesn't have
   to re-render the SVG on click. */
.ui-topbar .theme-toggle{
  display:inline-flex;align-items:center;justify-content:center;
  width:28px;height:28px;padding:0;border-radius:999px;
  background:transparent;border:1px solid var(--border-strong, rgba(255,255,255,.18));
  color:var(--text-dim, rgba(255,255,255,.62));
  cursor:pointer;font-family:inherit;
  /* 2026-05-26: see .sfx-toggle above — same dim-by-default + reveal-
     on-topbar-hover treatment. Paired cluster reads as one quiet
     settings group instead of two loud individual buttons. */
  opacity:.55;
  transition:color .15s, background .15s, border-color .15s, opacity .2s;
  position:relative;
}
.ui-topbar:hover .theme-toggle,
.ui-topbar .theme-toggle:hover,
.ui-topbar .theme-toggle:focus-visible{opacity:1}
.ui-topbar .theme-toggle:hover{
  color:var(--text, #fff);
  border-color:var(--text, #fff);
  background:rgba(255,255,255,.04);
}
[data-theme="light"] .ui-topbar .theme-toggle{
  border-color:rgba(0,0,0,.18);
  color:rgba(0,0,0,.55);
}
[data-theme="light"] .ui-topbar .theme-toggle:hover{
  color:#1a1a1f;border-color:#1a1a1f;background:rgba(0,0,0,.03);
}
.ui-topbar .theme-toggle svg{width:14px;height:14px;display:block;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);transition:opacity .15s}
/* Default (dark family): show sun, hide moon. */
.ui-topbar .theme-toggle .ti-sun{opacity:1}
.ui-topbar .theme-toggle .ti-moon{opacity:0}
/* Light theme: show moon, hide sun. */
[data-theme="light"] .ui-topbar .theme-toggle .ti-sun{opacity:0}
[data-theme="light"] .ui-topbar .theme-toggle .ti-moon{opacity:1}
@media(max-width:560px){
  .ui-topbar .theme-toggle{width:24px;height:24px}
  .ui-topbar .theme-toggle svg{width:12px;height:12px}
}
@media(max-width:560px){
  /* Secondary category links (College / High School / Adults) drop off
     the topbar below 560px. Phone users land on content-first; the same
     routes are reachable from the footer and body sections. Keeps logo
     + primary DebateIt CTA thumb-reachable without overflow.
     !important is load-bearing: the "Live" link gets an inline
     display:inline-flex from topbar.js (so its red dot sits inline),
     which would otherwise beat this rule and leave Live leaking onto
     the bar — pushing the Voice AI CTA off the right edge. */
  .ui-topbar-right .ui-topbar-link{display:none !important}
  /* Keep one small discovery tab visible on phones: The Floor is the
     newest surface and otherwise hides behind the hamburger. */
  .ui-topbar-right .ui-topbar-link--mobile-keep{display:inline-flex !important}
  .ui-topbar .da-spar-pill{display:none !important}
  /* Tighten the icon cluster so the bell + lang flag + CTA never clip
     against the right edge once the links are gone. */
  .ui-topbar-right{gap:7px}
  /* Trim the CTA's inline 8px/18px padding (set in topbar.js) so the
     "Voice AI" pill clears the right edge on ~360px phones instead of
     getting sliced to "VOICE". !important beats the inline style. */
  .ui-topbar-right .ui-btn-primary{padding:8px 13px !important;letter-spacing:.02em}
}
@media(max-width:359px){
  /* Smallest phones (iPhone SE 1/2, older Androids): even with the
     trimmed cluster there isn't room for the sound + theme toggles
     alongside the bell, language flag, and the primary CTA. Drop the
     two utility toggles here only — bell (unread DMs), the language
     flag (≈80% of traffic is India), and the Voice AI CTA are the
     load-bearing controls. Both toggles stay on 360px+ phones. */
  .ui-topbar .sfx-toggle,
  .ui-topbar .theme-toggle,
  .ui-topbar-right .ui-topbar-link--mobile-keep{display:none !important}
}
@media(max-width:380px){
  /* Tightest phones (iPhone SE, small Android): trim padding + hide the
     trademark sup so the logo doesn't wrap into the CTA. */
  .ui-topbar{padding:0 10px}
  .ui-topbar-logo sup{display:none}
}

/* 2026-06-16: bigger thumb targets for the topbar icon cluster on phones.
   The icons stay visually compact (so the cluster still fits a ~360px bar),
   but an invisible ::after extends each one's TAPPABLE area to ~full bar
   height plus a few px sideways. The horizontal growth (6px total = 3px
   each side) stays inside the inter-icon gap so neighbors don't overlap.
   The big win is vertical: the bar is only 46px tall and the icons were
   14-34px, leaving dead zones above/below that ate taps. burger/bell/
   theme-toggle all use inline SVGs (no pseudo of their own), so ::after
   is free. Fixes the "hard to press the right buttons" complaint. */
@media(max-width:640px){
  .ui-topbar .ui-topbar-burger{position:relative}
  .ui-topbar .theme-toggle::after,
  .ui-topbar .ui-bell::after,
  .ui-topbar .ui-topbar-burger::after{
    content:'';position:absolute;top:50%;left:50%;
    transform:translate(-50%,-50%);
    width:calc(100% + 6px);height:42px;
  }
}

/* ── Nav tabs (pill row, uppercase) ──────────────────────── */
.ui-nav{
  display:flex;gap:16px;margin:0 auto 48px;padding:4px 32px;
  flex-wrap:nowrap;justify-content:center;align-items:center;
  max-width:100%;width:100%;
  position:sticky;top:calc(32px + 52px);z-index:999;
  overflow-x:auto;overflow-y:visible;
  -webkit-overflow-scrolling:touch;scrollbar-width:none;
}
body:not(.has-beta-strip) .ui-nav{top:52px}
.ui-nav::-webkit-scrollbar{display:none}
.ui-nav-btn{
  background:var(--bg-elev);border:1px solid var(--border);
  color:var(--text-dim);
  padding:13px 26px;border-radius:var(--radius-pill);
  font-size:.82rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  cursor:pointer;transition:all .2s var(--ease);
  font-family:inherit;white-space:nowrap;text-decoration:none;flex-shrink:0;
  box-shadow:var(--shadow-sm);
}
.ui-nav-btn:hover{
  color:var(--text);background:rgba(40,40,48,.75);
  border-color:var(--border-strong);transform:translateY(-1px);
  box-shadow:var(--shadow);
}
.ui-nav-btn.active{
  color:#fff;background:var(--accent);border-color:var(--accent);
  box-shadow:0 6px 24px var(--accent-glow);
}
@media(max-width:640px){
  .ui-nav{padding:12px 14px 10px;gap:8px;justify-content:flex-start}
  .ui-nav-btn{padding:9px 18px;font-size:.72rem}
}

/* ── Page shell / sections ───────────────────────────────── */
.ui-shell{
  position:relative;z-index:2;min-height:100vh;
  display:flex;flex-direction:column;align-items:center;
  width:100%;max-width:100vw;overflow-x:hidden;
  padding-top:96px; /* clear beta strip + topbar */
}
body:not(.has-beta-strip) .ui-shell{padding-top:64px}
.ui-section{padding:80px 24px;width:100%}
.ui-section-sm{padding:48px 24px;width:100%}
.ui-container{max-width:1100px;margin:0 auto;width:100%}
.ui-container-sm{max-width:760px;margin:0 auto;width:100%}
.ui-divider{height:1px;max-width:1100px;margin:0 auto;background:var(--border)}

/* ── Typography ──────────────────────────────────────────── */
.ui-eyebrow{
  display:inline-block;font-size:.72rem;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--accent);
  margin-bottom:20px;
}
.ui-h1{
  font-size:clamp(2.2rem,5vw,3.8rem);font-weight:900;
  text-transform:uppercase;letter-spacing:-.03em;line-height:.95;
  color:var(--text);margin:0 0 16px;
}
.ui-h1 .accent{color:var(--accent)}
.ui-h2{
  font-size:clamp(1.6rem,3.4vw,2.4rem);font-weight:800;
  letter-spacing:-.02em;line-height:1.1;color:var(--text);margin:0 0 14px;
}
.ui-h3{
  font-size:1.1rem;font-weight:700;letter-spacing:-.01em;
  line-height:1.25;color:var(--text);margin:0 0 8px;
}
.ui-lede{
  font-size:clamp(.95rem,1.4vw,1.1rem);color:var(--text-dim);
  line-height:1.65;max-width:620px;margin:0 auto 28px;font-weight:400;
}
.ui-p{font-size:.95rem;color:var(--text-dim);line-height:1.65;margin:0 0 14px}
.ui-muted{color:var(--text-dim)}

/* ── Buttons ─────────────────────────────────────────────── */
.ui-btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:14px 32px;border-radius:var(--radius-pill);
  font-size:.82rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  font-family:inherit;cursor:pointer;text-decoration:none;
  border:1px solid transparent;transition:transform .2s var(--ease),background .2s,border-color .2s,box-shadow .2s;
  white-space:nowrap;
}
.ui-btn:hover{transform:translateY(-1px)}
.ui-btn-primary{
  background:var(--accent);color:#fff;border-color:var(--accent);
  box-shadow:0 6px 24px var(--accent-glow);
}
.ui-btn-primary:hover{background:var(--accent-hover);border-color:var(--accent-hover)}
.ui-btn-secondary{
  background:var(--bg-elev);color:var(--text);border-color:var(--border-strong);
}
.ui-btn-secondary:hover{background:rgba(40,40,48,.75);border-color:var(--text)}
.ui-btn-ghost{
  background:transparent;color:var(--text-dim);border-color:var(--border);
}
.ui-btn-ghost:hover{color:var(--text);border-color:var(--border-strong)}
.ui-btn-sm{padding:10px 20px;font-size:.72rem}

/* Voice AI primary CTA. Solid brand red with a brighter halo so it
   still reads as "primary action" without the gold-amber gradient
   that drifted off-palette. 2026-05-19: orange stripped per user
   feedback. Pulsing white dot inside still signals "live, talk
   right now"; the white ring around the dot pops it against the red. */
.ui-btn-voice{
  display:inline-flex;align-items:center;gap:8px;
  background:#ef4444;
  color:#fff;border:1px solid rgba(255,255,255,.18);
  font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  box-shadow:0 6px 22px rgba(239,68,68,.48),0 0 0 1px rgba(255,255,255,.08) inset;
  text-decoration:none;white-space:nowrap;
  transition:transform .2s var(--ease),box-shadow .2s,background .2s;
}
.ui-btn-voice:hover{
  transform:translateY(-1px);
  background:#dc2626;
  box-shadow:0 10px 32px rgba(239,68,68,.6),0 0 0 1px rgba(255,255,255,.18) inset;
  color:#fff;
}
.ui-btn-voice-dot{
  width:7px;height:7px;border-radius:50%;
  background:#dc2626;
  box-shadow:0 0 0 2px rgba(255,255,255,.7),0 0 8px rgba(220,38,38,.9);
  /* 2026-05-26: pulse slowed 1.4s -> 2.8s + amplitude softened
     (scale 1.25 -> 1.12) per pulse-glow audit. The dot is the
     primary CTA's "live" signal so it stays animated — just at
     a calmer breathing pace instead of an urgent flash. */
  animation:ui-btn-voice-pulse 2.8s ease-in-out infinite;
}
@keyframes ui-btn-voice-pulse{
  0%,100%{transform:scale(1);opacity:1}
  50%{transform:scale(1.12);opacity:.78}
}
[data-theme="light"] .ui-btn-voice,
body.light-theme .ui-btn-voice{
  border-color:rgba(217,119,6,.65);
  box-shadow:0 6px 22px rgba(217,119,6,.32),0 0 0 1px rgba(0,0,0,.04) inset;
}

/* ── Badges / chips ──────────────────────────────────────── */
.ui-badge{
  display:inline-flex;align-items:center;gap:6px;
  padding:5px 12px;border-radius:var(--radius-pill);
  font-size:.7rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  border:1px solid var(--border);color:var(--text-dim);background:var(--bg-card);
}
.ui-badge.accent{border-color:var(--accent-border);color:var(--accent-hover);background:var(--accent-soft)}
.ui-chip{
  display:inline-flex;align-items:center;gap:6px;
  padding:8px 16px;border-radius:var(--radius-pill);
  font-size:.78rem;font-weight:500;color:var(--text-dim);
  background:var(--bg-card);border:1px solid var(--border);
  transition:border-color .2s,color .2s;
}
.ui-chip:hover{color:var(--text);border-color:var(--border-strong)}

/* ── Cards ───────────────────────────────────────────────── */
.ui-card{
  background:var(--bg-card);border:1px solid var(--border);
  border-radius:var(--radius-lg);padding:22px;
  transition:border-color .2s,transform .2s;
}
.ui-card:hover{border-color:var(--border-strong)}
.ui-card-label{
  display:block;font-size:.7rem;font-weight:700;color:var(--accent);
  text-transform:uppercase;letter-spacing:.08em;margin-bottom:6px;
}
.ui-card-body{font-size:.88rem;color:var(--text-dim);line-height:1.55}
.ui-grid{display:grid;gap:14px}
.ui-grid-2{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
.ui-grid-3{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}

/* ── Footer ──────────────────────────────────────────────── */
.ui-footer{
  padding:48px 24px 32px;border-top:1px solid var(--border);
  text-align:center;font-size:.78rem;color:var(--text-dim);line-height:1.6;
}
.ui-footer a{color:var(--text-dim);text-decoration:none;transition:color .2s}
.ui-footer a:hover{color:var(--text)}
.ui-footer-row{
  display:flex;gap:20px;justify-content:center;flex-wrap:wrap;
  margin-bottom:12px;
}

/* ── Mobile hamburger + slide-down sheet (≤560px only) ────
   The topbar links go display:none below 560px (existing media query
   above). Without this hamburger, mobile users had no way to
   navigate from the bar at all. Hamburger lives in .ui-topbar-right
   but shows ONLY on mobile; desktop uses the inline link rail. */
.ui-topbar-burger{
  display:none;
  width:34px;height:34px;padding:0;
  background:transparent;border:1px solid var(--border-strong, rgba(255,255,255,.18));
  border-radius:999px;color:var(--text, #fff);
  cursor:pointer;align-items:center;justify-content:center;
  font-family:inherit;transition:background .15s, border-color .15s, color .15s;
}
.ui-topbar-burger:hover{background:rgba(255,255,255,.06);border-color:var(--text)}
.ui-topbar-burger.is-open{background:var(--accent);border-color:var(--accent);color:#fff}
[data-theme="light"] .ui-topbar-burger{border-color:rgba(0,0,0,.18);color:rgba(0,0,0,.78)}
[data-theme="light"] .ui-topbar-burger:hover{background:rgba(0,0,0,.04);color:#1a1a1f}
@media(max-width:560px){
  .ui-topbar-burger{display:inline-flex}
}

/* Backdrop dims the page while the sheet is open. Pointer-events:auto
   only when .is-open so the dim layer never blocks clicks while invisible. */
.ui-topbar-sheet-backdrop{
  position:fixed;inset:0;z-index:998;
  background:rgba(0,0,0,.45);
  opacity:0;pointer-events:none;
  transition:opacity .18s ease;
}
.ui-topbar-sheet-backdrop.is-open{opacity:1;pointer-events:auto}

/* Sheet itself: full width, anchored just below the topbar, slides
   down from the bar. Stacks LINKS as full-width tap targets +
   primary CTA at the bottom. */
.ui-topbar-sheet{
  position:fixed;left:0;right:0;top:60px;z-index:999;
  display:flex;flex-direction:column;gap:4px;
  padding:14px 16px 22px;
  background:var(--bg-elev-solid, #17171b);
  border-bottom:1px solid var(--border, rgba(255,255,255,.08));
  box-shadow:0 18px 40px rgba(0,0,0,.4);
  transform:translateY(-12px);opacity:0;
  /* CRITICAL: the closed sheet must NOT catch taps. The class rule
     `display:flex` above outranks the UA `[hidden]{display:none}` rule
     (author beats user-agent origin), so the `hidden` attribute the JS
     sets does nothing on its own — leaving an invisible, full-screen,
     z-index:999 overlay that swallowed every tap on mobile and routed it
     to whichever stacked nav link sat under the finger ("tap Live Debates,
     land on Learn"). Two guards make the closed state truly inert:
       1) pointer-events:none whenever .is-open is absent;
       2) [hidden] hard-hides via display:none (restores intended behavior).
     Only .is-open re-enables interaction. */
  pointer-events:none;
  transition:transform .2s ease, opacity .2s ease;
}
.ui-topbar-sheet[hidden]{display:none}
.ui-topbar-sheet.is-open{transform:translateY(0);opacity:1;pointer-events:auto}
body.has-beta-strip .ui-topbar-sheet{top:88px}
.ui-topbar-sheet-link{
  display:flex;align-items:center;gap:10px;
  padding:14px 14px;border-radius:10px;
  font-size:1rem;font-weight:600;letter-spacing:-.005em;
  color:var(--text, #fff);text-decoration:none;
}
.ui-topbar-sheet-link:hover,
.ui-topbar-sheet-link:focus-visible{background:rgba(255,255,255,.04);outline:none}
.ui-topbar-sheet-link.is-active{color:var(--accent)}
.ui-topbar-sheet-dot{
  width:8px;height:8px;border-radius:50%;
  background:#ef4444;box-shadow:0 0 10px #ef4444;flex-shrink:0;
}
.ui-topbar-sheet-cta{
  display:inline-flex;align-items:center;justify-content:center;
  margin:10px 0 0;padding:14px 18px;border-radius:999px;
  background:var(--accent);color:#fff;text-decoration:none;
  font-size:1rem;font-weight:800;letter-spacing:.01em;
}
.ui-topbar-sheet-cta:hover{background:#dc2626}
[data-theme="light"] .ui-topbar-sheet{background:rgba(255,255,255,.97);border-bottom-color:rgba(0,0,0,.08)}
[data-theme="light"] .ui-topbar-sheet-link{color:#1a1a1f}
[data-theme="light"] .ui-topbar-sheet-link:hover{background:rgba(0,0,0,.04)}
[data-theme="light"] .ui-topbar-sheet-link.is-active{color:#dc2626}
/* Hide the sheet + backdrop entirely above the mobile breakpoint so a
   misfired class toggle on desktop can never leave hidden-but-tappable
   nodes intercepting clicks. */
@media(min-width:561px){
  .ui-topbar-sheet,
  .ui-topbar-sheet-backdrop{display:none !important}
}

/* ── Topbar utility-toggle hide (sitewide) ─────────────────
   2026-05-26: per Aidan, the SFX mute toggle (.sfx-toggle) and the
   sun/moon theme toggle (.theme-toggle) are gone from the topbar
   everywhere — not just mobile. They were tertiary controls that
   added visual noise next to the bell, lang flag, and primary CTA
   without anyone using them. Promoted from the prior @media
   (max-width:560px)-only hide to an unconditional hide that wins
   over every other display:inline-flex declaration earlier in this
   file (including the base .ui-topbar .sfx-toggle{display:inline-flex}
   and .ui-topbar .theme-toggle{display:inline-flex} rules). If we
   ever want either control back, drop this block and the cascade
   restores the originals. The mobile-only hide rule inside the
   @media block is now redundant but harmless.
   2026-05-27 plane session: theme-toggle revived (per user request,
   "have the option to change lighting here"). SFX toggle stays
   killed — that was a separate decision and didn't survive the
   2026-05-19 amber-strip sweep. */
.ui-topbar .sfx-toggle{display:none !important}

/* 2026-05-26: on mobile, the auth chip's inline "Sign out" button
   was getting truncated to "Sig..." at the right edge of the topbar
   because the chip + bell + lang caret + Voice AI pill together
   exceeded the 375px viewport. Hide the Sign-out button on ≤560px;
   the avatar+name pill is still tappable and links to /profile
   where the user can sign out from the profile actions. */
@media(max-width:560px){
  #barUser > button{display:none !important}
}

/* ── Site-wide motion polish (2026-07-01) ─────────────────────
   Loaded via ui.css on ~48 pages, so it's the one place to make the
   whole site feel smoother without touching each page.

   1) Cross-page fade. The View Transitions API crossfades one page into
      the next on same-origin navigation. Pure progressive enhancement:
      browsers without it (or reduced-motion users, via the block below)
      just hard-cut. Matches the existing @view-transition convention on
      index.html / debate-it.html, spread site-wide.
   2) Smooth interactive states for buttons/links. Deliberately LOW
      specificity and paint-only properties (color/background/border/
      shadow, never transform/layout), so any component's own transition
      wins and nothing janks. Buttons that had instant hovers now ease. */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: no-preference){
  ::view-transition-old(root),
  ::view-transition-new(root){ animation-duration:260ms; animation-timing-function:cubic-bezier(.22,.9,.32,1); }
  ::view-transition-old(root){ animation-name:ui-vt-out }
  ::view-transition-new(root){ animation-name:ui-vt-in }
  @keyframes ui-vt-out{ to{ opacity:0; transform:translateY(-6px) } }
  @keyframes ui-vt-in { from{ opacity:0; transform:translateY(8px) } }
  a, button{ transition:color .18s ease, background-color .18s ease, border-color .18s ease, box-shadow .18s ease; }
}

/* ── Reduced motion ──────────────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms!important;transition-duration:.01ms!important}
  .ui-nav-btn:hover,.ui-btn:hover{transform:none}
  /* Kill the cross-page crossfade too. */
  ::view-transition-group(*),::view-transition-old(root),::view-transition-new(root){animation:none!important}
}

/* ── Topbar "More" menu (2026-07-19) ─────────────────────────
   Desktop dropdown for the curated off-bar pages (spectate,
   leaderboard, community, classic trainer, coaches, pricing,
   schools, atlas, story, future). The bar keeps only the pillars;
   this is the discovery surface for everything else, since app
   pages carry no footer. Hidden ≤560px — the mobile sheet carries
   the same links as a compact two-column More group. */
.ui-topbar-more{position:relative;display:inline-flex}
.ui-topbar-more-btn{display:inline-flex;align-items:center;gap:5px}
.ui-topbar-more-btn svg{transition:transform .18s ease}
.ui-topbar-more-btn[aria-expanded="true"] svg{transform:rotate(180deg)}
.ui-topbar-more-panel{
  position:absolute;top:calc(100% + 17px);right:-10px;z-index:1001;
  display:none;grid-template-columns:auto auto auto;gap:16px 26px;
  padding:18px 22px 20px;border-radius:14px;
  /* Solid, not --bg-elev: inside the blurred topbar, backdrop-filter
     can't reach the page behind, so a translucent bg lets the hero
     text bleed through the open menu. */
  background:var(--bg-elev-solid, #17171b);
  border:1px solid var(--border, rgba(255,255,255,.1));
  box-shadow:0 24px 60px -20px rgba(0,0,0,.5);
}
.ui-topbar-more-panel.is-open{display:grid}
.ui-topbar-more-head{
  font-size:.56rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:color-mix(in srgb, var(--text, #fff) 52%, transparent);
  margin-bottom:9px;white-space:nowrap;
}
.ui-topbar-more-panel a{
  display:block;padding:5px 0;white-space:nowrap;
  font-size:.78rem;font-weight:500;letter-spacing:.01em;
  color:color-mix(in srgb, var(--text, #fff) 86%, transparent);
  text-decoration:none;transition:color .15s;
}
.ui-topbar-more-panel a:hover{color:var(--accent)}
.ui-topbar-more-panel a.is-active{color:var(--accent)}
@media(max-width:560px){
  .ui-topbar-more{display:none}
}

/* Mobile-sheet More group: quiet two-column grid under the main
   stack so ten extra links don't triple the sheet's height. The
   sheet itself gains a scroll guard for short viewports. */
.ui-topbar-sheet{max-height:calc(100dvh - 60px);overflow-y:auto}
.ui-topbar-sheet-more-head{
  margin:10px 14px 2px;padding-top:12px;
  border-top:1px solid var(--border, rgba(255,255,255,.08));
  font-size:.6rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:color-mix(in srgb, var(--text, #fff) 52%, transparent);
}
.ui-topbar-sheet-more{display:grid;grid-template-columns:1fr 1fr;gap:0 10px;padding:0 4px}
.ui-topbar-sheet-more a{
  display:block;padding:10px 10px;border-radius:8px;
  font-size:.85rem;font-weight:500;
  color:color-mix(in srgb, var(--text, #fff) 78%, transparent);
  text-decoration:none;
}
.ui-topbar-sheet-more a:hover,
.ui-topbar-sheet-more a:focus-visible{background:rgba(255,255,255,.04);outline:none}
.ui-topbar-sheet-more a.is-active{color:var(--accent)}
