/* ============================================================================
   LEXARENA — Design System
   "Premium & trustworthy": deep indigo/navy base, gold + teal accents,
   glassmorphism, refined type, smooth motion.
   Single source of truth for tokens, components and motion. Pages compose
   these classes; page-specific tweaks use the CSS variables below.
   ========================================================================== */

/* ------------------------------- Tokens ---------------------------------- */
:root {
  /* Color: base & surfaces */
  --color-bg:            #0B1020;
  --color-bg-2:          #0F1630;
  --color-surface:       #161E3A;
  --color-surface-2:     #1E2748;
  --color-glass:         rgba(30, 39, 72, 0.55);
  --color-glass-hi:      rgba(255, 255, 255, 0.06);

  /* Color: brand & accents */
  --color-primary:       #5B6CFF;
  --color-primary-700:   #3E4CD8;
  --color-primary-300:   #97A2FF;
  --color-secondary:     #8A6BFF;
  --color-gold:          #F5C04A;
  --color-gold-600:      #D9A22E;
  --color-teal:          #2DD4BF;
  --color-teal-600:      #14B8A6;

  /* Color: semantic */
  --color-success:       #34D399;
  --color-warning:       #FBBF24;
  --color-danger:        #FB5E6D;

  /* Color: text & lines */
  --color-text:          #F4F6FF;
  --color-text-muted:    #A3ACCB;
  --color-text-faint:    #6B7497;
  --color-border:        rgba(255, 255, 255, 0.10);
  --color-border-strong: rgba(255, 255, 255, 0.18);

  /* Consolidated overlay/tint scale — replaces ad-hoc rgba(255,255,255,X)
     used throughout for "faint card on dark bg" and hover-state effects.
     Dark defaults below match what those rules used to hardcode; light
     mode flips these to dark-tinted so the same effect reads on a white bg. */
  --tint-1: rgba(255, 255, 255, .03);  /* faint card tint */
  --tint-2: rgba(255, 255, 255, .05);  /* weak hover */
  --tint-4: rgba(255, 255, 255, .10);  /* strong hover/active */
  /* the ~.06-.07 tier reuses --color-glass-hi below, no separate token */

  /* Sticky/fixed chrome bars (header, tab-bar, mobile nav dropdown) */
  --chrome-bg:       rgba(11, 16, 32, .78);
  --chrome-bg-solid: rgba(11, 16, 32, .96);

  /* Text colors that read fine on a dark chip bg but need to flip
     direction (darker, not lighter) once the same tinted chip sits on white */
  --chip-live-text:    #ffd7dc;
  --rank-silver-text:  #CBD5E1;
  --cefr-b2-text:      #c4b5ff;

  /* Typography */
  --font-display: "Sora", system-ui, -apple-system, sans-serif;
  --font-body:    "Inter", system-ui, -apple-system, sans-serif;
  --fs-xs:   0.75rem;
  --fs-sm:   0.875rem;
  --fs-base: 1rem;
  --fs-md:   1.125rem;
  --fs-lg:   1.5rem;
  --fs-xl:   2rem;
  --fs-2xl:  2.75rem;
  --fs-3xl:  3.75rem;
  --lh-tight: 1.1;
  --lh-snug:  1.3;
  --lh-body:  1.6;
  --tracking-tight: -0.02em;

  /* Spacing (4px base) */
  --sp-1: 0.25rem;  --sp-2: 0.5rem;  --sp-3: 0.75rem; --sp-4: 1rem;
  --sp-5: 1.5rem;   --sp-6: 2rem;    --sp-8: 3rem;    --sp-10: 4rem;
  --sp-12: 6rem;

  /* Radius */
  --r-sm: 8px;   --r-md: 12px;  --r-lg: 18px;
  --r-xl: 26px;  --r-pill: 999px; --r-circle: 50%;

  /* Elevation / shadow */
  --shadow-1: 0 1px 2px rgba(5,8,22,.40);
  --shadow-2: 0 6px 18px rgba(5,8,22,.45);
  --shadow-3: 0 16px 40px rgba(5,8,22,.55);
  --shadow-4: 0 28px 70px rgba(5,8,22,.65);
  --glow-primary: 0 0 28px rgba(91,108,255,.45);
  --glow-gold:    0 0 26px rgba(245,192,74,.50);
  --glow-teal:    0 0 24px rgba(45,212,191,.45);

  /* Glassmorphism recipe */
  --glass-bg:     rgba(30, 39, 72, 0.55);
  --glass-blur:   blur(18px) saturate(140%);
  --glass-border: 1px solid rgba(255,255,255,0.12);

  /* Gradients */
  --grad-brand:   linear-gradient(135deg, #5B6CFF 0%, #8A6BFF 100%);
  --grad-victory: linear-gradient(135deg, #F5C04A 0%, #D9A22E 60%, #8A6BFF 130%);
  --grad-aurora:  linear-gradient(120deg, #2DD4BF 0%, #5B6CFF 55%, #8A6BFF 100%);
  --grad-surface: linear-gradient(180deg, rgba(255,255,255,.06) 0%, rgba(255,255,255,0) 100%);
  --grad-hero-bg: radial-gradient(1200px 600px at 70% -10%, rgba(91,108,255,.30), transparent 60%),
                  radial-gradient(900px 500px at 10% 10%, rgba(45,212,191,.16), transparent 55%),
                  var(--color-bg);

  /* Motion */
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
  --ease-out:    cubic-bezier(.16, 1, .3, 1);
  --dur-fast: .15s;
  --dur-mid:  .3s;
  --dur-slow: .6s;

  /* Z-index ladder */
  --z-header: 100;
  --z-overlay: 500;
  --z-modal: 600;
  --z-toast: 700;
}

/* CEFR level accent colors (shared by chips, badges, tags) */
:root {
  --cefr-A1: #34D399;
  --cefr-A2: #2DD4BF;
  --cefr-B1: #5B6CFF;
  --cefr-B2: #8A6BFF;
  --cefr-C1: #F5C04A;
  --cefr-C2: #FB5E6D;
}

/* ---------------------------- Light theme --------------------------------
   Explicit choice (data-theme="light", set by the toggle in mountHeader())
   always wins. With no explicit choice, the OS preference decides via the
   @media block below — same token values, re-declared under the media
   query since custom properties can't be shared across two selector blocks
   any other way. */
:root[data-theme="light"] {
  --color-bg:            #F0F1F7;
  --color-bg-2:          #E8EAF3;
  --color-surface:       #FFFFFF;
  --color-surface-2:     #F5F6FB;
  --color-glass:         rgba(255, 255, 255, .72);
  --color-glass-hi:      rgba(15, 20, 45, .05);

  --color-text:          #15162B;
  --color-text-muted:    #6B6F8E;
  --color-text-faint:    #9498B3;
  --color-border:        rgba(15, 20, 45, .09);
  --color-border-strong: rgba(15, 20, 45, .16);

  --tint-1: rgba(15, 20, 45, .035);
  --tint-2: rgba(15, 20, 45, .05);
  --tint-4: rgba(15, 20, 45, .09);

  --chrome-bg:       rgba(255, 255, 255, .82);
  --chrome-bg-solid: rgba(255, 255, 255, .98);

  --chip-live-text:   #B3123A;
  --rank-silver-text: #64748B;
  --cefr-b2-text:     #6D28D9;

  --shadow-1: 0 1px 2px rgba(30,35,70,.07);
  --shadow-2: 0 6px 18px rgba(30,35,70,.09);
  --shadow-3: 0 16px 40px rgba(30,35,70,.11);
  --shadow-4: 0 28px 70px rgba(30,35,70,.15);
  --glow-primary: 0 0 20px rgba(91,108,255,.28);
  --glow-gold:    0 0 18px rgba(245,192,74,.32);
  --glow-teal:    0 0 16px rgba(45,212,191,.28);

  --glass-bg:     rgba(255, 255, 255, .72);
  --glass-border: 1px solid rgba(15, 20, 45, .08);

  --grad-hero-bg: radial-gradient(1200px 600px at 70% -10%, rgba(91,108,255,.10), transparent 60%),
                  radial-gradient(900px 500px at 10% 10%, rgba(45,212,191,.08), transparent 55%),
                  var(--color-bg);
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --color-bg:            #F0F1F7;
    --color-bg-2:          #E8EAF3;
    --color-surface:       #FFFFFF;
    --color-surface-2:     #F5F6FB;
    --color-glass:         rgba(255, 255, 255, .72);
    --color-glass-hi:      rgba(15, 20, 45, .05);

    --color-text:          #15162B;
    --color-text-muted:    #6B6F8E;
    --color-text-faint:    #9498B3;
    --color-border:        rgba(15, 20, 45, .09);
    --color-border-strong: rgba(15, 20, 45, .16);

    --tint-1: rgba(15, 20, 45, .035);
    --tint-2: rgba(15, 20, 45, .05);
    --tint-4: rgba(15, 20, 45, .09);

    --chrome-bg:       rgba(255, 255, 255, .82);
    --chrome-bg-solid: rgba(255, 255, 255, .98);

    --chip-live-text:   #B3123A;
    --rank-silver-text: #64748B;
    --cefr-b2-text:     #6D28D9;

    --shadow-1: 0 1px 2px rgba(30,35,70,.07);
    --shadow-2: 0 6px 18px rgba(30,35,70,.09);
    --shadow-3: 0 16px 40px rgba(30,35,70,.11);
    --shadow-4: 0 28px 70px rgba(30,35,70,.15);
    --glow-primary: 0 0 20px rgba(91,108,255,.28);
    --glow-gold:    0 0 18px rgba(245,192,74,.32);
    --glow-teal:    0 0 16px rgba(45,212,191,.28);

    --glass-bg:     rgba(255, 255, 255, .72);
    --glass-border: 1px solid rgba(15, 20, 45, .08);

    --grad-hero-bg: radial-gradient(1200px 600px at 70% -10%, rgba(91,108,255,.10), transparent 60%),
                    radial-gradient(900px 500px at 10% 10%, rgba(45,212,191,.08), transparent 55%),
                    var(--color-bg);
  }
}

/* ------------------------------- Reset ----------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; overflow-x: hidden; }
body {
  font-family: var(--font-body);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  color: var(--color-text);
  background: var(--color-bg);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
  /* clip, not hidden: still stops a stray wide child from panning the page
     sideways, but unlike `hidden` it doesn't establish a scroll container —
     `hidden` here was silently breaking every position:sticky element on the
     site (confirmed on #app-header itself, not just this page's new bar). */
  overflow-x: clip;
}
img, svg, canvas { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; padding: 0; }
h1, h2, h3, h4 { font-family: var(--font-display); line-height: var(--lh-tight); letter-spacing: var(--tracking-tight); font-weight: 700; }
:focus-visible { outline: 2px solid var(--color-primary-300); outline-offset: 2px; border-radius: var(--r-sm); }
::selection { background: rgba(91,108,255,.4); }

/* App background glow used on authed pages */
.app-bg { background: var(--grad-hero-bg); }

/* ------------------------------ Layout ----------------------------------- */
.container { width: 100%; max-width: 1200px; margin-inline: auto; padding-inline: var(--sp-5); }
.container-narrow { max-width: 880px; }
.grid > * { min-width: 0; } /* grid tracks don't shrink below their content by default — let long names/rows truncate instead of overflowing */
.section { padding-block: var(--sp-12); }
.stack { display: flex; flex-direction: column; gap: var(--sp-4); }
.row { display: flex; align-items: center; gap: var(--sp-3); }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.wrap { flex-wrap: wrap; }
.grid { display: grid; gap: var(--sp-5); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-auto { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.spacer { flex: 1; }
.center { text-align: center; }
.hidden { display: none !important; }

/* --------------------------- Typography utils ---------------------------- */
.display-1 { font-size: clamp(2.5rem, 6vw, var(--fs-3xl)); font-weight: 800; }
.display-2 { font-size: clamp(2rem, 4.5vw, var(--fs-2xl)); font-weight: 800; }
.h-section { font-size: clamp(1.6rem, 3.4vw, var(--fs-xl)); }
.lead { font-size: var(--fs-md); color: var(--color-text-muted); }
.muted { color: var(--color-text-muted); }
.faint { color: var(--color-text-faint); }
.text-sm { font-size: var(--fs-sm); }
.text-xs { font-size: var(--fs-xs); }
.text-gold   { color: var(--color-gold); }
/* @handle: an identifier, so it reads slightly apart from the display name. */
.lx-handle { font-variant-numeric: tabular-nums; letter-spacing: .01em; opacity: .95; }
.text-teal   { color: var(--color-teal); }
.text-danger { color: var(--color-danger); }
.text-success{ color: var(--color-success); }
.fw-700 { font-weight: 700; }
.mono { font-variant-numeric: tabular-nums; }
.grad-text {
  background: var(--grad-aurora); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.grad-text-gold {
  background: var(--grad-victory); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

/* ------------------------------ Surfaces --------------------------------- */
.glass, .card-glass {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: var(--glass-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-3);
}
.card {
  background: linear-gradient(180deg, var(--color-surface) 0%, var(--color-surface-2) 140%);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-2);
}
.pad-4 { padding: var(--sp-4); }
.pad-5 { padding: var(--sp-5); }
.pad-6 { padding: var(--sp-6); }
.card-glass.pad, .card.pad { padding: var(--sp-5); }
.hover-lift { transition: transform var(--dur-mid) var(--ease-out), box-shadow var(--dur-mid) var(--ease-out); }
.hover-lift:hover { transform: translateY(-4px); box-shadow: var(--shadow-4); }

/* ------------------------------ Buttons ---------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  padding: .7rem 1.3rem; border-radius: var(--r-md); font-weight: 600; font-size: var(--fs-sm);
  font-family: var(--font-body); white-space: nowrap; border: 1px solid transparent;
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-mid),
              background var(--dur-mid), border-color var(--dur-mid), opacity var(--dur-fast);
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn:disabled { opacity: .5; pointer-events: none; }
.btn-lg { padding: .95rem 1.8rem; font-size: var(--fs-base); border-radius: var(--r-md); }
.btn-sm { padding: .45rem .9rem; font-size: var(--fs-xs); }
.btn-block { width: 100%; }
/* Dashboard hero "Play" CTA — bigger than even .btn-lg calls for, since this
   is the single most important action on the page and needs to read as such
   at a glance (the emoji scales up right along with the text, same em unit). */
.play-cta-btn { font-size: 1.6rem; font-weight: 800; padding: 1.15rem 1.8rem; gap: .6rem; }
.btn-primary { background: var(--grad-brand); color: #fff; box-shadow: var(--shadow-2); }
.btn-primary:hover { box-shadow: var(--glow-primary), var(--shadow-2); }
.btn-gold { background: var(--grad-victory); color: #1a1305; box-shadow: var(--shadow-2); font-weight: 700; }
.btn-gold:hover { box-shadow: var(--glow-gold), var(--shadow-2); }
.btn-teal { background: linear-gradient(135deg, var(--color-teal), var(--color-teal-600)); color: #042420; }
.btn-teal:hover { box-shadow: var(--glow-teal), var(--shadow-2); }
.btn-ghost { background: var(--tint-2); border-color: var(--color-border); color: var(--color-text); }
.btn-ghost:hover { background: var(--tint-4); border-color: var(--color-border-strong); }
.btn-danger { background: rgba(251,94,109,.15); border-color: rgba(251,94,109,.4); color: var(--color-danger); }
.btn-danger:hover { background: rgba(251,94,109,.25); }
.btn-icon { padding: .55rem; width: 2.5rem; height: 2.5rem; border-radius: var(--r-md); }

/* ------------------------- Chips / pills / badges ------------------------ */
.chip {
  display: inline-flex; align-items: center; gap: var(--sp-2); white-space: nowrap;
  padding: .3rem .7rem; border-radius: var(--r-pill); font-size: var(--fs-xs); font-weight: 600;
  background: var(--color-glass-hi); border: 1px solid var(--color-border); color: var(--color-text-muted);
}
.chip-primary { background: rgba(91,108,255,.16); border-color: rgba(91,108,255,.35); color: var(--color-primary-300); }
.chip-gold { background: rgba(245,192,74,.14); border-color: rgba(245,192,74,.4); color: var(--color-gold); }
.chip-teal { background: rgba(45,212,191,.14); border-color: rgba(45,212,191,.4); color: var(--color-teal); }
.chip-danger { background: rgba(251,94,109,.14); border-color: rgba(251,94,109,.4); color: var(--color-danger); }
.chip-live { background: rgba(251,94,109,.16); border-color: rgba(251,94,109,.45); color: var(--chip-live-text); }
.chip-live::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--color-danger); box-shadow: 0 0 8px var(--color-danger); animation: pulse-dot 1.4s infinite; }

/* CEFR level pill — color set inline via --cefr-{level} or class */
.cefr { font-weight: 700; }
.cefr-A1 { background: rgba(52,211,153,.16); border-color: rgba(52,211,153,.45); color: var(--cefr-A1); }
.cefr-A2 { background: rgba(45,212,191,.16); border-color: rgba(45,212,191,.45); color: var(--cefr-A2); }
.cefr-B1 { background: rgba(91,108,255,.18); border-color: rgba(91,108,255,.45); color: var(--color-primary-300); }
.cefr-B2 { background: rgba(138,107,255,.18); border-color: rgba(138,107,255,.45); color: var(--cefr-b2-text); }
.cefr-C1 { background: rgba(245,192,74,.16); border-color: rgba(245,192,74,.45); color: var(--cefr-C1); }
.cefr-C2 { background: rgba(251,94,109,.16); border-color: rgba(251,94,109,.45); color: var(--cefr-C2); }

/* ------------------------------ Avatars ---------------------------------- */
.avatar {
  --size: 40px;
  width: var(--size); height: var(--size); border-radius: 50%;
  display: grid; place-items: center; flex: 0 0 auto;
  font-family: var(--font-display); font-weight: 700; color: #fff;
  background: var(--grad-brand); box-shadow: var(--shadow-1);
  position: relative; font-size: calc(var(--size) * .4);
}
.avatar-sm { --size: 32px; }
.avatar-lg { --size: 64px; }
.avatar-xl { --size: 96px; }
.avatar-gold { background: var(--grad-victory); color: #1a1305; box-shadow: var(--glow-gold); }
.avatar-teal { background: linear-gradient(135deg, var(--color-teal), var(--color-teal-600)); color: #042420; }
.avatar-ring { box-shadow: 0 0 0 3px var(--color-bg), 0 0 0 5px var(--color-gold); }
.avatar .presence { position: absolute; right: -1px; bottom: -1px; width: 12px; height: 12px; border-radius: 50%; background: var(--color-success); border: 2px solid var(--color-bg); }
.avatar-img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block; }
/* editable avatar (profile page): camera badge overlapping the photo */
.avatar-edit { position: relative; display: inline-block; cursor: pointer; }
.avatar-cam {
  position: absolute; right: -2px; bottom: -2px; width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center; font-size: 14px; cursor: pointer;
  background: var(--color-teal); color: #042420; border: 2px solid var(--color-bg);
  box-shadow: var(--shadow-1); transition: transform .12s ease;
}
.avatar-edit:hover .avatar-cam { transform: scale(1.08); }

/* ------------------------------ Stat tile -------------------------------- */
.stat-tile {
  display: flex; flex-direction: column; gap: var(--sp-1);
  padding: var(--sp-5); border-radius: var(--r-lg);
  background: var(--glass-bg); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  border: var(--glass-border); position: relative; overflow: hidden;
}
.stat-tile .stat-icon { font-size: 1.3rem; opacity: .9; }
.stat-tile .stat-value { font-family: var(--font-display); font-size: var(--fs-xl); font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.stat-tile .stat-label { font-size: var(--fs-xs); color: var(--color-text-muted); text-transform: uppercase; letter-spacing: .06em; }
.stat-tile .stat-delta { font-size: var(--fs-xs); font-weight: 600; }
.stat-tile::after { content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--grad-aurora); opacity: .8; }

/* ------------------------------ Progress --------------------------------- */
.progress-bar { height: 10px; border-radius: var(--r-pill); background: var(--color-surface-2); overflow: hidden; }
.progress-bar > span { display: block; height: 100%; border-radius: var(--r-pill); background: var(--grad-aurora); transition: width var(--dur-slow) var(--ease-out); }
.progress-bar.gold > span { background: var(--grad-victory); }
.progress-thin { height: 6px; }

/* XP ring (SVG) helper sizing */
.xp-ring { display: inline-grid; place-items: center; position: relative; }
.xp-ring .xp-ring-label { position: absolute; text-align: center; font-family: var(--font-display); }

/* --------------------------- Leaderboard rows ---------------------------- */
.leaderboard { display: flex; flex-direction: column; gap: var(--sp-2); }
.lb-row {
  display: grid; grid-template-columns: 38px 1fr auto; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md);
  background: var(--tint-1); border: 1px solid var(--color-border);
  transition: transform var(--dur-mid) var(--ease-spring), background var(--dur-mid), border-color var(--dur-mid);
}
.lb-row .lb-rank { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-md); color: var(--color-text-muted); text-align: center; }
.lb-row .lb-name { font-weight: 600; }
.lb-row .lb-score { font-family: var(--font-display); font-weight: 700; font-variant-numeric: tabular-nums; }
.lb-row .lb-meta { font-size: var(--fs-xs); color: var(--color-text-faint); }
.lb-row.is-you { border-color: rgba(91,108,255,.55); background: rgba(91,108,255,.10); box-shadow: var(--glow-primary); }
.lb-row.rank-1 { border-color: rgba(245,192,74,.55); background: linear-gradient(90deg, rgba(245,192,74,.14), var(--tint-1)); }
.lb-row.rank-1 .lb-rank { color: var(--color-gold); }
.lb-row.rank-2 { border-color: rgba(203,213,225,.4); }
.lb-row.rank-2 .lb-rank { color: var(--rank-silver-text); }
.lb-row.rank-3 { border-color: rgba(217,162,46,.45); }
.lb-row.rank-3 .lb-rank { color: var(--color-gold-600); }
.lb-delta { font-size: var(--fs-xs); font-weight: 700; }
.lb-delta.up { color: var(--color-success); }
.lb-delta.down { color: var(--color-danger); }

/* ------------------------------- Podium ---------------------------------- */
.podium { display: flex; align-items: flex-end; justify-content: center; gap: var(--sp-4); padding-top: var(--sp-8); }
.podium-col { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); width: 150px; }
.podium-stand {
  width: 100%; border-radius: var(--r-lg) var(--r-lg) 0 0; position: relative;
  display: grid; place-items: start center; padding-top: var(--sp-3);
  background: linear-gradient(180deg, var(--color-surface-2), var(--color-surface));
  border: 1px solid var(--color-border); border-bottom: none;
  transform-origin: bottom; animation: rise var(--dur-slow) var(--ease-spring) both;
}
.podium-stand .podium-place { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-2xl); opacity: .25; }
.podium-col.p1 .podium-stand { height: 190px; background: linear-gradient(180deg, rgba(245,192,74,.25), var(--color-surface)); border-color: rgba(245,192,74,.5); box-shadow: var(--glow-gold); }
.podium-col.p2 .podium-stand { height: 140px; }
.podium-col.p3 .podium-stand { height: 110px; }
.podium-col.p1 { order: 2; } .podium-col.p2 { order: 1; } .podium-col.p3 { order: 3; }
/* Shared places are rendered in plain rank order, so the 2-1-3 shuffle above
   must not reorder them (it would split a tied pair apart). */
.podium-tied .podium-col.p1, .podium-tied .podium-col.p2, .podium-tied .podium-col.p3 { order: 0; }
.podium-col.p1 .avatar { box-shadow: var(--glow-gold); }
.podium-crown { font-size: 1.6rem; animation: float 2.4s ease-in-out infinite; }

/* ------------------------------ Timer ring ------------------------------- */
.timer-ring { position: relative; width: 110px; height: 110px; }
.timer-ring svg { transform: rotate(-90deg); }
.timer-ring .timer-track { fill: none; stroke: var(--color-surface-2); }
.timer-ring .timer-prog { fill: none; stroke: var(--color-teal); stroke-linecap: round; transition: stroke .3s; }
.timer-ring .timer-num {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-xl); font-variant-numeric: tabular-nums;
}
.timer-ring.warn .timer-prog { stroke: var(--color-warning); }
.timer-ring.danger .timer-prog { stroke: var(--color-danger); }
.timer-ring.danger { animation: pulse 0.7s ease-in-out infinite; }

/* ----------------------------- Option cards ------------------------------ */
.option-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); }
/* one lone child (a typed-answer form) would sit in the left column of the
   2-up grid — this centres it under the question stem instead. */
.option-grid.single-col { grid-template-columns: 1fr; justify-items: center; }
.option-card {
  display: flex; align-items: center; gap: var(--sp-4); text-align: left;
  padding: var(--sp-5); border-radius: var(--r-lg); width: 100%;
  background: var(--glass-bg); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--color-border); color: var(--color-text); font-size: var(--fs-md); font-weight: 600;
  transition: transform var(--dur-fast) var(--ease-out), border-color var(--dur-mid), background var(--dur-mid), box-shadow var(--dur-mid);
}
.option-card:hover:not(:disabled) { transform: translateY(-3px); border-color: var(--color-primary); box-shadow: var(--glow-primary); }
.option-card:disabled { cursor: default; }
.option-card .opt-key {
  width: 36px; height: 36px; flex: 0 0 auto; border-radius: var(--r-md); display: grid; place-items: center;
  background: var(--color-glass-hi); font-family: var(--font-display); font-weight: 800;
}
.option-card.correct { border-color: var(--color-success); background: rgba(52,211,153,.16); box-shadow: 0 0 26px rgba(52,211,153,.35); }
.option-card.correct .opt-key { background: var(--color-success); color: #052b1e; }
.option-card.wrong { border-color: var(--color-danger); background: rgba(251,94,109,.14); animation: shake .4s; }
.option-card.wrong .opt-key { background: var(--color-danger); color: #2b0509; }
.option-card.chosen { border-color: var(--color-primary-300); }
.option-card.dim { opacity: .45; }

/* ------------------------------- HUD ------------------------------------- */
.hud { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); }
.hud-pill { display: flex; align-items: center; gap: var(--sp-2); padding: .5rem 1rem; border-radius: var(--r-pill); background: var(--glass-bg); border: var(--glass-border); font-weight: 700; font-family: var(--font-display); }
.hud-pill .hud-icon { font-size: 1.1rem; }
.streak-flame { animation: pulse-flame 1.2s ease-in-out infinite; }

/* ------------------------------- Modal ----------------------------------- */
/* A modal's primary action pinned to the bottom of its scroll area, for forms
   long enough that the button would otherwise require scrolling all the way
   down to find (or worse, land under mobile browser chrome). */
.modal-footer-sticky {
  position: sticky; bottom: calc(-1 * var(--sp-6));
  margin: var(--sp-2) calc(-1 * var(--sp-6)) calc(-1 * var(--sp-6));
  padding: var(--sp-3) var(--sp-6) var(--sp-6);
  background: var(--color-bg-2); border-top: 1px solid var(--color-border);
}
.scrim {
  position: fixed; inset: 0; z-index: var(--z-modal); display: grid; place-items: center; padding: var(--sp-5);
  background: rgba(5,8,22,.6); backdrop-filter: blur(6px);
  animation: fade-in var(--dur-mid) var(--ease-out);
}
.modal {
  width: min(540px, 100%);
  max-height: 90vh;   /* fallback for browsers without dvh support */
  max-height: 90dvh;  /* accounts for mobile browser chrome (address bar/nav) so content never renders behind it */
  overflow: auto; -webkit-overflow-scrolling: touch;
  background: linear-gradient(180deg, var(--color-surface), var(--color-bg-2));
  border: var(--glass-border); border-radius: var(--r-xl); box-shadow: var(--shadow-4);
  padding: var(--sp-6); animation: pop-in var(--dur-mid) var(--ease-spring);
  position: relative;
}
/* Sticky so it stays reachable while a tall modal body scrolls under it.
   `float` keeps it out of the flow's top-left without overlapping the first
   heading, which a positioned corner button would do on narrow screens. */
.modal-close {
  position: sticky; top: 0; float: right; z-index: 1;
  width: 32px; height: 32px; margin: -.35rem -.35rem .1rem .5rem;
  display: grid; place-items: center; flex-shrink: 0;
  border: 1px solid var(--color-border); border-radius: 50%;
  background: var(--color-surface-2); color: var(--color-text-muted);
  font-size: 1.35rem; line-height: 1; cursor: pointer;
  transition: color var(--dur-fast), background var(--dur-fast), transform var(--dur-fast);
}
.modal-close:hover { color: var(--color-text); background: var(--color-surface); transform: scale(1.06); }

/* ------------------------------- Toasts ---------------------------------- */
.toast-host { position: fixed; top: 80px; right: 20px; z-index: var(--z-toast); display: flex; flex-direction: column; gap: var(--sp-3); max-width: 340px; }
.toast {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4);
  background: var(--glass-bg); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  border: var(--glass-border); border-left: 4px solid var(--color-primary); border-radius: var(--r-md);
  box-shadow: var(--shadow-3); animation: slide-in-right var(--dur-mid) var(--ease-spring);
}
.toast.success { border-left-color: var(--color-success); }
.toast.warning { border-left-color: var(--color-warning); }
.toast.danger  { border-left-color: var(--color-danger); }
.toast.xp { border-left-color: var(--color-gold); }
.toast .toast-icon { font-size: 1.2rem; }
.toast.leaving { animation: slide-out-right var(--dur-mid) var(--ease-out) forwards; }

/* ------------------------------- Forms ----------------------------------- */
.field { display: flex; flex-direction: column; gap: var(--sp-2); }
.field label { font-size: var(--fs-sm); font-weight: 600; color: var(--color-text-muted); }
.input, .select {
  padding: .8rem 1rem; border-radius: var(--r-md);
  background: var(--color-surface-2); border: 1px solid var(--color-border); color: var(--color-text);
  transition: border-color var(--dur-mid), box-shadow var(--dur-mid);
}
.input::placeholder { color: var(--color-text-faint); }
.input:focus, .select:focus { outline: none; border-color: var(--color-primary); box-shadow: var(--glow-primary); }
.field-error { color: var(--color-danger); font-size: var(--fs-xs); }
.input.invalid { border-color: var(--color-danger); }

/* Schedule option radio — a 3-way "when to play" choice (start now / schedule
   flexible / schedule strict) styled as icon + title/description cards with a
   custom radio dot. The strict/flexible cards each carry their own nested
   datetime-local input, dimmed and disabled until their own radio is picked
   (real .disabled, toggled in JS — see openDuelModal/openMeleeModal — not
   just a visual state, so an inactive card's time can't be submitted). The
   whole card highlights via :has() when its radio is the checked one. */
.option-radio { display: flex; align-items: flex-start; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md); background: var(--tint-1); border: 1px solid var(--color-border); cursor: pointer; transition: background var(--dur-fast), border-color var(--dur-fast); }
.option-radio:hover { background: var(--tint-2); }
.option-radio:has(input:checked) { border-color: var(--color-primary); background: rgba(91,108,255,.08); }
.option-radio input[type="radio"] { position: absolute; opacity: 0; width: 0; height: 0; }
.option-radio-dot { flex-shrink: 0; width: 20px; height: 20px; margin-top: .1rem; border-radius: 50%; border: 2px solid var(--color-border); position: relative; transition: border-color var(--dur-fast); }
.option-radio-dot::after { content: ""; position: absolute; inset: 3px; border-radius: 50%; background: var(--grad-brand); transform: scale(0); transition: transform var(--dur-fast) var(--ease-spring); }
.option-radio input:checked ~ .option-radio-dot { border-color: var(--color-primary); }
.option-radio input:checked ~ .option-radio-dot::after { transform: scale(1); }
.option-radio input:focus-visible ~ .option-radio-dot { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.option-radio-icon { font-size: 1.2rem; flex-shrink: 0; }
.option-radio-body { display: flex; flex-direction: column; gap: .3rem; min-width: 0; flex: 1; }
.option-radio-title { font-weight: 700; font-size: var(--fs-sm); }
.option-radio-desc { font-size: var(--fs-xs); color: var(--color-text-muted); }
.option-radio-time { width: 100%; }
.option-radio-time:disabled { opacity: .4; cursor: not-allowed; }
.schedule-card { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-4); border-radius: var(--r-lg); background: var(--tint-1); border: 1px solid var(--color-border); }
.schedule-card-head { font-size: var(--fs-sm); font-weight: 700; }

/* ----------------------------- App header -------------------------------- */
.app-header {
  position: sticky; top: 0; z-index: var(--z-header);
  background: var(--chrome-bg); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--color-border);
}
.app-header .header-inner { display: flex; align-items: center; gap: var(--sp-5); height: 66px; }
.brand { display: flex; align-items: center; gap: var(--sp-2); font-family: var(--font-display); font-weight: 800; font-size: var(--fs-md); }
.brand .brand-mark {
  width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center;
  background: var(--grad-brand); box-shadow: var(--glow-primary); font-size: 1.1rem;
}
.brand .brand-mark::after { content: "L"; color: #fff; font-weight: 800; }
.nav-links { display: flex; align-items: center; gap: var(--sp-2); }
.nav-link {
  padding: .5rem .85rem; border-radius: var(--r-md); font-size: var(--fs-sm); font-weight: 600;
  color: var(--color-text-muted); transition: color var(--dur-fast), background var(--dur-fast);
}
.nav-link:hover { color: var(--color-text); background: var(--tint-2); }
.nav-link.active { color: var(--color-text); background: rgba(91,108,255,.14); box-shadow: inset 0 0 0 1px rgba(91,108,255,.3); }
.header-user { display: flex; align-items: center; gap: var(--sp-3); flex-shrink: 0; }
.menu-toggle { display: none; }

/* ---------------------------- Bottom tab bar ------------------------------ */
/* Mobile-only, student-role nav — see mountBottomTabs() in ui.js. Hidden by
   default; shown (and the header's hamburger nav hidden) at the ≤720px
   breakpoint via body.has-tabbar below. */
.tab-bar {
  display: none;
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-header);
  background: var(--chrome-bg); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border-top: 1px solid var(--color-border);
  padding-bottom: env(safe-area-inset-bottom);
}
.tab-item {
  position: relative; flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .15rem; padding: .5rem 0; color: var(--color-text-muted); font-size: 10px; font-weight: 600;
  transition: color var(--dur-fast);
}
.tab-item .tab-icon { font-size: 1.3rem; line-height: 1; }
.tab-item.active { color: var(--color-text); }
.tab-item.active::before { content: ""; position: absolute; top: 0; left: 25%; right: 25%; height: 2px; border-radius: var(--r-pill); background: var(--color-primary); }
.tab-badge {
  position: absolute; top: 2px; right: calc(50% - 22px); min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: var(--r-pill); background: var(--color-danger); color: #fff; font-size: 9px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; line-height: 1; box-shadow: 0 0 0 2px var(--color-bg);
}

/* ------------------------------ Notifications ----------------------------- */
.notif-bell { position: relative; }
.notif-badge {
  position: absolute; top: 2px; right: 2px; min-width: 16px; height: 16px; padding: 0 3px;
  border-radius: var(--r-pill); background: var(--color-danger); color: #fff; font-size: 10px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; line-height: 1; box-shadow: 0 0 0 2px var(--color-bg);
}
.notif-badge[hidden] { display: none; } /* author `display:flex` above would otherwise beat the UA [hidden] rule */
.notif-panel {
  position: fixed; z-index: var(--z-modal); width: min(360px, 92vw); max-height: min(480px, 70vh);
  background: linear-gradient(180deg, var(--color-surface), var(--color-bg-2)); border: var(--glass-border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-4); overflow: hidden; display: flex; flex-direction: column;
  animation: pop-in var(--dur-mid) var(--ease-spring);
}
.notif-panel-head { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--color-border); font-weight: 700; font-size: var(--fs-sm); flex-shrink: 0; }
.notif-panel-head button { background: none; border: none; color: var(--color-primary-300); font-size: var(--fs-xs); cursor: pointer; font-weight: 600; padding: 0; }
.notif-panel-head button:hover { text-decoration: underline; }
.notif-panel-list { overflow-y: auto; -webkit-overflow-scrolling: touch; }
.notif-item {
  position: relative; display: flex; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4) var(--sp-3) calc(var(--sp-4) + 12px);
  text-decoration: none; color: inherit; border-bottom: 1px solid var(--color-glass-hi);
  /* pan-y keeps vertical scrolling native while horizontal drags are ours */
  touch-action: pan-y; background: var(--color-surface);
  transition: background var(--dur-fast), transform var(--dur-mid) var(--ease-out), opacity var(--dur-mid);
}
/* While a finger is down the row must track it exactly — no easing. */
.notif-item.swiping { transition: background var(--dur-fast); }
/* The "dismiss" affordance revealed as the row slides away. */
.notif-swipe-wrap { position: relative; overflow: hidden; }
.notif-swipe-wrap::after {
  content: "Dismiss"; position: absolute; inset: 0 var(--sp-4) 0 auto; display: flex; align-items: center;
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--color-danger); pointer-events: none;
}
.notif-item:last-child { border-bottom: none; }
.notif-item:hover { background: var(--tint-2); }
.notif-item.unread { background: rgba(91,108,255,.08); }
.notif-item.unread::before { content: ""; position: absolute; left: var(--sp-2); top: 1.15rem; width: 6px; height: 6px; border-radius: 50%; background: var(--color-primary); }
.notif-item-icon { font-size: 1.2rem; flex-shrink: 0; }
.notif-item-body { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.notif-item-title { font-weight: 700; font-size: var(--fs-sm); }
.notif-item-text { font-size: var(--fs-xs); color: var(--color-text-muted); }
.notif-item-time { font-size: var(--fs-xs); color: var(--color-text-faint); margin-top: .1rem; }
.notif-item-kickoff { font-size: var(--fs-xs); color: var(--color-text-muted); margin-top: .15rem; }
.notif-item-actions { display: flex; gap: .4rem; margin-top: .4rem; }
.notif-item-actions .btn { padding: .3rem .7rem; font-size: var(--fs-xs); }
.notif-empty { padding: var(--sp-5); text-align: center; color: var(--color-text-muted); font-size: var(--fs-sm); }
@media (max-width: 480px) {
  .notif-panel { position: fixed; top: 70px !important; right: var(--sp-3) !important; left: var(--sp-3); width: auto; }
}

/* ------------------------------ Footer ----------------------------------- */
.app-footer { border-top: 1px solid var(--color-border); background: var(--color-bg-2); padding-block: var(--sp-6); margin-top: var(--sp-10); }
.footer-social { width: 42px; height: 42px; border-radius: 50%; display: grid; place-items: center; font-size: 1.15rem; text-decoration: none; color: var(--color-text); background: var(--color-glass); border: 1px solid var(--color-glass-hi); transition: transform .12s ease, border-color .12s ease; }
.footer-social:hover { transform: translateY(-2px); border-color: var(--color-primary); }
.footer-cols { display: grid; grid-template-columns: 1.5fr repeat(3, 1fr); gap: var(--sp-6); }
.footer-cols h4 { font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: .08em; color: var(--color-text-muted); margin-bottom: var(--sp-3); }
.footer-cols a { display: block; padding: .25rem 0; color: var(--color-text-muted); font-size: var(--fs-sm); }
.footer-cols a:hover { color: var(--color-text); }

/* ------------------------------ Badges ----------------------------------- */
.badge-tile {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); text-align: center;
  padding: var(--sp-4); border-radius: var(--r-lg); background: var(--tint-1); border: 1px solid var(--color-border);
  transition: transform var(--dur-mid) var(--ease-spring), box-shadow var(--dur-mid);
}
.badge-tile:hover { transform: translateY(-4px); }
.badge-medal { width: 56px; height: 56px; border-radius: 50%; display: grid; place-items: center; font-size: 1.6rem; }
.badge-medal.bronze { background: radial-gradient(circle at 30% 30%, #d8a47f, #8a5a3b); box-shadow: 0 0 18px rgba(200,130,80,.4); }
.badge-medal.silver { background: radial-gradient(circle at 30% 30%, #eef2f7, #97a3b6); box-shadow: 0 0 18px rgba(200,210,230,.4); }
.badge-medal.gold   { background: radial-gradient(circle at 30% 30%, #ffe7a0, #d9a22e); box-shadow: var(--glow-gold); }
.badge-medal.teal   { background: radial-gradient(circle at 30% 30%, #9af2e6, #14b8a6); box-shadow: var(--glow-teal); }
.badge-tile.locked { opacity: .4; filter: grayscale(.7); }
.badge-tile .badge-name { font-weight: 700; font-size: var(--fs-sm); }
.badge-tile .badge-desc { font-size: var(--fs-xs); color: var(--color-text-muted); }

/* --------------------------- Review accordion ---------------------------- */
.review-item { border: 1px solid var(--color-border); border-radius: var(--r-lg); overflow: hidden; background: var(--tint-1); }
.review-item.correct { border-left: 4px solid var(--color-success); }
.review-item.wrong { border-left: 4px solid var(--color-danger); }
.review-head { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4); width: 100%; text-align: left; }
.review-head .rev-q { flex: 1; font-weight: 600; }
.review-body { padding: 0 var(--sp-4) var(--sp-4); display: grid; gap: var(--sp-3); }
.review-answer { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-3); border-radius: var(--r-md); font-size: var(--fs-sm); }
.review-answer.yours-wrong { background: rgba(251,94,109,.1); }
.review-answer.correct-ans { background: rgba(52,211,153,.12); }
.review-explain { font-size: var(--fs-sm); color: var(--color-text-muted); background: var(--tint-1); border-radius: var(--r-md); padding: var(--sp-3); border: 1px solid var(--color-border); }
/* Sticky "back to results" bar — same chrome treatment as .app-header, sits
   flush beneath it (top: 66px = header height) so it reads as one continuous
   nav surface while the question list scrolls underneath. */
.review-sticky-bar { position: sticky; top: 66px; z-index: 5; background: var(--chrome-bg); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border-bottom: 1px solid var(--color-border); }
.review-sticky-bar-inner { padding-block: .6rem; }
/* Bookmark ribbon icon — outline when unsaved, solid fill once bookmarked.
   Uses currentColor so it inherits the button's own text color (btn-ghost's
   neutral text vs. btn-gold's dark-on-gold), same as the emoji it replaced. */
.bookmark-icon { display: block; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.bookmark-icon.filled { fill: currentColor; }
/* Report — text-only, no icon; a quiet ghost link that only turns danger-red
   on hover so it doesn't compete visually with the bookmark button. */
.report-link { background: none; border: none; padding: .3rem .6rem; border-radius: var(--r-sm); font-size: var(--fs-xs); font-weight: 600; color: var(--color-text-muted); cursor: pointer; transition: color var(--dur-fast), background var(--dur-fast); }
.report-link:hover { color: var(--color-danger); background: rgba(251,94,109,.1); }

/* ------------------------------- Tables ---------------------------------- */
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.table th { text-align: left; padding: var(--sp-3); color: var(--color-text-muted); font-weight: 600; border-bottom: 1px solid var(--color-border); font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .05em; }
.table td { padding: var(--sp-3); border-bottom: 1px solid var(--color-border); }
.table tr:last-child td { border-bottom: none; }
.table-hover tbody tr:hover { background: var(--tint-1); }

/* -------------------------------- Tabs ----------------------------------- */
.tabs { display: flex; width: 100%; max-width: 100%; gap: var(--sp-1); padding: var(--sp-1); border-radius: var(--r-pill); background: var(--color-surface-2); border: 1px solid var(--color-border); }
.tab { flex: 1; min-width: 0; padding: .5rem .35rem; border-radius: var(--r-pill); font-size: clamp(.75rem, 3.4vw, var(--fs-sm)); font-weight: 600; color: var(--color-text-muted); transition: all var(--dur-fast); text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tab.active { background: var(--grad-brand); color: #fff; }

/* ------------------------------- Misc ------------------------------------ */
.divider { height: 1px; background: var(--color-border); margin-block: var(--sp-4); }
.skeleton { background: linear-gradient(90deg, var(--tint-2), var(--tint-4), var(--tint-2)); background-size: 200% 100%; animation: shimmer 1.4s infinite; border-radius: var(--r-md); }
.dot-sep::before { content: "•"; margin: 0 .5rem; color: var(--color-text-faint); }
.float-card { animation: float 5s ease-in-out infinite; }

/* ------------------------------ Animation -------------------------------- */
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop-in { from { opacity: 0; transform: scale(.94) translateY(8px); } to { opacity: 1; transform: scale(1) translateY(0); } }
@keyframes pop { 0% { transform: scale(.6); opacity: 0; } 60% { transform: scale(1.15); } 100% { transform: scale(1); opacity: 1; } }
@keyframes rise { from { transform: scaleY(0); opacity: 0; } to { transform: scaleY(1); opacity: 1; } }
@keyframes float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
@keyframes pulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.05); } }
@keyframes pulse-dot { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
@keyframes pulse-flame { 0%,100% { transform: scale(1) rotate(-3deg); } 50% { transform: scale(1.18) rotate(3deg); } }
@keyframes shake { 0%,100% { transform: translateX(0); } 20% { transform: translateX(-7px); } 40% { transform: translateX(7px); } 60% { transform: translateX(-5px); } 80% { transform: translateX(5px); } }
@keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
@keyframes slide-in-right { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: translateX(0); } }
@keyframes slide-out-right { to { opacity: 0; transform: translateX(40px); } }
@keyframes count-pop { 0% { transform: scale(1); } 50% { transform: scale(1.3); color: var(--color-gold); } 100% { transform: scale(1); } }
@keyframes spin { to { transform: rotate(360deg); } }
.animate-pop { animation: pop .4s var(--ease-spring) both; }
.animate-rise-in { animation: pop-in .5s var(--ease-out) both; }
.stagger > * { animation: pop-in .5s var(--ease-out) both; }
.stagger > *:nth-child(2) { animation-delay: .06s; }
.stagger > *:nth-child(3) { animation-delay: .12s; }
.stagger > *:nth-child(4) { animation-delay: .18s; }
.stagger > *:nth-child(5) { animation-delay: .24s; }
.stagger > *:nth-child(6) { animation-delay: .30s; }

/* ----------------------------- Responsive -------------------------------- */
@media (max-width: 940px) {
  .footer-cols { grid-template-columns: 1fr 1fr; }
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 720px) {
  .nav-links { display: none; }
  .nav-links.open {
    display: flex; flex-direction: column; position: absolute; top: 66px; left: 0; right: 0;
    padding: var(--sp-4); background: var(--chrome-bg-solid); border-bottom: 1px solid var(--color-border); gap: var(--sp-1);
  }
  .menu-toggle { display: grid; }
  /* Students get the bottom tab bar instead of the hamburger nav — see
     mountBottomTabs() in ui.js, which adds this class when it mounts. */
  body.has-tabbar .tab-bar { display: flex; }
  body.has-tabbar .menu-toggle, body.has-tabbar .nav-links, body.has-tabbar .nav-links.open { display: none; }
  body.has-tabbar { padding-bottom: calc(64px + env(safe-area-inset-bottom)); }
  /* The PWA install pill (web/js/pwa.js) floats at the same bottom edge —
     push it up above the tab bar so the two don't overlap. */
  body.has-tabbar .pwa-install { bottom: calc(78px + env(safe-area-inset-bottom)) !important; }
  .section { padding-block: var(--sp-8); }
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .option-grid { grid-template-columns: 1fr; }
  /* Phones stack the options, so four of them at desktop padding ran ~390px on
     their own. Trimmed to what a comfortable tap target actually needs (the
     card stays well above the 44px accessibility floor) — the answer text
     itself is untouched, since squinting at it is a comprehension problem. */
  .option-card { padding: var(--sp-3) var(--sp-4); gap: var(--sp-3); }
  .option-card .opt-key { width: 30px; height: 30px; font-size: var(--fs-sm); }
  .option-grid { gap: var(--sp-3); }
  .quiz-body { gap: var(--sp-4); }
  /* no bottom padding: the pinned bar below owns the space beneath it, so
     scrolling to the end lands it flush with the bottom of the viewport */
  .quiz-stage { padding-block: var(--sp-4) 0; }
  .quiz-stem { font-size: clamp(1.15rem, 4.6vw, 1.5rem); }
  /* Pin Submit to the bottom of the viewport. `sticky` (not `fixed`) keeps the
     bar in normal flow, so it reserves its own height and costs the options
     nothing: with a short question it simply sits under the last option, as an
     ordinary button would. Mid-scroll the options pass beneath it — hence the
     opaque backdrop — and scrolling to the end returns it to its natural place
     at the very bottom of the page, where it covers nothing. Phones only: on a
     desktop the round already fits, and a pinned bar there just floats in the
     middle of the page with dead space beneath it. */
  .quiz-actionbar {
    position: sticky; bottom: 0; z-index: 6;
    padding-block: var(--sp-3);
    padding-bottom: calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
    margin-inline: calc(var(--sp-5) * -1); padding-inline: var(--sp-5);
    background: var(--chrome-bg); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
    border-top: 1px solid var(--color-border);
  }
  /* Bare .grid (dashboard/profile/friends 2-up panels) gets its column count
     from an inline style, which a normal media-query rule can't outrank —
     force it to stack at the same breakpoint every other multi-column layout does. */
  .grid[style*="grid-template-columns"] { grid-template-columns: 1fr !important; }
  .podium-col { width: 100px; }
  .podium-col.p1 .podium-stand { height: 150px; }
  .display-1 { font-size: clamp(2rem, 9vw, 2.6rem); }
}
@media (max-width: 600px) {
  /* The streak/XP badges and the signed-in name are shown elsewhere (welcome
     banner, profile) — on a phone-width header they're what forces the whole
     page to scroll sideways, so drop them and keep just the avatar + menu. */
  .header-user .chip { display: none; }
  .header-user #userMenuBtn .fw-700 { display: none; }
  .header-user .btn-sm { padding-inline: .6rem; }
  .brand span:not(.brand-mark) { font-size: var(--fs-sm); }
}
@media (max-width: 480px) {
  .container { padding-inline: var(--sp-4); }
  .footer-cols { grid-template-columns: 1fr; }
  .toast-host { right: 12px; left: 12px; max-width: none; }
  .hud { flex-wrap: wrap; }
  /* match the narrower container padding above */
  .quiz-actionbar { margin-inline: calc(var(--sp-4) * -1); padding-inline: var(--sp-4); }
  .hud-pill { padding: .35rem .7rem; font-size: var(--fs-sm); }
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
  .float-card, .streak-flame, .podium-crown { animation: none !important; }
}

/* ============================================================================
   PAGE MODULES — feature-scoped classes composed by individual pages.
   ========================================================================== */

/* ------------------------------- Charts ---------------------------------- */
@keyframes lcDraw { to { stroke-dashoffset: 0; } }
@keyframes radarPop { from { transform: scale(.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.bars { display: flex; align-items: flex-end; gap: var(--sp-3); height: 200px; padding-top: var(--sp-4); }
.bar-col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); height: 100%; justify-content: flex-end; }
.bar-track { width: 100%; max-width: 46px; flex: 1; background: var(--color-surface-2); border-radius: var(--r-sm); display: flex; align-items: flex-end; overflow: hidden; }
.bar-fill { width: 100%; background: var(--grad-aurora); border-radius: var(--r-sm) var(--r-sm) 0 0; transition: height 1s var(--ease-out); }
.bar-label { font-size: var(--fs-xs); color: var(--color-text-muted); text-align: center; }
.bar-val { font-size: var(--fs-xs); font-weight: 700; }
.donut-wrap { display: flex; align-items: center; gap: var(--sp-5); flex-wrap: wrap; justify-content: center; }
.donut-legend { display: flex; flex-direction: column; gap: var(--sp-2); }
.heatmap { display: grid; grid-template-columns: repeat(14, 1fr); gap: 5px; }
.hm-cell { display: inline-block; width: 100%; aspect-ratio: 1; min-width: 12px; border-radius: 3px; }

/* Skill mastery bar (profile) */
.skill-row { display: grid; grid-template-columns: 130px 1fr 96px; align-items: center; gap: var(--sp-3); }
.skill-band { font-size: var(--fs-xs); font-weight: 700; }

/* ----------------------------- Quiz stage -------------------------------- */
.quiz-stage { min-height: calc(100vh - 66px); display: flex; flex-direction: column; gap: var(--sp-5); padding-block: var(--sp-6); position: relative; }
.quiz-hud-bar { position: sticky; top: 66px; z-index: 5; }
.quiz-hud-bar .hud { justify-content: center; gap: var(--sp-3); flex-wrap: wrap; }
.quiz-body { flex: 1; display: flex; flex-direction: column; align-items: center; gap: var(--sp-5); max-width: 820px; margin-inline: auto; width: 100%; }

/* Countdown + Submit on one row. On a roomy screen this is just an ordinary
   row under the last option — the pinning below is a phone-only measure. */
.quiz-actionbar { width: 100%; display: flex; align-items: center; gap: var(--sp-4); }
.quiz-actionbar .quiz-submit-wrap { flex: 1; min-width: 0; }
.quiz-timer { display: grid; place-items: center; flex: 0 0 auto; }
/* the ring is 56px in the bar, so the seconds inside it can't wear --fs-xl */
.quiz-actionbar .timer-ring .timer-num { font-size: var(--fs-md); }
.quiz-stem { font-size: clamp(1.4rem, 3.5vw, 2.1rem); max-width: 28ch; line-height: var(--lh-snug); }
/* the instruction lead ("Complete the conversation") sits on its own line in a
   quieter accent colour; the actual question sits below in the main text colour. */
.quiz-lead { display: block; font-size: clamp(.8rem, 1.6vw, .95rem); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--color-teal); margin-bottom: var(--sp-3); line-height: 1.4; }
.quiz-stem-body { display: block; color: var(--color-text); }
.rev-lead { color: var(--color-teal); font-weight: 600; font-size: .85em; }
/* fill-in-the-blank (typed answer) question */
.fill-form { display: flex; flex-direction: column; gap: var(--sp-3); align-items: center; width: 100%; max-width: 460px; margin-inline: auto; }
.fill-form .fill-input { width: 100%; text-align: center; font-size: 1.2rem; font-family: var(--font-display); }
.fill-form .btn { width: 100%; }
.fill-input.input-correct { border-color: var(--color-success); box-shadow: 0 0 0 3px rgba(52, 211, 153, .25); }
.fill-input.input-wrong { border-color: var(--color-danger); box-shadow: 0 0 0 3px rgba(251, 94, 109, .25); }
.fill-result { min-height: 1.4rem; font-size: .95rem; }
/* listening (transcription) question — a full sentence reads better left-aligned in the body font than fill's centered single-word display style */
.fill-form textarea.listening-input { text-align: left; font-size: 1rem; font-family: var(--font-body); resize: vertical; min-height: 4.5rem; }
.listening-audio { width: 100%; max-width: 420px; }
.fill-ok { color: var(--color-success); font-weight: 700; }
.fill-no { color: var(--color-danger); font-weight: 700; }
.quiz-media { min-height: 0; }
.quiz-options { width: 100%; }
.quiz-options.locked .option-card { pointer-events: none; }
.quiz-overlay {
  position: fixed; inset: 66px 0 0 0; z-index: 50; display: grid; place-items: center; padding: var(--sp-5);
  background: var(--chrome-bg-solid); backdrop-filter: blur(10px); animation: fade-in var(--dur-mid);
}
.countdown-num { font-family: var(--font-display); font-weight: 800; font-size: clamp(4rem, 16vw, 9rem); background: var(--grad-aurora); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.lb-overlay { width: min(560px, 100%); }

/* ------------------------------ Results ---------------------------------- */
.results-hero { position: relative; overflow: hidden; }
.confetti-canvas { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; }
/* Lifts the hero's real content above the confetti — but must exclude the
   canvas itself, or it wins on source order and drops the overlay back into
   the flow, where its intrinsic 150px shoves the whole page down. */
.results-hero > *:not(.confetti-canvas) { position: relative; z-index: 2; }
.breakdown-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--sp-4); }
.reward-card { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4); border-radius: var(--r-lg); background: rgba(245,192,74,.08); border: 1px solid rgba(245,192,74,.3); animation: pop-in .5s var(--ease-spring) both; }

/* ------------------------------- Landing --------------------------------- */
.hero { position: relative; padding-top: var(--sp-10); padding-bottom: var(--sp-12); overflow: hidden; }
.hero-grid { display: grid; grid-template-columns: 1.05fr .95fr; gap: var(--sp-8); align-items: center; }
.hero-badges { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.hero-art { position: relative; min-height: 380px; }
.quiz-card-mock {
  position: absolute; width: 270px; padding: var(--sp-4); border-radius: var(--r-lg);
  background: var(--glass-bg); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  border: var(--glass-border); box-shadow: var(--shadow-4);
}
.qcm-1 { top: 10px; right: 30px; }
.qcm-2 { top: 150px; left: 0; animation-delay: .6s; }
.qcm-3 { bottom: 0; right: 70px; animation-delay: 1.2s; }
.live-counter { display: inline-flex; align-items: center; gap: var(--sp-2); }
.feature-card { padding: var(--sp-5); border-radius: var(--r-lg); background: var(--tint-1); border: 1px solid var(--color-border); transition: transform var(--dur-mid) var(--ease-out), border-color var(--dur-mid); }
.feature-card:hover { transform: translateY(-4px); border-color: rgba(91,108,255,.4); }
.feature-icon { width: 48px; height: 48px; border-radius: var(--r-md); display: grid; place-items: center; font-size: 1.5rem; background: rgba(91,108,255,.14); margin-bottom: var(--sp-3); }
.mode-card { padding: var(--sp-5); border-radius: var(--r-lg); background: var(--glass-bg); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); border: var(--glass-border); transition: transform var(--dur-mid) var(--ease-out), box-shadow var(--dur-mid); }
.mode-card:hover { transform: translateY(-5px); box-shadow: var(--glow-primary); }
.mode-icon { font-size: 1.8rem; }
.step { display: flex; gap: var(--sp-4); align-items: flex-start; }
.step-num { width: 40px; height: 40px; flex: 0 0 auto; border-radius: 50%; display: grid; place-items: center; font-family: var(--font-display); font-weight: 800; background: var(--grad-brand); }
.cat-grid { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: center; }

/* Pricing */
.pricing-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-5); align-items: stretch; }
.price-card { display: flex; flex-direction: column; gap: var(--sp-4); padding: var(--sp-6); border-radius: var(--r-xl); background: var(--tint-1); border: 1px solid var(--color-border); position: relative; }
.price-card.featured { border-color: rgba(91,108,255,.6); box-shadow: var(--glow-primary); background: linear-gradient(180deg, rgba(91,108,255,.12), var(--tint-1)); }
.price-card .price { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-2xl); }
.price-card ul { display: flex; flex-direction: column; gap: var(--sp-2); }
.price-card li { display: flex; gap: var(--sp-2); align-items: flex-start; font-size: var(--fs-sm); color: var(--color-text-muted); }
.price-card li::before { content: "✓"; color: var(--color-teal); font-weight: 800; }
.price-tag { position: absolute; top: -12px; right: 20px; }
.billing-toggle { display: inline-flex; align-items: center; gap: var(--sp-3); }
.switch { width: 48px; height: 26px; border-radius: var(--r-pill); background: var(--color-surface-2); border: 1px solid var(--color-border); position: relative; transition: background var(--dur-mid); }
.switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%; background: var(--grad-brand); transition: transform var(--dur-mid) var(--ease-spring); }
.switch.on { background: rgba(91,108,255,.3); } .switch.on::after { transform: translateX(22px); }

/* FAQ */
.faq-item { border-bottom: 1px solid var(--color-border); }
.faq-q { width: 100%; text-align: left; padding: var(--sp-4) 0; display: flex; justify-content: space-between; gap: var(--sp-3); font-weight: 600; }
.faq-a { padding-bottom: var(--sp-4); color: var(--color-text-muted); font-size: var(--fs-sm); }

/* ------------------------------ Lobby ------------------------------------ */
.lobby-grid { display: grid; grid-template-columns: 1.4fr .9fr; gap: var(--sp-5); align-items: start; }
.participant { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3); border-radius: var(--r-md); background: var(--tint-1); border: 1px solid var(--color-border); animation: pop-in .4s var(--ease-spring) both; }
.participant .ready { margin-left: auto; }
.rules-list li { display: flex; gap: var(--sp-2); padding: var(--sp-2) 0; border-bottom: 1px solid var(--color-border); }
.big-countdown { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-3xl); text-align: center; }

/* ------------------------- Dashboard helpers ----------------------------- */
.welcome-banner { position: relative; overflow: hidden; }
.welcome-banner::before { content: ""; position: absolute; inset: 0; background: var(--grad-hero-bg); opacity: .5; z-index: 0; }
.welcome-banner > * { position: relative; z-index: 1; }
.comp-card { display: flex; gap: var(--sp-4); align-items: center; padding: var(--sp-4); border-radius: var(--r-lg); background: var(--tint-1); border: 1px solid var(--color-border); transition: border-color var(--dur-mid), transform var(--dur-mid); }
.comp-card:hover { border-color: rgba(91,108,255,.4); transform: translateX(3px); }
.mini-flame { font-size: 2.2rem; }

/* ----------------------- Teacher / Admin tables -------------------------- */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--sp-4); }
.side-panel { display: grid; grid-template-columns: 280px 1fr; gap: var(--sp-5); align-items: start; }

@media (max-width: 940px) {
  .hero-grid, .lobby-grid, .side-panel { grid-template-columns: 1fr; }
  .hero-art { min-height: 320px; }
  .pricing-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .pricing-grid { grid-template-columns: 1fr; }
  .skill-row { grid-template-columns: 90px 1fr 60px; }
  .heatmap { grid-template-columns: repeat(10, 1fr); }
  .quiz-overlay { inset: 56px 0 0 0; }
}

/* ------------------------------- Community chat --------------------------- */
.community-card { transition: transform var(--dur-mid), border-color var(--dur-mid); }
.community-card:hover { transform: translateY(-3px); border-color: rgba(91,108,255,.4); }

.chat-shell {
  display: flex; flex-direction: column;
  height: calc(100vh - 66px - var(--sp-5) * 2);
  height: calc(100dvh - 66px - var(--sp-5) * 2); /* mobile browser chrome accounted for, same fix as the modal's dvh use */
  min-height: 420px;
  background: linear-gradient(180deg, var(--color-surface) 0%, var(--color-surface-2) 140%);
  border: 1px solid var(--color-border); border-radius: var(--r-lg); box-shadow: var(--shadow-3);
  overflow: hidden;
}
.chat-header { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--color-border); flex-shrink: 0; }
.chat-header-meta { flex: 1; min-width: 0; }
.chat-header-meta .fw-700, .chat-header-meta .text-xs { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-body { flex: 1; display: grid; grid-template-columns: 1fr 260px; min-height: 0; }
.chat-scroll { overflow-y: auto; padding: var(--sp-4); display: flex; flex-direction: column; -webkit-overflow-scrolling: touch; scroll-behavior: smooth; }
.chat-sidebar {
  border-left: 1px solid var(--color-border); padding: var(--sp-4); background: var(--tint-1);
  display: flex; flex-direction: column; min-height: 0; overflow: hidden;
}
.chat-sidebar h4 { font-size: var(--fs-sm); color: var(--color-text-muted); margin-bottom: var(--sp-3); }
.chat-play-row { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-4); flex-shrink: 0; }
.chat-play-row .btn { flex: 1; }
/* Only the member rows scroll — search, play buttons and Leave stay put no
   matter how long the roster gets (large communities were the whole reason
   for this: "Leave" used to sit below every member, and there was no way to
   find someone without scrolling past everyone ahead of them). */
.chat-member-list { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.chat-member-row { display: flex; align-items: center; gap: var(--sp-2); padding: .35rem 0; }
.chat-member-info { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; flex: 1; cursor: pointer; }
.chat-member-row span.name { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--fs-sm); }
.chat-duel-btn {
  flex-shrink: 0; background: none; border: 1px solid var(--color-border); border-radius: var(--r-sm);
  padding: .25rem .45rem; font-size: .85rem; cursor: pointer; line-height: 1;
  transition: background var(--dur-fast), border-color var(--dur-fast);
}
.chat-duel-btn:hover { background: var(--tint-4); border-color: var(--color-border-strong); }
.chat-input-bar { display: flex; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--color-border); background: var(--tint-1); flex-shrink: 0; }
.chat-input-bar .input { flex: 1; }
.chat-scrim { display: none; position: fixed; inset: 0; z-index: calc(var(--z-modal) - 1); background: rgba(5,8,22,.5); }

.msg-row { display: flex; gap: .55rem; max-width: 78%; margin-top: var(--sp-3); }
.msg-row.mine { align-self: flex-end; flex-direction: row-reverse; }
.msg-row.grouped { margin-top: 3px; }
.msg-row.grouped .msg-meta { display: none; }
.msg-row.grouped .avatar { visibility: hidden; }
.msg-col { display: flex; flex-direction: column; min-width: 0; }
.msg-row.mine .msg-col { align-items: flex-end; }
.msg-bubble {
  background: var(--color-surface-2); border: 1px solid var(--color-border);
  border-radius: var(--r-lg); border-top-left-radius: var(--r-sm);
  padding: .55rem .85rem; word-break: break-word; white-space: pre-wrap; font-size: var(--fs-sm); line-height: 1.4;
}
.msg-row.mine .msg-bubble { background: var(--grad-brand); color: #fff; border-color: transparent; border-top-left-radius: var(--r-lg); border-top-right-radius: var(--r-sm); }
.msg-meta { font-size: var(--fs-xs); color: var(--color-text-muted); margin-bottom: .2rem; padding-inline: .2rem; }
.msg-day-sep { text-align: center; margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-xs); color: var(--color-text-faint); }
.msg-day-sep:first-child { margin-top: 0; }
.msg-edited-tag { font-size: .7rem; color: var(--color-text-faint); font-style: italic; margin-left: .35rem; }

/* Always-visible (not hover-only — reactions/edit must work on touch too) but
   subtle action row under each bubble. */
.msg-actions-row { display: flex; gap: .6rem; margin-top: .2rem; padding-inline: .2rem; }
.msg-action-btn { background: none; border: none; padding: 0; font-size: .75rem; color: var(--color-text-faint); cursor: pointer; }
.msg-action-btn:hover { color: var(--color-text); }

.msg-reactions { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .35rem; }
.msg-reaction-chip {
  display: inline-flex; align-items: center; gap: .25rem; padding: .15rem .5rem; border-radius: var(--r-pill);
  background: var(--color-glass-hi); border: 1px solid var(--color-border); font-size: .75rem; cursor: pointer;
  transition: background var(--dur-fast), border-color var(--dur-fast);
}
.msg-reaction-chip:hover { background: var(--tint-4); }
.msg-reaction-chip.mine { background: rgba(91,108,255,.16); border-color: rgba(91,108,255,.4); color: var(--color-primary-300); }

.reaction-picker {
  position: absolute; z-index: var(--z-modal); display: flex; gap: .2rem; padding: .4rem;
  background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--r-pill); box-shadow: var(--shadow-3);
}
.reaction-picker button { background: none; border: none; font-size: 1.15rem; cursor: pointer; padding: .2rem; border-radius: var(--r-sm); line-height: 1; }
.reaction-picker button:hover { background: var(--tint-4); }

.msg-edit-box { display: flex; flex-direction: column; gap: .4rem; width: min(320px, 100%); }
.msg-edit-box textarea {
  width: 100%; resize: none; min-height: 2.4rem; max-height: 8rem; overflow-y: auto;
  background: var(--color-surface); border: 1px solid var(--color-primary); border-radius: var(--r-md);
  padding: .5rem .7rem; color: inherit; font: inherit; line-height: 1.4;
}
.msg-edit-actions { display: flex; gap: .5rem; justify-content: flex-end; }

/* auto-growing message composer — a textarea styled to look like the single-line
   .input it replaces, so Shift+Enter can insert a real newline (an <input>
   can never do that, regardless of key handling) */
.chat-input-bar textarea.input {
  resize: none; min-height: 2.6rem; max-height: 7.5rem; overflow-y: auto; line-height: 1.4; padding-top: .65rem; padding-bottom: .65rem;
}

@media (max-width: 720px) {
  .chat-body { grid-template-columns: 1fr; }
  .chat-sidebar {
    position: fixed; top: 0; right: 0; bottom: 0; width: min(300px, 82vw); z-index: var(--z-modal);
    transform: translateX(100%); transition: transform var(--dur-mid) var(--ease-out); box-shadow: var(--shadow-4);
    /* as a side-panel tint it only needs to read against the chat shell's own
       background — as a fixed mobile drawer it must be opaque on its own, or
       the header/messages behind it show through and collide with its text */
    background: linear-gradient(180deg, var(--color-surface) 0%, var(--color-surface-2) 140%);
  }
  .chat-sidebar.open { transform: translateX(0); }
  .chat-sidebar.open ~ .chat-scrim, .chat-scrim.open { display: block; }
  .msg-row { max-width: 88%; }
}
@media (max-width: 480px) {
  .chat-header { padding: var(--sp-2) var(--sp-3); gap: var(--sp-2); }
  .chat-header .btn-sm span.label { display: none; }
  .chat-scroll, .chat-input-bar { padding-inline: var(--sp-3); }
}
