/* ==========================================================================
   AscendSAT — view + question-content styles
   ========================================================================== */

/* ==========================================================================
   Rendered CollegeBoard question content
   ========================================================================== */

.qhtml { font-size: 16px; line-height: 1.62; color: var(--ink); }
.qhtml p { margin: 0 0 14px; }
.qhtml p:last-child { margin-bottom: 0; }
.qhtml ul, .qhtml ol { margin: 0 0 14px; padding-left: 24px; }
.qhtml li { margin-bottom: 5px; }
.qhtml em, .qhtml i { font-style: italic; }
.qhtml strong, .qhtml b { font-weight: 700; }
.qhtml sup { font-size: .74em; vertical-align: super; }
.qhtml sub { font-size: .74em; vertical-align: sub; }
.qhtml .sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.qhtml.stim { font-size: 16px; }
.qhtml.stem { font-size: 16.5px; font-weight: 500; margin: 14px 0 20px; }
.qhtml.rationale { font-size: 15px; color: var(--slate-700); }
.qhtml.qchoice-html { font-size: 15.5px; line-height: 1.5; }
.qhtml.qchoice-html p { margin: 0; }

/* Blank placeholder in "complete the text" items */
.qblank {
  display: inline-block;
  min-width: 76px;
  border-bottom: 2px solid var(--slate-400);
  vertical-align: baseline;
  color: transparent;
  margin: 0 2px;
}

/* MathML */
.qhtml math {
  font-size: 1.06em;
  font-family: "Latin Modern Math", "STIX Two Math", "Cambria Math", serif;
}
.qhtml p:has(> math:only-child) { text-align: center; margin: 18px 0; }
.qhtml math[display="block"] { display: block; margin: 16px auto; }

/* Figures */
.qfig-wrap {
  margin: 18px 0;
  display: flex;
  justify-content: center;
  overflow-x: auto;
}
.qfig {
  max-width: 100%;
  height: auto;
  max-height: 420px;
  background: #fff;
  border-radius: var(--r-sm);
}
.qfig text { font-family: var(--font-body) !important; }

/* Tables */
.qtable-wrap { overflow-x: auto; margin: 18px 0; }
.qtable {
  border-collapse: collapse;
  font-size: 14.5px;
  min-width: 260px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}
.qtable caption {
  caption-side: top;
  text-align: left;
  font-weight: 700;
  padding: 0 0 8px;
  font-size: 14px;
  color: var(--slate-700);
}
.qtable th, .qtable td {
  border: 1px solid var(--line);
  padding: 8px 14px;
  text-align: center;
}
.qtable th { background: var(--slate-50); font-weight: 700; color: var(--slate-700); }
.qtable tr:nth-child(even) td { background: #FCFDFE; }

/* Highlighter marks */
mark.hl {
  background: #FFF3A3;
  padding: 1px 0;
  border-radius: 2px;
  cursor: pointer;
  box-shadow: 0 0 0 1px rgba(217, 168, 8, .28);
}
mark.hl:hover { background: #FFE96B; }

/* ==========================================================================
   Session player
   ========================================================================== */

.sess { display: flex; flex-direction: column; min-height: 100vh; background: #fff; }

.sess-top {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 22px;
  border-bottom: 1px solid var(--line);
  background: #fff;
  position: sticky; top: 0; z-index: 30;
}
.sess-exit {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--slate-600);
  font-size: 13px; font-weight: 700;
  cursor: pointer;
  transition: var(--t);
}
.sess-exit:hover { background: var(--red-tint); border-color: var(--red); color: var(--red-dark); }
.sess-exit svg { width: 15px; height: 15px; }

.sess-id { min-width: 0; }
.sess-id .t { font-family: var(--font-head); font-weight: 700; font-size: 16px; line-height: 1.2; }
.sess-id .s { font-size: 12.5px; color: var(--ink-3); font-weight: 600; }

.sess-tools { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.sess-timer {
  font-size: 16px; font-weight: 800;
  color: var(--slate-700);
  min-width: 58px; text-align: center;
}
.sess-timerbtn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px 6px 10px;
  border: 1px solid var(--line);
  border-radius: var(--pill);
  background: var(--slate-50);
  cursor: pointer;
  color: var(--slate-500);
  transition: var(--t);
  margin-right: 4px;
}
.sess-timerbtn:hover { background: var(--slate-100); }
.sess-timerbtn.static { cursor: default; }
.sess-timerbtn.static:hover { background: var(--slate-50); }
.sess-timerbtn svg { width: 15px; height: 15px; }
/* Names the clock, so a stopwatch can't be misread as "time on the lesson". */
.sess-timerlbl {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
  margin-left: -2px;
}
@media (max-width: 720px) { .sess-timerlbl { display: none; } }

/* --- Stage --------------------------------------------------------------- */
/* align-items: stretch, explicitly — flexbox's own default here, but written
   out because something upstream (a reset, or just this browser's resolution
   of the `normal` default) was actually landing on `start`. Left implicit,
   the stimulus pane's grey background only ever reached as tall as its own
   text, so a short stimulus beside a long question left grey ending
   mid-page with plain white below it — looking exactly like the pane had
   been cut off, on every question short enough for it to show. */
.sess-stage { flex: 1; display: flex; align-items: stretch; overflow: hidden; }
.sess-pane { flex: 1; min-width: 0; overflow-y: auto; }
.sess-stage.split .sess-pane.stim { border-right: 1px solid var(--line); background: var(--slate-50); }
.pane-inner { max-width: 660px; margin: 0 auto; padding: 30px 34px 48px; }
.sess-stage:not(.split) .pane-inner { max-width: 780px; }
.sess-stage.hl-on .sess-pane { cursor: text; }

.q-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; }
.q-num {
  font-family: var(--font-head);
  font-size: 15px; font-weight: 700;
  color: var(--slate-900);
  padding-right: 4px;
}

/* --- Choices ------------------------------------------------------------- */
.choices { display: grid; gap: 11px; margin-top: 4px; }
.choice-row { display: flex; align-items: stretch; gap: 8px; }

.choice {
  flex: 1;
  display: flex;
  align-items: flex-start;
  gap: 13px;
  padding: 16px 18px;
  border: 2px solid var(--slate-200);
  border-radius: var(--r-md);
  background: #fff;
  text-align: left;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: border-color var(--t), background var(--t), transform .15s var(--ease-out), box-shadow .15s var(--ease-out);
}
.choice:hover { border-color: var(--blue); background: var(--blue-tint); box-shadow: var(--sh-xs); }
.choice:active { transform: scale(.985); transition-duration: .08s; }

.choice .letter {
  flex: none;
  width: 27px; height: 27px;
  border-radius: 50%;
  border: 2px solid var(--slate-300);
  display: grid; place-items: center;
  font-size: 13px; font-weight: 800;
  color: var(--slate-500);
  transition: var(--t);
  margin-top: 1px;
}
.choice:hover .letter { border-color: var(--blue); color: var(--blue-dark); }

.choice.sel { border-color: var(--blue); background: var(--blue-tint); }
.choice.sel .letter { background: var(--blue); border-color: var(--blue); color: #fff; }

.choice.correct { border-color: var(--green); background: var(--green-tint); }
.choice.correct .letter { background: var(--green); border-color: var(--green); color: #fff; }
.choice.wrong { border-color: var(--red); background: var(--red-tint); }
.choice.wrong .letter { background: var(--red); border-color: var(--red); color: #fff; }

.choice.crossed { opacity: .45; }
.choice.crossed .qhtml { text-decoration: line-through; }
.choice.crossed:hover { border-color: var(--slate-200); background: #fff; }

.choice .mark { width: 20px; height: 20px; flex: none; margin-left: auto; margin-top: 3px; }
.choice .mark.ok { color: var(--green-dark); }
.choice .mark.bad { color: var(--red-dark); }

.cross {
  flex: none;
  width: 34px;
  border: 1px dashed var(--slate-300);
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--slate-400);
  font-size: 12px; font-weight: 800;
  cursor: pointer;
  transition: var(--t);
}
.cross span { display: inline-block; text-decoration: line-through; }
.cross:hover { border-color: var(--red); color: var(--red); background: var(--red-tint); }

/* --- SPR ----------------------------------------------------------------- */
.spr { margin-top: 6px; }
.spr-hint { font-size: 13px; color: var(--ink-3); margin-bottom: 10px; }
.spr-input {
  max-width: 300px;
  font-size: 20px !important;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  padding: 14px 16px !important;
  text-align: center;
}
.spr-key {
  margin-top: 14px;
  padding: 12px 16px;
  background: var(--green-tint);
  border: 1px solid rgba(34, 197, 94, .35);
  border-radius: var(--r-sm);
  font-size: 14px;
  color: var(--green-dark);
}

/* --- Feedback ------------------------------------------------------------ */
.fb {
  margin-top: 22px;
  border-radius: var(--r);
  border: 1.5px solid;
  overflow: hidden;
  animation: rise .3s var(--ease) both;
}
.fb.ok  { border-color: rgba(34, 197, 94, .4);  background: var(--green-tint); }
.fb.bad { border-color: rgba(239, 68, 68, .35); background: var(--red-tint); }
.fb-hd {
  display: flex; align-items: center; gap: 9px;
  padding: 13px 17px;
  font-family: var(--font-head);
  font-weight: 700; font-size: 16px;
}
.fb.ok  .fb-hd { color: var(--green-dark); }
.fb.bad .fb-hd { color: var(--red-dark); }
.fb-hd svg { width: 21px; height: 21px; }
.fb-key { font-family: var(--font-body); font-size: 13px; font-weight: 700; opacity: .85; }
.fb-why { border-top: 1px solid rgba(15, 23, 42, .08); background: rgba(255, 255, 255, .65); }
.fb-why summary {
  padding: 12px 17px;
  cursor: pointer;
  font-size: 14px; font-weight: 700;
  color: var(--slate-700);
  user-select: none;
}
.fb-why summary:hover { color: var(--ink); }
.fb-why[open] summary { border-bottom: 1px solid rgba(15, 23, 42, .07); }
.fb-why .rationale { padding: 16px 17px; }

/* --- Footer -------------------------------------------------------------- */
.sess-foot {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 13px 22px;
  border-top: 1px solid var(--line);
  background: #fff;
  position: sticky; bottom: 0;
}
.sess-bar { flex: 1; min-width: 60px; }

/* --- Navigator ----------------------------------------------------------- */
.navgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(46px, 1fr));
  gap: 9px;
}
.nav-cell {
  aspect-ratio: 1;
  border: 2px solid var(--slate-200);
  border-radius: var(--r-sm);
  background: #fff;
  font-size: 14px; font-weight: 700;
  color: var(--slate-500);
  cursor: pointer;
  touch-action: manipulation;
  transition: border-color var(--t), color var(--t), background var(--t), transform .15s var(--ease-out);
  position: relative;
}
.nav-cell:hover { border-color: var(--blue); color: var(--blue-dark); transform: translateY(-1px); }
.nav-cell:active { transform: translateY(0) scale(.9); transition-duration: .08s; }
.nav-cell.filled { background: var(--blue-tint); border-color: var(--blue); color: var(--blue-dark); }
.nav-cell.ok  { background: var(--green-tint); border-color: var(--green); color: var(--green-dark); }
.nav-cell.bad { background: var(--red-tint); border-color: var(--red); color: var(--red-dark); }
.nav-cell.now { outline: 3px solid rgba(0, 166, 255, .35); outline-offset: 1px; }
.nav-cell.flag::after {
  content: ""; position: absolute; top: -4px; right: -4px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--amber); border: 2px solid #fff;
}
.navlegend { display: flex; gap: 18px; margin-bottom: 16px; font-size: 12.5px; color: var(--ink-2); }
.navlegend span { display: inline-flex; align-items: center; gap: 6px; }
.navlegend .k { width: 13px; height: 13px; border-radius: 4px; border: 2px solid var(--slate-300); }
.navlegend .k.filled { background: var(--blue-tint); border-color: var(--blue); }
.navlegend .k.flag { background: var(--amber); border-color: var(--amber); }
.navlegend .k.now { border-color: var(--blue); outline: 2px solid rgba(0,166,255,.3); }

/* --- Results ------------------------------------------------------------- */
.results { flex: 1; display: grid; place-items: start center; padding: 40px 20px 80px; background: var(--bg); }
.results-card {
  width: min(760px, 100%);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh);
  padding: 30px;
}
.results-hd { display: flex; align-items: center; gap: 24px; margin-bottom: 24px; }
.results-hd h2 { font-size: 27px; margin: 2px 0 4px; }

.results-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: 26px;
}
.rstat {
  background: var(--slate-50);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 14px;
  text-align: center;
}
.rstat .v {
  font-family: var(--font-head);
  font-size: 25px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.rstat .k { font-size: 12px; color: var(--ink-2); font-weight: 600; margin-top: 2px; }
.rstat.green .v { color: var(--green-dark); }
.rstat.red   .v { color: var(--red-dark); }
.rstat.blue  .v { color: var(--blue-dark); }

.results-list { display: grid; gap: 7px; max-height: 340px; overflow-y: auto; padding-right: 4px; }
.res-row {
  display: flex; align-items: center; gap: 11px;
  padding: 10px 13px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--slate-300);
  border-radius: var(--r-sm);
  background: #fff;
  font: inherit; text-align: left;
  cursor: pointer;
  transition: var(--t);
}
.res-row:hover { background: var(--slate-50); transform: translateX(2px); }
.res-row.ok  { border-left-color: var(--green); }
.res-row.bad { border-left-color: var(--red); }
.res-row .n { font-size: 12px; font-weight: 800; color: var(--ink-3); width: 22px; flex: none; }
.res-row .ri { width: 17px; height: 17px; flex: none; }
.res-row.ok .ri  { color: var(--green-dark); }
.res-row.bad .ri { color: var(--red-dark); }
.res-row .txt { flex: 1; min-width: 0; font-size: 13.5px; color: var(--slate-700); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.res-row .go { width: 15px; height: 15px; color: var(--slate-300); flex: none; }

.results-act { display: flex; gap: 12px; justify-content: flex-end; margin-top: 26px; }

.review .stim { padding-bottom: 14px; border-bottom: 1px solid var(--line); margin-bottom: 14px; }
.review-choices .choice { cursor: default; }
.review-choices .choice:hover { border-color: var(--slate-200); background: #fff; }
.review-choices .choice.correct:hover { border-color: var(--green); background: var(--green-tint); }
.review-choices .choice.wrong:hover { border-color: var(--red); background: var(--red-tint); }

/* ==========================================================================
   Daily Question — its own chrome, distinct from the practice/exam player:
   a blue header with a live reveal countdown, a dark "daily question" strip,
   a two-pane stage (stem left, answer card right), and a discussion thread
   that only appears once the answer is locked in.
   ========================================================================== */
.daily-sess { background: var(--slate-50); }

.daily-top {
  display: flex; align-items: center; gap: 20px;
  padding: 14px 24px;
  background: var(--blue);
  color: #fff;
  position: sticky; top: 0; z-index: 30;
}
.daily-top .sess-id .t { font-size: 16px; color: #fff; }
.daily-top .sess-id .s { color: rgba(255, 255, 255, .82); }
.sess-exit.on-dark { background: rgba(255, 255, 255, .14); border-color: rgba(255, 255, 255, .3); color: #fff; }
.sess-exit.on-dark:hover { background: rgba(255, 255, 255, .22); border-color: #fff; color: #fff; }

.daily-top-timer {
  margin-left: auto; flex: none; text-align: center;
  padding: 0 18px;
}
.daily-top-timer .tiny { color: rgba(255, 255, 255, .78); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; font-size: 10.5px; }
.daily-timer { font: 800 26px var(--font-head); letter-spacing: -.01em; }

.daily-tools { display: flex; align-items: center; gap: 6px; flex: none; }
.daily-tool {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 6px 12px;
  border: none; border-radius: var(--r-sm);
  background: transparent; color: rgba(255, 255, 255, .85);
  font-size: 10.5px; font-weight: 700;
  cursor: pointer;
  transition: var(--t);
}
.daily-tool svg { width: 19px; height: 19px; }
.daily-tool:hover { background: rgba(255, 255, 255, .14); color: #fff; }
.daily-tool.on { background: rgba(255, 255, 255, .22); color: #fff; }

.daily-strip {
  background: var(--slate-900); color: #fff;
  text-align: center; padding: 8px;
  font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
}

.daily-body { display: flex; flex: 1; align-items: flex-start; }
.daily-left { flex: 1; min-width: 0; border-right: 1px solid var(--line); background: #fff; min-height: calc(100vh - 90px); }
.daily-left .pane-inner { max-width: 640px; }
.daily-right { width: 460px; flex: none; padding: 24px; display: flex; flex-direction: column; gap: 20px; }

.daily-card-hd { display: flex; align-items: center; gap: 10px; padding: 18px 20px 4px; }
.daily-id-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; height: 32px; padding: 0 8px;
  background: var(--slate-900); color: #fff;
  border-radius: var(--r-sm);
  font: 800 15px var(--font-head);
}
.daily-card-body { padding: 14px 20px 22px; }

.daily-wait {
  text-align: center; margin-top: 20px; padding: 22px;
  border: 1.5px dashed var(--slate-300); border-radius: var(--r-md);
  background: var(--slate-50); color: var(--slate-600);
  animation: rise .35s var(--ease-out) both;
}
.daily-wait svg { width: 22px; height: 22px; color: var(--blue); }
.daily-wait-cd { font: 800 28px var(--font-head); color: var(--blue); margin-top: 8px; letter-spacing: -.01em; }

/* The choice list must NOT animate on rebuild: picking an answer re-renders
   it, and a translate-in replayed on every click read as the whole panel
   jumping. Selection is communicated by the choice's own colour change. */
.daily-card-body .btn { transition: background var(--t), transform .15s var(--ease-out), box-shadow .15s var(--ease-out), opacity var(--t); }

/* --- Question details ------------------------------------------------------
   Domain/skill breakdown, collapsible, sitting under the question stem. --- */
.qd { margin-top: 24px; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--slate-50); overflow: hidden; }
.qd summary {
  display: flex; align-items: center; gap: 8px;
  padding: 13px 16px; cursor: pointer; user-select: none;
  font-weight: 700; font-size: 14px; color: var(--ink);
  list-style: none;
}
.qd summary::-webkit-details-marker { display: none; }
.qd .qd-chev { width: 16px; height: 16px; color: var(--slate-500); transition: transform var(--t); }
.qd[open] .qd-chev { transform: rotate(180deg); }
.qd-body { border-top: 1px solid var(--line); background: #fff; }
.qd-row {
  display: flex; align-items: center; gap: 14px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--line);
}
.qd-row:last-child { border-bottom: none; }
.qd-k { flex: none; width: 68px; font-size: 10.5px; font-weight: 800; letter-spacing: .06em; color: var(--ink-3); }
.qd-txt { flex: 1; min-width: 0; }
.qd-txt .b { font-size: 14px; }
.qd-pct {
  flex: none; min-width: 32px; padding: 5px 9px;
  border-radius: var(--r-sm); background: var(--slate-200); color: var(--slate-700);
  font-size: 12.5px; font-weight: 800; text-align: center;
}

/* --- Reference sheet -------------------------------------------------------
   Mirrors the printed sheet: a plain white field of figures with the formula
   under each, then the three facts as a footer. No cards, no tinting — the
   real one is unadorned and students should recognise it instantly. --------- */
.ref-sheet { color: var(--ink); }
.ref-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 18px 10px;
  padding: 4px 2px 20px;
}
.ref-fig { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.ref-art { width: 100%; max-width: 118px; color: var(--ink); }
.ref-art svg { width: 100%; height: auto; display: block; }
.ref-eq {
  text-align: center;
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 14.5px;
  line-height: 1.5;
  font-style: italic;
}
.ref-eq sup { font-size: .68em; font-style: normal; }
/* Stacked fraction for the 4/3 and 1/3 coefficients. */
.ref-eq .frac {
  display: inline-flex; flex-direction: column; align-items: center;
  vertical-align: middle; margin: 0 2px; font-size: .74em;
  position: relative; top: -.06em;
}
.ref-eq .frac i { font-style: italic; line-height: 1.15; padding: 0 3px; }
.ref-eq .frac i:first-child { border-bottom: 1px solid currentColor; }

.ref-notes {
  border-top: 1px solid var(--line);
  padding-top: 14px;
  display: grid; gap: 7px;
}
.ref-notes p {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 13.5px; line-height: 1.45; color: var(--ink-2);
}

@media (max-width: 720px) {
  .ref-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 900px) {
  .daily-body { flex-direction: column; }
  .daily-left { border-right: 0; border-bottom: 1px solid var(--line); min-height: 0; }
  .daily-right { width: 100%; }
  .daily-top { flex-wrap: wrap; padding: 12px 16px; }
  .daily-top-timer { order: 3; margin-left: 0; padding: 8px 0 0; flex: 1 0 100%; text-align: left; }
  .daily-tools { margin-left: auto; }
}

@media (max-width: 900px) {
  .sess-stage { flex-direction: column; overflow: visible; }
  .sess-stage.split .sess-pane.stim { border-right: 0; border-bottom: 1px solid var(--line); }
  .sess-pane { overflow: visible; }
  .pane-inner { padding: 22px 18px 30px; }
  .sess-tools .icon-btn { width: 33px; height: 33px; }
  .sess-id .s { display: none; }
  .results-stats { grid-template-columns: repeat(2, 1fr); }
}

/* ==========================================================================
   Home
   ========================================================================== */

.daily-cards { display: grid; gap: 14px; padding: 18px; }
.daily-card {
  position: relative;
  border: 2px solid var(--slate-200);
  border-radius: var(--r-md);
  padding: 20px;
  min-height: 168px;
  display: flex;
  flex-direction: column;
  cursor: pointer;
  overflow: hidden;
  background: #EDF1F6;
  transition: box-shadow var(--t), background var(--t), border-color var(--t);
}
.daily-card:hover { box-shadow: var(--sh); border-color: var(--blue); background: linear-gradient(135deg, #E8F1FF, #DCE9FF); }
.daily-card.eng:hover { border-color: #C1443C; background: linear-gradient(135deg, #FDEBEA, #FDF3F2); }
.daily-card.done { background: var(--slate-100); border-color: var(--slate-300); }
.daily-card.done:hover { border-color: var(--slate-300); background: var(--slate-100); box-shadow: none; }
.daily-card .tag { font-size: 11px; font-weight: 800; letter-spacing: .07em; color: var(--slate-500); }
.daily-card h3 { font-size: 23px; margin-top: 2px; }
.daily-card .state { position: absolute; top: 16px; right: 16px; }
.daily-card .foot {
  margin-top: auto; display: flex; align-items: center; justify-content: space-between;
  font-size: 13px; font-weight: 700; color: var(--slate-600);
}
.daily-card .views { display: inline-flex; align-items: center; gap: 5px; }
.daily-card .views svg { width: 15px; height: 15px; }
.daily-card .ghost {
  position: absolute; right: -18px; bottom: -26px;
  width: 178px; height: 178px; opacity: .2; pointer-events: none;
  color: var(--blue);
  transform: rotate(-14deg);
  transition: transform .3s var(--ease-out), opacity .3s var(--ease-out);
}
.daily-card:hover .ghost { transform: rotate(-9deg) scale(1.05); opacity: .26; }
.daily-card .ghost svg { width: 100%; height: 100%; }

/* ==========================================================================
   Community — a plain section heading (no card chrome) for the daily strip,
   and leaderboard cards with light headers instead of the solid blue bars
   the rest of the app uses. Boards are reference material you scan, so they
   read better as quiet panels than as another shouty coloured header.
   ========================================================================== */
.sec-hd { display: flex; align-items: center; gap: 9px; margin-bottom: 14px; }
.sec-flame { display: flex; color: var(--amber); }
.sec-flame svg { width: 22px; height: 22px; }
.sec-title {
  font-family: var(--font-head); font-size: 20px; font-weight: 800;
  letter-spacing: -.01em; color: var(--amber-dark, #C2870B);
}
.sec-link {
  margin-left: auto; display: inline-flex; align-items: center; gap: 3px;
  font-size: 14px; font-weight: 700; color: var(--blue);
}
.sec-link:hover { text-decoration: underline; }
.sec-link svg { width: 16px; height: 16px; }

.lb-card .lb-hd {
  display: flex; align-items: center; gap: 9px;
  padding: 15px 18px 0;
}
.lb-card .lb-ic { width: 21px; height: 21px; color: var(--blue); flex: none; }
.lb-card .lb-title {
  font-family: var(--font-head); font-size: 19px; font-weight: 800; color: var(--ink);
}
.lb-card .lb-all {
  margin-left: auto; background: none; border: 0; padding: 0; cursor: pointer;
  font-family: var(--font-body); font-size: 13px; font-weight: 600; color: var(--ink-3);
}
.lb-card .lb-all:hover { color: var(--blue); text-decoration: underline; }
/* The add-friend button follows "View all", so the header reads title →
   browse → act, left to right. */
.lb-card .lb-add {
  width: 26px; height: 26px; border-radius: 8px; flex: none;
  display: grid; place-items: center;
  border: 1px solid var(--line); background: #fff;
  color: var(--ink-3); cursor: pointer;
  transition: var(--t-fast);
}
.lb-card .lb-add:hover { border-color: var(--blue); color: var(--blue); background: var(--blue-tint); }
.lb-card .lb-add svg { width: 14px; height: 14px; }
.lb-card .card-body { padding: 14px 16px 16px; }
.lb-reset {
  margin-top: 14px; text-align: center;
  font-size: 12.5px; font-weight: 600; color: var(--ink-3);
}

/* Metric switcher — which number a board is ranking on. */
.lb-tabs {
  display: flex;
  gap: 3px;
  padding: 3px;
  margin-bottom: 12px;
  background: var(--slate-100);
  border-radius: var(--pill);
}
.lb-tabs button {
  flex: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  padding: 6px 4px;
  border: 0;
  border-radius: var(--pill);
  background: none;
  font-family: var(--font-body);
  font-size: 12px; font-weight: 700;
  color: var(--ink-3);
  cursor: pointer;
  white-space: nowrap;
  transition: var(--t-fast);
}
.lb-tabs button svg { width: 13px; height: 13px; flex: none; }
.lb-tabs button:hover { color: var(--slate-700); }
.lb-tabs button.on { background: #fff; color: var(--blue-dark); box-shadow: var(--sh-xs); }
.lb-tabs button:active { transform: scale(.96); transition-duration: .08s; }

/* Your own row, pinned below the top ten when you rank outside it. */
.lb-yours { margin-top: 4px; }
.lb-gap {
  text-align: center;
  font-size: 13px; font-weight: 800; letter-spacing: .18em;
  color: var(--slate-300);
  line-height: 1;
  padding: 5px 0 7px;
}

/* Both home tiles are perfectly square (via aspect-ratio), side by side. */
.card.sq { aspect-ratio: 1 / 1; display: flex; flex-direction: column; overflow: hidden; }

/* Streak tile — its own card, flame icon + big count + label. */
.streak-tile { flex: 1; min-height: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; padding: 14px; text-align: center; }
.streak-tile .flame { display: flex; align-items: center; gap: 4px; }
.streak-tile .flame svg { width: 56px; height: 56px; animation: flamePulse 2.4s ease-in-out infinite; }
.streak-tile .n { font-family: var(--font-head); font-size: 52px; font-weight: 700; line-height: 1; color: var(--ink); }
.streak-tile .n.zero { color: var(--slate-300); }
.streak-tile .k { font-size: 17px; font-weight: 700; color: var(--ink-2); }

/* Day-by-day calendar — one day at a time, like a real calendar. */
.day-tile { padding: 0; display: flex; flex-direction: column; flex: 1; }
.day-hd {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px; border-bottom: 1px solid var(--line); flex: none;
}
.day-nav {
  width: 30px; height: 30px; border-radius: 8px;
  display: grid; place-items: center;
  border: none; background: transparent; color: var(--ink-3); cursor: pointer;
  transition: background var(--t), color var(--t);
}
.day-nav:hover:not(:disabled) { background: var(--slate-100); color: var(--ink); }
.day-nav:disabled { opacity: .3; cursor: default; }
.day-nav svg { width: 18px; height: 18px; }
.day-label { font-family: var(--font-head); font-size: 24px; font-weight: 800; color: var(--ink); }
.day-label.today { color: var(--blue); }

.day-body { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 10px; gap: 6px; overflow-y: auto; }
.day-empty { flex: 1; display: grid; place-items: center; text-align: center; }

.day-task {
  display: flex; align-items: center; gap: 10px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 9px 12px; background: #fff; text-align: left; width: 100%;
  font: inherit; cursor: default; transition: background var(--t), border-color var(--t);
  flex: none;
}
.day-task.link { cursor: pointer; }
.day-task.link:hover { background: var(--blue-tint); border-color: var(--blue); }
.day-task-box {
  width: 18px; height: 18px; border-radius: 6px; flex: none;
  border: 2px solid var(--slate-300); display: grid; place-items: center;
}
.day-task-box svg { width: 12px; height: 12px; color: #fff; }
.day-task.done .day-task-box { background: var(--green); border-color: var(--green); }
.day-task-label { font-size: 13px; font-weight: 600; color: var(--ink); }
.day-task.done .day-task-label { color: var(--ink-3); text-decoration: line-through; }

.goal-card { padding: 20px; }
.goal-card .top { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 12px; }
.goal-card h3 { font-size: 18px; }
.goal-card .v { font-size: 14px; font-weight: 800; color: var(--slate-600); font-variant-numeric: tabular-nums; }

/* "Resume where you left off" — same colored-card language as the daily
   questions, just one tile with a subject-tinted background. */
.resume-tile {
  position: relative;
  min-height: 148px;
  border-radius: var(--r-md);
  padding: 20px;
  overflow: hidden;
  background: linear-gradient(135deg, #E8F1FF, #DCE9FF);
  border: 2px solid var(--blue);
  cursor: pointer;
  transition: box-shadow var(--t);
  box-sizing: border-box;
}
.resume-tile:hover { box-shadow: var(--sh); }
.resume-tile.eng { background: linear-gradient(135deg, #F1EEFF, #E8E2FF); border-color: var(--english); }
.resume-tile .meta { display: flex; gap: 8px; align-items: center; margin-bottom: 10px; flex-wrap: wrap; }
.resume-q {
  font-size: 15px; font-weight: 500; color: var(--slate-800); line-height: 1.5;
  max-height: 72px; overflow: hidden;
  margin-bottom: 16px;
}
.resume-tile .ghost {
  position: absolute; right: -14px; bottom: -22px;
  width: 140px; height: 140px; opacity: .1; pointer-events: none;
  transform: rotate(-14deg);
}

.spark { width: 100%; height: 180px; display: block; }
.spark .grid-l { stroke: var(--line); stroke-width: 1; }
.spark .ln { fill: none; stroke: var(--blue); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.spark .ar { fill: url(#sparkgrad); }
.spark .pt { fill: #fff; stroke: var(--blue); stroke-width: 2.5; }
.spark .lbl { font-size: 10px; fill: var(--ink-3); font-family: var(--font-body); }

/* ==========================================================================
   Training bank
   ========================================================================== */

.bank-total { display: flex; align-items: baseline; gap: 8px; margin: 6px 0 10px; }
.bank-total .n { font-family: var(--font-head); font-size: 48px; font-weight: 700; color: var(--blue); line-height: 1; }
.bank-total .d { font-size: 17px; font-weight: 700; color: var(--slate-500); }

/* Focus strip — weakest-skills quick launcher above the domain accordion */
.focus-strip { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 12px; padding: 4px 20px 20px; }
.focus-chip {
  text-align: left; border: 1px solid var(--line); border-radius: var(--r-sm); padding: 12px 14px;
  background: #fff; cursor: pointer; font: inherit; transition: border-color .12s var(--ease), transform .12s var(--ease);
}
.focus-chip:hover { border-color: var(--blue); transform: translateY(-1px); }
.fc-top { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.fc-name { font-size: 13.5px; font-weight: 700; color: var(--ink); }
.fc-pct { font-size: 11.5px; font-weight: 800; color: var(--blue); flex: none; }
.fc-sub { font-size: 11.5px; color: var(--ink-3); margin: 2px 0 8px; }
.fc-bar.bar { height: 5px; }

.dom-title { font-family: var(--font-head); font-size: 21px; font-weight: 700; line-height: 1.2; }
.dom-sub { font-size: 13px; color: var(--blue); font-weight: 600; }

/* Tiled grid of skill cards — each tile splits into a labelled left half and
   a boxed stats/action panel on the right. */
.skill-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 14px;
}

.skill-card {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: stretch;
  gap: 0;
  border: 1px solid var(--line);
  border-left: 4px solid var(--blue);
  border-radius: var(--r-sm);
  background: #fff;
  transition: box-shadow var(--t), border-color var(--t), background var(--t);
}
.skill-card:hover { box-shadow: var(--sh-sm); }
.skill-card.dom-blue   { border-left-color: var(--blue); }
.skill-card.dom-purple { border-left-color: var(--purple); }
.skill-card.dom-green  { border-left-color: var(--green); }
.skill-card.dom-amber  { border-left-color: var(--amber); }
.skill-card.dom-indigo { border-left-color: var(--indigo); }
.skill-card.dom-red    { border-left-color: var(--red); }

.skill-left {
  position: relative;
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
  padding: 14px 14px 12px;
  overflow: hidden;
}
.skill-left .ghost {
  position: absolute; right: -18px; top: 50%;
  width: 116px; height: 116px;
  margin-top: -58px;
  opacity: .07; pointer-events: none;
  transform: rotate(-14deg);
  color: var(--blue);
}
.skill-left .nm { font-family: var(--font-head); font-size: 16px; font-weight: 800; line-height: 1.25; }
.skill-left .sh { font-size: 12px; color: var(--ink-3); font-weight: 600; margin-top: 2px; }
.skill-left .foot {
  margin-top: auto; padding-top: 14px;
  display: flex; align-items: center; gap: 12px;
  font-size: 12.5px; font-weight: 600; color: var(--slate-500);
}
.skill-left .foot svg { width: 14px; height: 14px; }

.skill-right {
  flex: none;
  width: 152px;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 14px 12px;
  border-left: 1px solid var(--line);
  background: #fff;
}
.skill-right .cc { display: flex; gap: 12px; font-size: 13px; font-weight: 800; }
.skill-right .cc span { display: inline-flex; align-items: center; gap: 4px; }
.skill-right .cc svg { width: 15px; height: 15px; }
.skill-right .cc .g { color: var(--green-dark); }
.skill-right .cc .r { color: var(--red-dark); }
.skill-right .frac {
  width: 100%; padding-top: 8px;
  border-top: 1px solid var(--line);
  text-align: center;
  font-size: 13px; font-weight: 700; color: var(--slate-500); font-variant-numeric: tabular-nums;
}
.skill-right .frac b { color: var(--blue); }
.skill-right .btn { margin-top: auto; letter-spacing: .04em; }

@media (max-width: 560px) {
  .skill-grid { grid-template-columns: 1fr; }
  .skill-right { width: 132px; }
  .acc-bd { padding: 0 12px 16px; }
  .acc-hd { padding: 14px 12px; gap: 10px; }
}

/* ==========================================================================
   Shared page furniture used across views
   ========================================================================== */

.filters { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 20px; }

.list-row {
  display: flex; align-items: center; gap: 13px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
  transition: background var(--t);
}
.list-row:last-child { border-bottom: 0; }
.list-row:hover { background: var(--slate-50); }

.kv { display: flex; align-items: center; justify-content: space-between; padding: 11px 0; border-bottom: 1px solid var(--line); }
.kv:last-child { border-bottom: 0; }
.kv .k { font-size: 14px; font-weight: 600; color: var(--slate-600); }
.kv .v { font-size: 14px; font-weight: 700; }

.pill-tabs { display: inline-flex; background: var(--slate-100); padding: 4px; border-radius: var(--pill); gap: 2px; }
.pill-tabs button {
  padding: 8px 18px; border: 0; border-radius: var(--pill);
  background: none; color: var(--slate-600);
  font-size: 13.5px; font-weight: 700; cursor: pointer;
  touch-action: manipulation;
  transition: background var(--t), color var(--t), transform .15s var(--ease-out), box-shadow var(--t);
}
.pill-tabs button:active { transform: scale(.94); transition-duration: .08s; }
.pill-tabs button.on { background: #fff; color: var(--blue-dark); box-shadow: var(--sh-xs); }

/* ==========================================================================
   Diagnostics — projected-score hero + KPI strip
   ========================================================================== */

.proj-body { display: flex; gap: 28px; padding: 26px 28px; flex-wrap: wrap; }
.proj-main { flex: 1 1 340px; min-width: 0; }
.proj-n {
  font-family: var(--font-head); font-weight: 800; font-size: 72px; line-height: 1;
  color: var(--blue); margin: 4px 0 8px;
}
.proj-sub { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 13.5px; color: var(--ink-2); font-weight: 600; }
.proj-gap {
  padding: 3px 10px; border-radius: var(--pill);
  background: var(--amber-tint); color: var(--amber-dark);
  font-size: 12px; font-weight: 800;
}
.proj-gap.hit { background: var(--green-tint); color: var(--green-dark); }

/* The 400–1600 track, with a notch marking the goal score. */
.proj-track {
  position: relative; height: 10px; margin-top: 20px;
  border-radius: var(--pill); background: var(--slate-200); overflow: visible;
}
.proj-fill {
  height: 100%; border-radius: var(--pill);
  background: linear-gradient(90deg, var(--blue), var(--indigo));
}
.proj-goal {
  position: absolute; top: -5px; width: 3px; height: 20px;
  border-radius: 2px; background: var(--amber-dark);
  transform: translateX(-50%);
}
.proj-scale { display: flex; justify-content: space-between; margin-top: 7px; font-size: 11.5px; font-weight: 700; color: var(--ink-3); }

.proj-sections { flex: 0 1 340px; display: grid; gap: 12px; align-content: center; }
.proj-sec { border: 1px solid var(--line); border-radius: var(--r-sm); padding: 12px 14px; }
.proj-sec-v { font-family: var(--font-head); font-size: 28px; font-weight: 800; line-height: 1; color: var(--ink); }
.proj-sec-k { font-size: 12.5px; font-weight: 700; color: var(--ink-2); margin-top: 3px; }
.proj-sec-u { font-size: 11.5px; color: var(--ink-3); font-weight: 600; }

/* KPI strip */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }
.kpi {
  display: flex; align-items: center; gap: 14px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r);
  padding: 16px 18px; box-shadow: var(--sh-xs);
}
.kpi-ic { width: 42px; height: 42px; border-radius: 12px; display: grid; place-items: center; flex: none; }
.kpi-ic svg { width: 21px; height: 21px; }
.kpi-txt { min-width: 0; }
.kpi-v { font-family: var(--font-head); font-size: 26px; font-weight: 800; line-height: 1.05; color: var(--ink); }
.kpi-k { font-size: 12.5px; font-weight: 700; color: var(--ink-2); margin-top: 2px; }
.kpi-u { font-size: 11.5px; color: var(--ink-3); font-weight: 600; }

.kpi-blue   .kpi-ic { background: var(--blue-tint);   color: var(--blue); }
.kpi-green  .kpi-ic { background: var(--green-tint);  color: var(--green-dark); }
.kpi-amber  .kpi-ic { background: var(--amber-tint);  color: var(--amber-dark); }
.kpi-purple .kpi-ic { background: var(--purple-tint); color: var(--purple); }

@media (max-width: 720px) {
  .proj-body { padding: 20px; gap: 20px; }
  .proj-n { font-size: 54px; }
}

/* ==========================================================================
   Study-plan completion — Home "Today's Plan" card and the Schedule day modal
   ========================================================================== */

/* Schedule day-modal: progress summary above the lesson list */
.plan-sum {
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 12px 14px; margin-bottom: 14px; background: var(--slate-50);
}

/* A scheduled lesson: status line, not a checkbox. */
.task-row {
  display: flex; align-items: center; gap: 10px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 10px 12px;
  transition: border-color var(--t), background var(--t);
}
.task-row.done { background: var(--green-tint); border-color: rgba(34, 197, 94, .3); }
.task-row.done .sm.b { text-decoration: line-through; opacity: .6; }
.task-mark { display: grid; place-items: center; width: 20px; height: 20px; flex: none; color: var(--green-dark); }
.task-mark svg { width: 18px; height: 18px; }
.task-dot { display: block; width: 15px; height: 15px; border-radius: 50%; border: 2px solid var(--slate-300); }

/* Home card */
.plan-head { display: flex; align-items: center; gap: 16px; }
.plan-ring { flex: none; }
.plan-copy { min-width: 0; }
.plan-n { font-family: var(--font-head); font-size: 17px; font-weight: 800; line-height: 1.2; }
.plan-xp { font-size: 12.5px; font-weight: 700; color: var(--blue); margin-top: 2px; }

.plan-next {
  display: flex; align-items: center; gap: 12px; width: 100%;
  margin-top: 16px; padding: 12px 14px;
  border: 1px solid var(--line); border-left: 4px solid var(--blue);
  border-radius: var(--r-sm);
  background: #fff; font: inherit; text-align: left; cursor: pointer;
  transition: background var(--t), box-shadow var(--t), transform .12s var(--ease);
}
.plan-next:hover { background: var(--blue-tint); box-shadow: var(--sh-sm); transform: translateY(-1px); }
.plan-next:active { transform: translateY(0) scale(.99); transition-duration: .08s; }
.pn-ic {
  display: grid; place-items: center; flex: none;
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--blue); color: #fff;
}
.pn-ic svg { width: 16px; height: 16px; }
.pn-txt { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.pn-k { font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.pn-v { font-size: 14.5px; font-weight: 700; color: var(--ink); }
.pn-go { color: var(--slate-400); flex: none; display: grid; place-items: center; }
.pn-go svg { width: 18px; height: 18px; }

.plan-done {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin-top: 16px; padding: 14px;
  border-radius: var(--r-sm); background: var(--green-tint);
  color: var(--green-dark); font-size: 14px; font-weight: 800;
}
.plan-done svg { width: 18px; height: 18px; }

/* Seven-day XP momentum strip */
.week-strip { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line); }
.week-bars { display: grid; grid-template-columns: repeat(7, 1fr); gap: 8px; align-items: end; }
.week-col { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.week-bar-track {
  width: 100%; height: 56px;
  display: flex; align-items: flex-end;
  background: var(--slate-100); border-radius: 5px; overflow: hidden;
}
.week-bar { width: 100%; border-radius: 5px; background: var(--slate-300); transition: height var(--t); }
.week-bar.hit { background: var(--green); }
.week-bar.today { background: var(--blue); }
.week-bar.today.hit { background: var(--green); }
.week-d { font-size: 11px; font-weight: 700; color: var(--ink-3); }

/* ==========================================================================
   Settings
   ========================================================================== */

.set-hero { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; padding: 22px 24px; }
.set-hero-n { font-family: var(--font-head); font-size: 22px; font-weight: 800; line-height: 1.15; }
.set-hero-s { font-size: 13px; color: var(--ink-2); font-weight: 600; margin-top: 2px; }

.set-layout { display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: 24px; align-items: start; }

.set-nav {
  position: sticky; top: 22px;
  display: flex; flex-direction: column; gap: 2px;
}
.set-nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-radius: var(--r-sm);
  font-size: 14px; font-weight: 600; color: var(--slate-600);
  text-decoration: none;
  transition: background var(--t), color var(--t);
}
.set-nav-item svg { width: 17px; height: 17px; color: var(--slate-400); flex: none; }
.set-nav-item:hover { background: var(--slate-100); color: var(--ink); }
.set-nav-item:hover svg { color: var(--blue); }

.set-main { display: grid; gap: 22px; }
.set-card { scroll-margin-top: 20px; }
.set-body { padding: 6px 22px 20px; }

.set-row {
  display: flex; align-items: center; gap: 20px;
  padding: 15px 0;
  border-bottom: 1px solid var(--line);
}
.set-row:last-child { border-bottom: none; }
.set-row-txt { flex: 1; min-width: 0; }
.set-row-k { font-size: 14.5px; font-weight: 700; color: var(--ink); }
.set-row-n { font-size: 12.5px; color: var(--ink-3); font-weight: 500; margin-top: 2px; line-height: 1.4; }
.set-row-ctl { flex: none; display: flex; align-items: center; gap: 10px; }
.set-val { font-size: 14px; font-weight: 700; color: var(--ink-2); }

.set-note { font-size: 13px; color: var(--ink-2); line-height: 1.55; padding-top: 12px; }
.set-actions { display: flex; gap: 10px; flex-wrap: wrap; padding-top: 18px; }

/* Target-score slider */
.set-score { display: flex; align-items: center; gap: 12px; }
.set-range { width: 190px; accent-color: var(--blue); cursor: pointer; }
.set-score-v {
  min-width: 52px; text-align: center;
  font-family: var(--font-head); font-size: 17px; font-weight: 800; color: var(--blue);
}

/* --- Codes: redeem a promo, carry Premium to the phone -------------------- */

/* The code box is the one control on this page that is typed into rather than
   toggled, so it gets real width — a 90px input beside a Redeem button reads
   as an afterthought, and these codes are fifteen characters long. */
.code-inp {
  width: 230px;
  max-width: 100%;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  letter-spacing: .06em;
  text-transform: uppercase;
}
.code-inp::placeholder { letter-spacing: normal; text-transform: none; }
.code-note { margin-top: 8px; font-weight: 600; }
.code-note.ok { color: var(--green-dark, #047857); }
.code-note.bad { color: var(--red-dark); }

/* The hand-off to the phone is an announcement, not a settings row: someone
   who has just paid should find it without reading down a list. */
.mobile-unlock {
  margin-top: 18px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--blue-tint, rgba(0, 166, 255, .07));
}
.mobile-unlock-hd {
  display: flex; align-items: center; gap: 8px;
  font-size: 14.5px; font-weight: 800; color: var(--ink);
}
.mobile-unlock-hd svg { width: 17px; height: 17px; color: var(--blue); }
.mobile-unlock-p {
  margin: 7px 0 13px;
  font-size: 12.5px; font-weight: 500; line-height: 1.5; color: var(--ink-2);
}
.mobile-unlock-code { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.mobile-unlock-code code {
  padding: 9px 15px;
  border: 1px dashed var(--slate-300);
  border-radius: var(--r-sm);
  background: #fff;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 18px; font-weight: 700; letter-spacing: .16em; color: var(--ink);
}

/* Destructive action gets its own boxed-off zone. */
.set-danger {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  margin-top: 20px; padding: 14px 16px;
  border: 1px solid rgba(239, 68, 68, .35); border-radius: var(--r-sm);
  background: var(--red-tint);
}
.set-danger .set-row-txt { flex: 1; min-width: 200px; }
.set-danger .set-row-k { color: var(--red-dark); }

@media (max-width: 860px) {
  .set-layout { grid-template-columns: minmax(0, 1fr); }
  .set-nav { position: static; flex-direction: row; flex-wrap: wrap; }
  .set-nav-item { border: 1px solid var(--line); }
  .set-row { flex-direction: column; align-items: flex-start; gap: 10px; }
  .set-hero { justify-content: center; text-align: center; }
}

/* ==========================================================================
   Exam review — the question-by-question read-back of a finished test
   ========================================================================== */
.rv-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }

.rv-note {
  display: flex; align-items: flex-start; gap: 10px;
  margin-bottom: 20px; padding: 12px 14px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--wash);
  font-size: 12.5px; line-height: 1.55; color: var(--ink-2);
}
.rv-note svg { width: 16px; height: 16px; flex: none; margin-top: 1px; color: var(--ink-3); }

/* Sheet on the left, question on the right. The sheet sticks: scrolling a
   long passage should never cost you the ability to jump to another one. */
.rv-layout { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: 22px; align-items: start; }
.rv-side { position: sticky; top: 20px; display: grid; gap: 14px; }
.rv-seg { width: 100%; }
.rv-seg button { flex: 1; font-size: 12.5px; }

.rv-grid-wrap { display: grid; gap: 6px; }
.rv-grid-lbl {
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-3); margin-top: 8px;
}
.rv-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; }
.rv-cell {
  aspect-ratio: 1; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 9px;
  background: #fff;
  font: 700 12px var(--font-num, var(--font-body));
  color: var(--ink-2); cursor: pointer;
  transition: var(--t-fast);
}
.rv-cell:hover { border-color: var(--slate-300); transform: translateY(-1px); }
.rv-cell.ok { background: var(--green-tint); border-color: rgba(14, 159, 110, .3); color: var(--green); }
.rv-cell.bad { background: var(--red-tint); border-color: rgba(217, 74, 74, .3); color: var(--red-dark); }
.rv-cell.on { outline: 2px solid var(--blue); outline-offset: 1px; border-color: var(--blue); }

/* The panel is replaced wholesale on Next/Prev, so it gets a short fade-and-
   settle on arrival. Without it the swap is an instant pop that reads as the
   page having jumped even when the scroll position hasn't moved at all. */
.rv-card { overflow: hidden; animation: rvSwap .26s var(--ease, ease-out) both; }
@keyframes rvSwap {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .rv-card { animation: none; }
}
.rv-qhead {
  display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap;
  padding: 14px 20px; border-bottom: 1px solid var(--line); background: var(--wash);
}
.rv-qhead-l { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rv-qhead-r { display: flex; gap: 8px; }
.rv-num { font: 800 15px var(--font-head); color: var(--ink); }

/* The choice you picked and the one that was right both need naming — colour
   alone says "wrong" without saying "yours", and on a question you left blank
   there is no picked choice at all. */
.rv-choice { position: relative; padding-right: 96px; }
.rv-tag {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  font-size: 10px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: var(--red-dark);
}
.rv-tag.ok { color: var(--green); }

/* A third option being read — neither the key nor what they picked, so it
   gets an outline rather than red, which here means "you chose this." */
.rv-choice.peek { border-color: var(--slate-300); background: var(--wash); }
/* Whichever choice the explanation below is currently about. */
.rv-choice.reading { box-shadow: 0 0 0 2px rgba(47, 107, 255, .35); }
.review-choices .rv-choice { transition: box-shadow .18s ease, border-color .18s ease, background .18s ease; }

.rv-why {
  margin-top: 18px; padding: 14px 16px;
  border-left: 3px solid var(--red); border-radius: var(--r-sm);
  background: var(--red-tint);
}
.rv-why.ok { border-left-color: var(--green); background: var(--green-tint); }
.rv-why h4 { margin: 0 0 6px; font-size: 13px; }
.rv-why .rationale { font-size: 14px; line-height: 1.6; }

.rv-meta {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line);
  font-size: 12.5px; color: var(--ink-3);
}
.rv-meta svg { width: 14px; height: 14px; vertical-align: -2px; }
.rv-drill {
  margin-left: auto; display: inline-flex; align-items: center; gap: 6px;
  border: 0; background: none; padding: 0;
  font: 700 12.5px var(--font-body); color: var(--blue); cursor: pointer;
}
.rv-drill:hover { text-decoration: underline; }

.rv-weak { margin-bottom: 22px; }
.rv-weak-row { display: flex; gap: 10px; flex-wrap: wrap; }
.rv-weak-chip {
  display: flex; flex-direction: column; gap: 2px;
  padding: 10px 14px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--wash);
}
.rv-weak-chip b { font-size: 13.5px; color: var(--ink); }
.rv-weak-chip span { font-size: 11.5px; color: var(--red-dark); font-weight: 700; }

/* The way in, from Diagnostics */
.dg-review-list { display: grid; gap: 8px; }
.dg-review-row {
  display: flex; align-items: center; gap: 14px;
  padding: 11px 14px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: #fff; color: var(--ink); text-decoration: none;
  transition: var(--t-fast);
}
.dg-review-row:hover { border-color: var(--blue); background: var(--blue-tint); }
.dg-review-n {
  width: 34px; height: 34px; flex: none; display: grid; place-items: center;
  border-radius: 10px; background: var(--wash);
  font: 800 14px var(--font-head); color: var(--ink-2);
}
.dg-review-txt { flex: 1; min-width: 0; display: grid; }
.dg-review-txt b { font-size: 14px; }
.dg-review-txt span { font-size: 12px; color: var(--ink-3); }
.dg-review-row svg:last-child { width: 15px; height: 15px; color: var(--ink-3); }

@media (max-width: 900px) {
  .rv-layout { grid-template-columns: minmax(0, 1fr); }
  .rv-side { position: static; }
  .rv-grid { grid-template-columns: repeat(10, 1fr); }
}
@media (max-width: 560px) {
  .rv-grid { grid-template-columns: repeat(7, 1fr); }
  .rv-choice { padding-right: 14px; }
  .rv-tag { position: static; transform: none; display: block; margin-top: 4px; }
}

/* --------------------------------------------------------------------------
   Diagnostics — "Where your points are" opportunity list
   -------------------------------------------------------------------------- */
.opp-lead { font-size: 13px; color: var(--ink-2); line-height: 1.5; margin-bottom: 16px; }

.opp-list { display: flex; flex-direction: column; gap: 8px; }
.opp-row {
  display: flex; align-items: center; gap: 16px; width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: #fff; font: inherit; text-align: left; cursor: pointer;
  transition: background var(--t), box-shadow var(--t), transform .12s var(--ease);
}
.opp-row:hover { background: var(--blue-tint); box-shadow: var(--sh-sm); transform: translateY(-1px); }
.opp-row:active { transform: translateY(0) scale(.995); transition-duration: .08s; }

/* The score gain is the headline number — it leads the row. */
.opp-gain {
  flex: none; min-width: 62px;
  display: flex; align-items: baseline; justify-content: center; gap: 1px;
  color: var(--green-dark);
}
.opp-plus { font-size: 15px; font-weight: 800; }
.opp-n { font-family: var(--font-head); font-size: 27px; font-weight: 800; line-height: 1; }

.opp-mid { flex: 1; min-width: 0; }
.opp-nm { font-size: 14.5px; font-weight: 700; color: var(--ink); }
.opp-meta {
  display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
  font-size: 11.5px; font-weight: 600; color: var(--ink-3); margin-top: 2px;
}
.opp-dot { color: var(--slate-300); }
.opp-track {
  height: 6px; margin-top: 8px;
  border-radius: var(--pill); background: var(--slate-100); overflow: hidden;
}
.opp-fill { height: 100%; border-radius: var(--pill); background: linear-gradient(90deg, var(--green), var(--blue)); }
.opp-go { flex: none; color: var(--slate-400); display: grid; place-items: center; }
.opp-go svg { width: 18px; height: 18px; }

/* Pace — bar against the real test's per-question budget, marked at 100%. */
.pace-track {
  position: relative; height: 9px;
  border-radius: var(--pill); background: var(--slate-100); overflow: hidden;
}
.pace-fill { height: 100%; border-radius: var(--pill); }
.pace-fill.green { background: var(--green); }
.pace-fill.amber { background: var(--amber); }
.pace-fill.red   { background: var(--red); }
.pace-mark {
  position: absolute; top: -2px; right: 0;
  width: 2px; height: 13px; background: var(--ink-2); border-radius: 1px;
}

@media (max-width: 560px) {
  .opp-row { gap: 10px; padding: 10px; }
  .opp-gain { min-width: 48px; }
  .opp-n { font-size: 22px; }
}

/* Heatmap (Diagnostics, Profile) */
.heat { display: grid; grid-auto-flow: column; grid-template-rows: repeat(7, 12px); gap: 3px; overflow-x: auto; padding-bottom: 4px; }
.heat i { width: 12px; height: 12px; border-radius: 3px; background: var(--slate-200); display: block; }
.heat i.a { background: var(--green); }
.heat i.t { outline: 1.5px solid var(--blue); }

/* ==========================================================================
   Guided path
   ========================================================================== */

.path { position: relative; padding: 8px 0 40px; }
.path::before {
  content: "";
  position: absolute;
  top: 0; bottom: 40px; left: 50%;
  width: 3px;
  margin-left: -1.5px;
  background: var(--slate-200);
  border-radius: var(--pill);
}
.path-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 78px;
  width: 50%;
}
/* Padding clears the node, which overhangs the spine by up to 31px when it is
   the enlarged "current" node. */
.path-row.left  { margin-left: 0;    justify-content: flex-end;   padding-right: 50px; }
.path-row.right { margin-left: 50%;  justify-content: flex-start; padding-left: 50px; flex-direction: row-reverse; }
.path-row.right .path-label { text-align: right; }

.path-node {
  position: absolute;
  top: 50%;
  width: 52px; height: 52px;
  margin-top: -26px;
  border-radius: 50%;
  border: 3px solid var(--slate-300);
  background: #fff;
  color: var(--slate-400);
  font-size: 16px; font-weight: 800;
  display: grid; place-items: center;
  cursor: pointer;
  touch-action: manipulation;
  transition: transform .18s var(--ease-out), box-shadow .18s var(--ease-out);
  z-index: 2;
}
.path-row.left  .path-node { right: -26px; }
.path-row.right .path-node { left: -26px; }
.path-node svg { width: 22px; height: 22px; }
.path-node:hover { transform: scale(1.08); box-shadow: var(--sh-sm); }
.path-node:active { transform: scale(.95); transition-duration: .08s; }

.path-node.done   { background: var(--green); border-color: var(--green-dark); color: #fff; }
.path-node.now    {
  background: var(--blue); border-color: var(--blue-dark); color: #fff;
  width: 62px; height: 62px; margin-top: -31px; font-size: 18px;
  box-shadow: 0 0 0 6px rgba(0, 166, 255, .18);
}
.path-row.left  .path-node.now { right: -31px; }
.path-row.right .path-node.now { left: -31px; }
.path-node.locked { background: var(--slate-100); cursor: not-allowed; }
.path-node.locked:hover { transform: none; }
.path-node.check { border-radius: 16px; border-color: var(--amber); color: var(--amber); }
.path-node.check.done { background: var(--amber); border-color: var(--amber-dark); color: #fff; }

.path-label { max-width: 230px; }

@media (max-width: 720px) {
  .path::before { left: 34px; }
  .path-row, .path-row.right { width: 100%; margin-left: 0; padding-left: 76px; padding-right: 0;
    justify-content: flex-start; flex-direction: row; }
  .path-row.right .path-label { text-align: left; }
  .path-row .path-node,
  .path-row.right .path-node { left: 8px; right: auto; }
  .path-row .path-node.now,
  .path-row.right .path-node.now { left: 3px; right: auto; }
}

/* ==========================================================================
   Vocab
   ========================================================================== */

.vcard {
  cursor: pointer;
  transition: box-shadow var(--t);
  user-select: none;
}
.vcard:hover { box-shadow: var(--sh); }
.vcard .card-body { min-height: 250px; display: grid; align-content: center; }

/* --------------------------------------------------------------------------
   Flashcard — a real 3D flip. The outer element owns the perspective, the
   inner one rotates, and the two faces sit back-to-back inside it.
   -------------------------------------------------------------------------- */
.flip-card {
  perspective: 1400px;
  cursor: pointer;
  user-select: none;
  min-height: 320px;
}
.flip-inner {
  position: relative;
  width: 100%;
  min-height: 320px;
  transform-style: preserve-3d;
  transition: transform .55s cubic-bezier(.4, .2, .2, 1);
}
.flip-inner.flipped { transform: rotateY(180deg); }

.flip-face {
  position: absolute; inset: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px;
  padding: 32px 28px;
  text-align: center;
  border-radius: var(--r-lg);
  background: var(--card);
  border: 1px solid var(--line);
  box-shadow: var(--sh-sm);
}
.flip-face.back {
  transform: rotateY(180deg);
  background: linear-gradient(160deg, var(--blue-tint), #fff 60%);
}

.flip-word { font-family: var(--font-head); font-size: 42px; font-weight: 800; letter-spacing: -.01em; color: var(--ink); }
.flip-pos { font-size: 14px; color: var(--ink-3); font-style: italic; }
.flip-hint { position: absolute; bottom: 18px; font-size: 12px; color: var(--ink-3); }
.flip-def { font-size: 19px; font-weight: 600; color: var(--ink); line-height: 1.45; max-width: 46ch; }
.flip-ex { font-size: 14px; color: var(--ink-2); font-style: italic; margin-top: 10px; max-width: 48ch; }

/* The flip is decorative — respect a reduced-motion preference. */
@media (prefers-reduced-motion: reduce) {
  .flip-inner { transition: none; }
}

@media (max-width: 720px) {
  .flip-card, .flip-inner { min-height: 280px; }
  .flip-word { font-size: 32px; }
  .flip-def { font-size: 16px; }
}

/* ==========================================================================
   Graphing calculator
   ========================================================================== */

/* Diagnostics rows link into Training, so keep anchors looking like rows. */
a.list-row, a.opp-row { color: inherit; text-decoration: none; }

/* --------------------------------------------------------------------------
   Pricing — the whole decision should fit on one screen, so the plan cards
   are deliberately tight vertically.
   -------------------------------------------------------------------------- */
.pricing { max-width: 1040px; margin: 0 auto; }
.pricing .grid.g-2 { gap: 28px; }
.plan-card { border-width: 2px; border-radius: 20px; overflow: hidden; }
.plan-card .card-hd { padding: 22px 26px; }
.plan-price { background: var(--blue-tint); padding: 24px 26px; }
.plan-was {
  font-size: 20px; font-weight: 700; color: var(--slate-400);
  text-decoration: line-through;
}
.plan-now { font: 700 46px var(--font-head); letter-spacing: -.02em; }
.plan-card .card-body { padding: 24px 26px !important; }
.plan-card .btn-block { padding: 16px; font-size: 16px; border-radius: 12px; }
.plan-feats { gap: 14px; margin-top: 20px !important; }
.plan-feats .row-t { align-items: flex-start; }
.plan-feats span.tiny { font-size: 14.5px !important; line-height: 1.45 !important; }
.plan-card.on { border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-tint-2); }
.plan-card .btn-block[disabled] {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  color: var(--blue); background: var(--blue-tint); border-color: var(--blue-tint-2);
  opacity: 1; cursor: default;
}

.trial-pill {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  max-width: 520px; margin: 38px auto 0;
  background: var(--slate-200); border: 1px solid var(--slate-300);
  border-radius: 14px; padding: 18px 24px; cursor: default;
  color: var(--slate-600); font: 700 20px var(--font-head); letter-spacing: -.01em;
  transition: background var(--t);
}
.trial-pill svg { width: 18px; height: 18px; flex: none; }

/* ==========================================================================
   Calculator panel

   Docked it behaves like a dialog; floating it behaves like a window. The
   same element does both, because the transition between them happens
   mid-drag and re-creating it would drop the student's graph.
   ========================================================================== */
.calc-panel {
  display: flex;
  flex-direction: column;
  width: min(860px, 100%);
  background: #fff;
  border-radius: var(--r-lg);
  box-shadow: var(--sh-xl);
  overflow: hidden;
  animation: pop .28s var(--spring);
}

.calc-head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 12px 12px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--slate-50);
  cursor: grab;
  /* The header is a drag handle: no text selection, and no browser-native
     panning stealing the pointer stream mid-drag. */
  user-select: none;
  touch-action: none;
}
.calc-head h3 { flex: 1; font-size: 16px; }
.calc-grip { display: flex; color: var(--slate-300); }
.calc-grip svg { width: 18px; height: 18px; stroke-width: 2.6; }
.calc-head:hover .calc-grip { color: var(--slate-400); }

.calc-host { min-height: 420px; }
/* Desmos measures its own container, so give it a concrete box to fill. */
.desmos-host { width: 100%; height: min(70vh, 560px); min-height: 420px; }

/* --- Floating -------------------------------------------------------------
   Positioned by transform from the top-left corner, so a drag is a compositor
   job rather than a layout one. --------------------------------------------- */
.calc-panel.floating {
  position: fixed;
  top: 0; left: 0;
  z-index: 210;
  margin: 0;
  animation: none;            /* it is already on screen — do not re-pop it */
  box-shadow: 0 18px 50px rgba(15, 23, 42, .3);
}
.calc-panel.floating .calc-head { cursor: grab; }
.calc-panel.dragging { cursor: grabbing; }
.calc-panel.dragging .calc-head { cursor: grabbing; }
/* Hide the drop shadow's cost during the drag by not animating anything. */
.calc-panel.dragging { transition: none; }

/* Asking for the calculator when it is already open nudges it, so the answer
   to "where did it go?" is visible rather than a second one appearing.
   Deliberately not a transform: the floating panel carries its position in
   `transform`, and animating that property would fling it back to the origin
   for the length of the animation. */
@keyframes calcBump {
  0%   { box-shadow: 0 0 0 0 rgba(0, 166, 255, .55), 0 18px 50px rgba(15, 23, 42, .3); }
  70%  { box-shadow: 0 0 0 10px rgba(0, 166, 255, 0), 0 18px 50px rgba(15, 23, 42, .3); }
  100% { box-shadow: 0 0 0 0 rgba(0, 166, 255, 0), 0 18px 50px rgba(15, 23, 42, .3); }
}
.calc-panel.bump { animation: calcBump .55s var(--ease-out); }

/* The exam panel is deliberately smaller: it shares the screen with the
   question the whole time rather than replacing it. */
.calc-panel.compact { width: min(560px, calc(100vw - 32px)); }
.calc-panel.compact .calc-host { min-height: 0; }
.calc-panel.compact .desmos-host { height: min(52vh, 400px); min-height: 300px; }

@media (max-width: 900px) {
  .calc-panel.floating { width: calc(100vw - 24px); }
}

.calc { display: flex; min-height: 430px; font-family: var(--font-body); }
.calc-side {
  width: 250px; flex: none;
  border-right: 1px solid var(--line);
  padding: 14px;
  display: flex; flex-direction: column; gap: 8px;
  background: var(--slate-50);
}
.calc-rows { display: grid; gap: 8px; }
.calc-row {
  display: flex; align-items: center; gap: 8px;
  background: #fff;
  border: 1.5px solid var(--line);
  border-radius: var(--r-sm);
  padding: 6px 8px;
}
.calc-row.bad { border-color: var(--red); background: var(--red-tint); }
.calc-dot { width: 11px; height: 11px; border-radius: 50%; flex: none; }
.calc-input {
  flex: 1; min-width: 0;
  border: 0; outline: none; background: none;
  font-family: var(--font-mono);
  font-size: 13.5px;
  color: var(--ink);
}
.calc-del {
  border: 0; background: none; cursor: pointer;
  color: var(--slate-400); font-size: 16px; line-height: 1; padding: 2px 4px;
}
.calc-del:hover { color: var(--red); }
.calc-help { margin-top: auto; font-size: 11px; color: var(--ink-3); line-height: 1.45; }

.calc-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.calc-canvas { flex: 1; width: 100%; min-height: 340px; display: block; cursor: grab; touch-action: none; }
.calc-canvas:active { cursor: grabbing; }
.calc-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px;
  border-top: 1px solid var(--line);
  background: #fff;
}
.calc-read {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--slate-600);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 720px) {
  .calc { flex-direction: column; }
  .calc-side { width: auto; border-right: 0; border-bottom: 1px solid var(--line); }
  .calc-help { display: none; }
}

/* --------------------------------------------------------------------------
   Schedule — month calendar grid (Schedule page). Never had CSS before;
   without it the cells stacked into a single unstyled column.
   -------------------------------------------------------------------------- */
.cal-hd { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px 0; }
.cal-hd .m { font-family: var(--font-head); font-weight: 800; font-size: 15px; color: var(--ink); }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; padding: 12px 20px 20px; }
.dow { text-align: center; font-size: 10.5px; font-weight: 800; color: var(--ink-3); padding-bottom: 6px; }
.cal-day {
  aspect-ratio: 1 / 1;
  display: grid; place-items: center;
  border-radius: 8px;
  font-size: 12.5px; font-weight: 600; color: var(--ink-2);
}
.cal-day.off { visibility: hidden; }
.cal-day.active { background: var(--green-tint); color: var(--green-dark); font-weight: 800; }
.cal-day.today { outline: 2px solid var(--blue); outline-offset: -2px; }
.cal-day.sat { background: var(--amber-tint); color: var(--amber-dark); font-weight: 800; }

/* --------------------------------------------------------------------------
   Schedule — hero countdown card
   -------------------------------------------------------------------------- */
.hero-sat-body { display: flex; align-items: center; gap: 32px; flex-wrap: wrap; }
.hero-sat-gen { flex: none; margin-left: auto; }
.hero-sat-count { display: grid; justify-items: center; min-width: 120px; }
.hero-sat-n { font-family: var(--font-head); font-weight: 800; font-size: 56px; line-height: 1; color: var(--blue); }
.hero-sat-lbl { font-size: 12.5px; font-weight: 700; color: var(--ink-3); text-align: center; max-width: 130px; }
.hero-sat-info { flex: 1; min-width: 220px; }
.hero-sat-date { font-family: var(--font-head); font-weight: 800; font-size: 22px; color: var(--ink); }

/* --------------------------------------------------------------------------
   Schedule — full-width, plain-calendar-app style month grid. Every cell is
   a button that opens that day's lesson plan.
   -------------------------------------------------------------------------- */
.cal-full { overflow: hidden; }
.cal-hd-full {
  display: flex; align-items: center; gap: 4px;
  padding: 18px 20px;
  border-bottom: 1px solid var(--line);
}
.cal-hd-full .m { font-family: var(--font-head); font-weight: 800; font-size: 19px; color: var(--ink); margin-left: 10px; }

/* Shown in place of nothing when a student has no plan yet — the calendar
   below it still works, so this explains rather than blocks. */
.cal-empty-note {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--blue-tint);
}
.cal-empty-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.cal-empty-txt b { font-size: 13.5px; color: var(--ink); }
.cal-empty-txt span { font-size: 12.5px; color: var(--ink-2); line-height: 1.45; }
@media (max-width: 560px) {
  .cal-empty-note { gap: 12px; }
  .cal-empty-note .btn { width: 100%; }
}

.cal-dow-row { display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid var(--line); }
.cal-dow-row .dow {
  padding: 10px 0; font-size: 12.5px; font-weight: 700; color: var(--ink-2); text-align: center;
}

.cal-grid-full { display: grid; grid-template-columns: repeat(7, 1fr); }
/* Height is fixed, never min-height: generating a plan must not resize the
   month. Lessons compress and clip inside the cell instead of growing it. */
.cal-cell-full {
  position: relative;
  height: 122px;
  padding: 8px 8px 6px;
  /* All four borders declared, not just the two that draw the grid. A cell is
     a <button>, and a button with only border-right/border-bottom set keeps
     the browser's default `2px outset ButtonBorder` on the other two — which
     is the heavy dark outline that used to box in every day of the month. The
     top and left stay transparent so the shared 1px line comes from exactly
     one neighbour and never doubles up. */
  border: 1px solid transparent;
  border-right-color: var(--line);
  border-bottom-color: var(--line);
  text-align: left;
  background: #fff;
  font: inherit; cursor: pointer;
  display: flex; flex-direction: column; align-items: flex-start; gap: 5px;
  overflow: hidden;
  transition: background .12s var(--ease);
}
.cal-grid-full > :nth-child(7n) { border-right-color: transparent; }
.cal-cell-full:hover { background: var(--slate-50); }
.cal-cell-full .n { font-size: 14px; font-weight: 600; color: var(--ink-2); }
.cal-cell-full.out { background: var(--slate-50); cursor: default; }
.cal-cell-full.out .n { color: var(--ink-3); }
.cal-cell-full.today { background: var(--blue-tint); }
.cal-cell-full.today .n {
  display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  background: var(--blue); color: #fff; font-weight: 800; font-size: 13px;
}
.cal-cell-full.sat { background: var(--amber-tint); }
.cal-cell-full.sat .n { color: var(--amber-dark); font-weight: 800; }
.cal-cell-full .tag {
  font-size: 9.5px; font-weight: 800; color: #fff; background: var(--amber-dark);
  padding: 1px 6px; border-radius: var(--pill); letter-spacing: .03em;
}
.cal-cell-full.done { background: var(--green-tint); }

/* Lesson chips inside a day cell — full-width rectangles with the skill name,
   truncated with an ellipsis rather than shrinking the cell. */
.cal-cell-top { display: flex; align-items: center; gap: 6px; flex: none; height: 22px; }
.cal-events {
  display: flex; flex-direction: column; gap: 2px;
  width: 100%; min-width: 0;
  flex: 1 1 0; min-height: 0; overflow: hidden;
}
.cal-event {
  display: block; width: 100%; flex: none;
  padding: 2px 5px;
  border-radius: 4px;
  border-left: 3px solid var(--blue);
  background: var(--blue-tint);
  color: var(--blue-dark);
  font-size: 10.5px; font-weight: 600; line-height: 1.3;
  text-align: left;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cal-event.done {
  border-left-color: var(--green); background: var(--green-tint); color: var(--green-dark);
  text-decoration: line-through; opacity: .7;
}
.cal-more { font-size: 9.5px; font-weight: 700; color: var(--ink-3); padding-left: 3px; flex: none; }

@media (max-width: 720px) {
  .cal-cell-full { height: 72px; padding: 5px; gap: 3px; }
  .cal-cell-full .n { font-size: 12px; }
  .cal-cell-top { height: 18px; }
  .cal-event { font-size: 9px; padding: 1px 4px; }
  .cal-more { display: none; }
  .hero-sat-body { gap: 20px; }
  .hero-sat-n { font-size: 42px; }
  .hero-sat-gen { margin-left: 0; }
}

/* ==========================================================================
   Ranked Arena — rank hero, ladder, and the 1v1 duel sheet.
   Every tier drives its own colorway through --rank / --rank-edge.
   ========================================================================== */
.rank-hero {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center; gap: 22px;
  padding: 26px 28px;
  color: #fff;
  background: linear-gradient(135deg, var(--rank-edge), var(--rank));
  position: relative; overflow: hidden;
}
.rank-hero::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 140% at 100% -10%, rgba(255, 255, 255, .22), transparent 55%);
}
.rank-hero > * { position: relative; }
.rank-hero .eyebrow { color: rgba(255, 255, 255, .78); }
/* The emblem sits on the hero's own gradient, so a translucent white disc
   behind it just washed the whole thing out into a soft blob. A defined ring
   and a tighter shadow give it an edge to read against instead. */
.rank-hero-badge {
  display: grid; place-items: center;
  padding: 10px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .1);
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .35),
              0 8px 22px rgba(0, 0, 0, .26);
}
.rank-hero-badge .rank-emblem { filter: drop-shadow(0 2px 5px rgba(0, 0, 0, .3)); }
.rank-hero-n { font: 800 34px var(--font-head); letter-spacing: -.02em; line-height: 1.1; }
.rank-hero-sub { font-size: 14px; color: rgba(255, 255, 255, .9); margin-top: 2px; }
.rank-track {
  height: 8px; border-radius: var(--pill); overflow: hidden;
  background: rgba(0, 0, 0, .22); max-width: 340px;
}
.rank-track > i { display: block; height: 100%; border-radius: var(--pill); background: #fff; }
.ladder { max-height: 560px; overflow-y: auto; scroll-behavior: smooth; }
.ladder-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--line);
  border-left: 3px solid transparent;
  transition: background var(--t), border-color var(--t);
}
.ladder-row:last-child { border-bottom: none; }
.ladder-n { font-size: 14px; font-weight: 700; color: var(--ink); }
.ladder-row:hover { background: var(--slate-50); }
.ladder-em { display: flex; flex: none; }

/* Reached: the emblem in full colour, on a tint of its own tier. */
.ladder-row.reached .ladder-em {
  border-radius: 50%;
  background: color-mix(in srgb, var(--rank) 16%, #fff);
}

/* Not yet reached: still the tier's colour, just drained of weight. Enough to
   read the ladder as bronze → silver → gold → …, not enough to compete with
   the tiers actually earned. */
.ladder-row.locked .ladder-em { opacity: .34; filter: saturate(.55); }
.ladder-row.locked .ladder-n { color: var(--ink-3); font-weight: 600; }

.ladder-row.on {
  background: color-mix(in srgb, var(--rank) 14%, #fff);
  border-left-color: var(--rank-edge);
}
.ladder-row.on .ladder-n { color: var(--rank-edge); }

.ladder-tick, .ladder-lock { display: flex; flex: none; }
.ladder-tick { color: var(--rank-edge); }
.ladder-lock { color: var(--slate-300); }
.ladder-tick svg, .ladder-lock svg { width: 15px; height: 15px; }

.ladder-count {
  margin-left: auto;
  font-size: 12px; font-weight: 700; color: var(--ink-3);
}

.rank-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px 3px 4px; border-radius: var(--pill);
  font-size: 12px; font-weight: 700;
  color: var(--rank-edge);
  background: color-mix(in srgb, var(--rank) 18%, #fff);
}

/* --- Standing stats strip ------------------------------------------------ */
.rank-stats {
  display: grid; grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--line);
}
.rank-stat { padding: 14px 10px; text-align: center; border-right: 1px solid var(--line); }
.rank-stat:last-child { border-right: 0; }
.rank-stat .v { font: 800 22px var(--font-head); line-height: 1.1; color: var(--ink); }
.rank-stat.win .v { color: var(--green-dark); }
.rank-stat.loss .v { color: var(--red-dark); }
.rank-stat .k {
  margin-top: 3px; font-size: 11.5px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--ink-3);
}

/* --- Duel call-to-action card -------------------------------------------- */
.duel-cta { position: relative; overflow: hidden; background: linear-gradient(135deg, #4F46E5, #7C5CF6); }
.duel-cta-glow {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 160% at 110% -20%, rgba(255, 255, 255, .3), transparent 55%);
}
.duel-cta-in {
  position: relative; display: flex; align-items: center; gap: 16px;
  padding: 20px 22px; color: #fff; flex-wrap: wrap;
}
.duel-cta-ic {
  flex: none; width: 46px; height: 46px; border-radius: 14px;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .18);
}
.duel-cta-ic svg { width: 24px; height: 24px; }
.duel-cta-t { font: 800 20px var(--font-head); }
.duel-cta-p { font-size: 13.5px; line-height: 1.45; color: rgba(255, 255, 255, .85); margin-top: 2px; }
.duel-cta-btn {
  flex: none; background: #fff; color: #4F46E5; border: 0; font-weight: 800;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .2);
}
.duel-cta-btn:hover { background: rgba(255, 255, 255, .9); transform: translateY(-1px); }

/* --- Compete hub: stats bar, gamemode selector, condensed rank panel ----- */
.compete-stack { display: flex; flex-direction: column; gap: 16px; }

/* --- Rank rail: the full twenty-tier ladder as one horizontal strip ------- */
.rank-rail { padding: 0; overflow: hidden; }

.rail-head {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 16px 20px; color: #fff;
  background: linear-gradient(135deg, var(--rank), var(--rank-edge));
}
.rail-head .eyebrow { color: rgba(255, 255, 255, .78); }
.rail-head-em { flex: none; display: flex; filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .28)); }
.rail-head-id { min-width: 0; }
.rail-head-n { font: 800 26px var(--font-head); letter-spacing: -.02em; line-height: 1.15; }
.rail-head-sub { font-size: 13.5px; color: rgba(255, 255, 255, .9); }
.rail-head-next { margin-left: auto; min-width: 220px; }
.rail-head-next .tiny { color: rgba(255, 255, 255, .86); }
.rail-track { height: 8px; border-radius: var(--pill); background: rgba(0, 0, 0, .24); overflow: hidden; }
.rail-track i { display: block; height: 100%; border-radius: var(--pill); background: #fff; transition: width var(--t); }

.rail-scroll { overflow-x: auto; overflow-y: hidden; padding: 18px 20px 16px; }
.rail { display: flex; min-width: max-content; }
.rail-node {
  position: relative; flex: none; width: 88px;
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  text-align: center;
}
/* Connector back to the previous tier, lit only as far as the player has
   climbed — the ladder reads as one continuous track, not twenty chips. */
.rail-link {
  position: absolute; top: 20px; right: 50%; width: 88px; height: 3px;
  background: var(--slate-200); border-radius: var(--pill);
}
.rail-node:first-child .rail-link { display: none; }
.rail-link.lit { background: var(--rank-edge); }

.rail-em { position: relative; z-index: 1; display: flex; }
/* Two lines' worth of room whether or not the name wraps ("Grand Champion"
   does), so every rating figure below sits on the same baseline. */
.rail-n { font-size: 11.5px; font-weight: 700; color: var(--ink-2); line-height: 1.2; min-height: 28px; }
.rail-req { font-size: 10.5px; font-weight: 700; color: var(--ink-3); }
.rail-node.locked .rail-em { opacity: .32; filter: saturate(.5); }
.rail-node.locked .rail-n { color: var(--ink-3); font-weight: 600; }
.rail-node.on .rail-em::after {
  content: ''; position: absolute; inset: -6px; border-radius: 50%;
  border: 2px solid var(--rank-edge);
}
.rail-node.on .rail-n { color: var(--rank-edge); font-weight: 800; }
.rail-you {
  font-size: 9px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: #fff; background: var(--rank-edge); padding: 2px 8px; border-radius: var(--pill);
}
@media (max-width: 640px) {
  .rail-head-next { margin-left: 0; width: 100%; min-width: 0; }
}

.stuff-bar {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  padding: 16px 20px;
}
.stuff-who { display: flex; align-items: center; gap: 12px; min-width: 0; }
.stuff-name { font-weight: 800; font-size: 15px; color: var(--ink); }
.stuff-stats { display: flex; align-items: center; gap: 20px; margin-left: auto; }
.stuff-stat { text-align: center; }
.stuff-stat .v { font: 800 18px var(--font-head); color: var(--ink); line-height: 1.1; }
.stuff-stat .k { font-size: 10.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--ink-3); margin-top: 2px; }
/* On a narrow bar this wraps onto its own row. `margin-left: auto` keeps it
   flush right there too, so the wrap reads as a deliberate second row rather
   than a stray group that fell out of alignment. */
.stuff-side { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.stuff-actions { display: flex; gap: 8px; }
.stuff-actions .icon-btn {
  width: 38px; height: 38px; border-radius: var(--r-sm);
  border: 1px solid var(--line); background: var(--card);
  display: grid; place-items: center; color: var(--ink-2);
  transition: background var(--t), border-color var(--t), color var(--t);
}
.stuff-actions .icon-btn:hover { border-color: var(--blue); color: var(--blue); background: var(--blue-tint); }

/* The season is the clock every ranked mode runs against, so it sits in the
   identity strip rather than being buried in the leaderboard modal. */
.season-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: var(--pill);
  font-size: 12px; color: var(--ink-2);
  background: var(--slate-100);
}
.season-chip b { color: var(--ink); }
.season-chip svg { width: 14px; height: 14px; color: var(--ink-3); }

.gm-label {
  font-size: 12px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ink-3); margin: 20px 0 10px;
}
.gm-label:first-child { margin-top: 0; }

/* --- Mode tiles ----------------------------------------------------------
   Big, coloured, and unmistakably clickable. Each mode owns a gradient so
   the four read as four *places to go* at a glance, the way a game lobby
   does, rather than four rows of the same card. */
/* Four narrow columns rather than a 2x2 block: the tiles get tall enough to
   carry the artwork properly and the page stops ending in dead space. */
.mode-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
@media (max-width: 1080px) { .mode-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .mode-grid { grid-template-columns: 1fr; } }

.mode-tile {
  position: relative; overflow: hidden; text-align: left;
  border: 0; padding: 0; border-radius: var(--r-md);
  background: linear-gradient(135deg, var(--from), var(--to));
  color: #fff; cursor: pointer;
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: clamp(220px, 34vh, 310px);
  box-shadow: var(--sh-xs);
  transition: transform var(--t), box-shadow var(--t), filter var(--t);
}
.mode-tile::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 130% at 100% -20%, rgba(255, 255, 255, .3), transparent 58%);
}
.mode-tile:hover { transform: translateY(-3px); box-shadow: 0 14px 34px rgba(15, 23, 42, .22); filter: brightness(1.06); }
.mode-tile:active { transform: translateY(-1px); transition-duration: .08s; }

.mode-tile-art { position: absolute; inset: 0; display: grid; place-items: center; }
/* Oversized, low-contrast mark — reads as artwork behind the label instead
   of a second icon competing with it. */
.mode-tile-art { align-items: flex-start; padding-top: 14%; }
.mode-tile-ic { opacity: .22; transform: rotate(-10deg); }
.mode-tile-ic svg { width: 132px; height: 132px; }

.mode-tile-body { position: relative; padding: 18px; }
.mode-tile-n { font: 800 21px var(--font-head); letter-spacing: -.01em; }
.mode-tile-tag { font-size: 12.5px; color: rgba(255, 255, 255, .86); margin-top: 2px; }
.mode-tile-flag {
  position: absolute; top: 12px; right: 12px; z-index: 1;
  font-size: 9.5px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: #fff; background: rgba(0, 0, 0, .26); padding: 3px 9px; border-radius: var(--pill);
}

/* --- Mode sheet (variant picker) ---------------------------------------- */
.mode-sheet-hero {
  display: flex; align-items: center; gap: 14px;
  padding: 16px 18px; border-radius: var(--r-md); color: #fff;
  background: linear-gradient(135deg, var(--from), var(--to));
}
.mode-sheet-ic {
  flex: none; width: 42px; height: 42px; border-radius: 12px;
  display: grid; place-items: center; background: rgba(255, 255, 255, .2);
}
.mode-sheet-ic svg { width: 22px; height: 22px; }
.mode-sheet-tag { font-size: 14px; font-weight: 700; }
.mode-sheet-blurb { font-size: 13.5px; line-height: 1.55; color: var(--ink-2); margin-top: 14px; }

.var-grid { display: grid; gap: 10px; }
.var-btn {
  display: flex; align-items: center; gap: 12px; text-align: left;
  padding: 14px 16px; border-radius: var(--r-sm);
  border: 1px solid var(--line); background: var(--card); cursor: pointer;
  transition: border-color var(--t), background var(--t), transform var(--t), box-shadow var(--t);
}
.var-btn:hover { border-color: var(--blue); background: var(--blue-tint); transform: translateY(-1px); box-shadow: var(--sh-sm); }
.var-ic {
  flex: none; width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center; background: var(--slate-100); color: var(--ink-2);
}
.var-ic svg { width: 17px; height: 17px; }
.var-n { font-weight: 800; font-size: 14.5px; color: var(--ink); }
.var-note { font-size: 12px; color: var(--ink-3); margin-top: 1px; }
.var-n-q { flex: none; font: 800 15px var(--font-head); color: var(--blue); }

.rank-panel-hd { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px 0; }
.rank-panel-hd .lb-title { font-weight: 800; font-size: 13.5px; }
.rank-mini { max-height: none; }
.rank-mini .ladder-row { padding: 8px 16px; }
.rank-mini-more {
  display: block; width: 100%; text-align: center; padding: 12px;
  font-size: 12.5px; font-weight: 700; color: var(--blue); border-top: 1px solid var(--line);
}
.rank-mini-more:hover { background: var(--blue-tint); }

/* ==========================================================================
   1v1 duel — a full-screen arena
   A duel is the marquee event on this page, so it takes the whole viewport
   and runs on its own dark palette rather than sitting inside a modal.
   ========================================================================== */
body.duel-open { overflow: hidden; }

/* The arena's understudy.

   `.duel-fs` is `position: fixed; inset: 0` — exactly the viewport and not a
   pixel more — and every impact animation moves it: shake translates it up to
   10px, quake up to 16px plus a rotation, and the open/close animations scale
   it. Each of those slides the arena off its own footprint and puts the light
   app background into the gap, so a hit flashed white slivers down the edges
   of the screen — the one moment the effect most needs to feel solid.

   This layer paints the same gradient one z-index below and never animates,
   so whatever the arena uncovers is more arena. It also means the impact
   animations can be as violent as they like without ever being clipped to the
   viewport's edges. */
body.duel-open::before {
  content: '';
  position: fixed; inset: 0; z-index: 199;
  background: radial-gradient(120% 90% at 50% 0%, #1E1B4B, #0B1020 62%, #060814);
  pointer-events: none;
}

.duel-fs {
  position: fixed; inset: 0; z-index: 200;
  display: flex; flex-direction: column; align-items: center;
  /* The mode tag and Forfeit pill float over this box at the top corners. The
     stage is capped at 780px and centred, so below ~1020px its edges reach
     under them and the scoreboard's names disappear behind the chrome —
     reserve a band tall enough to clear both at every width. */
  padding: 72px 20px 32px;
  overflow-y: auto;
  /* Setting only overflow-y would compute overflow-x to `auto` rather than
     leaving it visible, so any effect that reaches past the left or right edge
     earns a horizontal scrollbar. Nothing in the arena is ever meant to be
     scrolled to sideways. */
  overflow-x: hidden;
  background: radial-gradient(120% 90% at 50% 0%, #1E1B4B, #0B1020 62%, #060814);
  color: #fff;
  animation: duelIn .32s var(--ease-out) both;
}
.duel-fs.out { animation: duelOut .22s var(--ease-out) both; }
@keyframes duelIn  { from { opacity: 0; transform: scale(1.03); } }
@keyframes duelOut { to   { opacity: 0; transform: scale(.985); } }
/* Impact knocks move the CONTENT, never `.duel-fs` itself.

   Two reasons, and the first is the subtle one. `.duel-fs` already carries
   `animation: duelIn` above; writing `animation` again in a `.shake` rule
   replaces it, and taking the class back off restores `duelIn` as a *new*
   animation — so the whole arena replayed its 320ms entrance (opacity 0 → 1,
   scale 1.03 → 1) after every single answer. That is the flash.

   The second is that a fixed, full-viewport element cannot be translated
   without sliding its own painted edge inward and showing whatever sits
   behind it. Keeping the shell still and knocking only what is inside it
   fixes both at once, and reads no less like an impact — the screen-wide
   vignette below is what actually sells the hit. */
.duel-fs.shake .duel-stage { animation: duelShake .32s var(--ease-out); will-change: transform; }
@keyframes duelShake {
  0%, 100% { transform: translate3d(0, 0, 0); }
  20% { transform: translate3d(-5px, 0, 0); } 45% { transform: translate3d(4px, 0, 0); }
  70% { transform: translate3d(-2px, 0, 0); }
}
/* The clash impact — one firmer knock. Translate only: the old one also
   rotated and scaled the whole stage, which re-rasterised every question
   card and scoreboard inside it on each of its frames. */
.duel-fs.quake .duel-stage { animation: duelQuake .38s cubic-bezier(.3, 0, .2, 1); will-change: transform; }
@keyframes duelQuake {
  0%, 100% { transform: translate3d(0, 0, 0); }
  15% { transform: translate3d(-7px, 3px, 0); } 38% { transform: translate3d(6px, -3px, 0); }
  62% { transform: translate3d(-3px, 1px, 0); } 85% { transform: translate3d(1px, 0, 0); }
}

/* Screen-edge feedback on every answer: the arena itself reacts, not just the
   scoreboard, so a hit lands even when you're reading the question. */
.duel-fs.hit::after, .duel-fs.blown::after {
  content: ''; position: fixed; inset: 0; z-index: 4; pointer-events: none;
  animation: vignette .62s var(--ease-out) both;
}
.duel-fs.hit::after {
  background: radial-gradient(115% 76% at 50% 114%, rgba(16, 185, 129, .8), rgba(16, 185, 129, .2) 44%, transparent 64%);
}
.duel-fs.blown::after {
  background: radial-gradient(102% 80% at 50% 50%, transparent 24%, rgba(225, 29, 72, .34) 54%, rgba(190, 18, 60, .85));
}
@keyframes vignette { 0% { opacity: 0; } 14% { opacity: 1; } 100% { opacity: 0; } }

/* Ambient background: slow drifting orbs over a faint grid. */
.duel-bg { position: fixed; inset: 0; pointer-events: none; overflow: hidden; }
/* Static radial gradients, not blurred discs.

   These were `filter: blur(70px)` circles drifting for 17s. A blur that large
   is rasterised from a layer several times its own size, and keeping it
   moving meant the GPU redid that work every frame underneath everything
   else in the arena — which is where the lag in every other effect came
   from. A radial gradient looks the same at rest, costs nothing, and since
   it no longer moves there is nothing left to compete with the animations
   that matter. */
.duel-bg .orb { position: absolute; border-radius: 50%; opacity: .5; }
.duel-bg .o1 { width: 560px; height: 560px; top: -200px; left: -180px; background: radial-gradient(closest-side, #4F46E5, transparent); }
.duel-bg .o2 { width: 520px; height: 520px; bottom: -220px; right: -180px; background: radial-gradient(closest-side, #C026D3, transparent); }
.duel-bg .o3 { width: 440px; height: 440px; top: 36%; left: 46%; background: radial-gradient(closest-side, #0EA5E9, transparent); opacity: .32; }
.duel-grid {
  position: absolute; inset: 0; opacity: .16;
  background-image: linear-gradient(rgba(255,255,255,.12) 1px, transparent 1px),
                    linear-gradient(90deg, rgba(255,255,255,.12) 1px, transparent 1px);
  background-size: 46px 46px;
  mask-image: radial-gradient(80% 60% at 50% 40%, #000, transparent 78%);
}

/* Above the letterbox: forfeiting has to stay reachable through the clash. */
.duel-quit {
  position: absolute; top: 22px; right: 24px; z-index: 9;
  display: flex; align-items: center; gap: 6px;
  padding: 9px 15px; border-radius: var(--pill);
  border: 1px solid rgba(255, 255, 255, .18);
  background: rgba(255, 255, 255, .09); color: rgba(255, 255, 255, .82);
  font-size: 13px; font-weight: 700; cursor: pointer;
  transition: var(--t);
}
.duel-quit:hover { background: rgba(255, 255, 255, .14); color: #fff; }
.duel-quit svg { width: 15px; height: 15px; }

.duel-stage { position: relative; z-index: 2; width: 100%; max-width: 780px; margin: auto 0; }
.duel-msg { text-align: center; padding: 80px 10px; color: rgba(255, 255, 255, .7); }

/* --- Hit / miss bursts ---------------------------------------------------- */
.duel-fx { position: fixed; top: 24%; z-index: 5; pointer-events: none; display: grid; place-items: center; }
.duel-fx.me { left: 15%; }
.duel-fx.them { right: 15%; }
.duel-fx .fx-n {
  font: 900 78px var(--font-head); line-height: 1;
  color: #34D399; text-shadow: 0 0 28px rgba(52, 211, 153, .85);
  animation: fxFloat .9s var(--ease-out) both; will-change: transform, opacity;
}
.duel-fx .fx-ring {
  position: absolute; width: 64px; height: 64px; border-radius: 50%;
  border: 3px solid rgba(52, 211, 153, .9);
  animation: fxRing .7s var(--ease-out) both; will-change: transform, opacity;
}
.duel-fx.miss .fx-n { color: #FB7185; text-shadow: 0 0 28px rgba(248, 113, 113, .85); }
.duel-fx.miss .fx-ring { border-color: rgba(251, 113, 133, .9); }
@keyframes fxFloat {
  0%   { opacity: 0; transform: translate3d(0, 18px, 0) scale(.5); }
  25%  { opacity: 1; transform: translate3d(0, 0, 0) scale(1.15); }
  40%  { transform: translate3d(0, -4px, 0) scale(1); }
  65%  { opacity: 1; transform: translate3d(0, -14px, 0) scale(1); }
  100% { opacity: 0; transform: translate3d(0, -48px, 0) scale(.95); }
}
/* No border-width in the keyframes: animating it re-lays-out the ring every
   frame, and a ring that thins as it grows is what scaling it does anyway. */
@keyframes fxRing {
  0%   { opacity: .9; transform: scale(.3); }
  100% { opacity: 0; transform: scale(3); }
}

/* Three of your own in a row. Deliberately loud — it's the only moment in a
   match that celebrates something other than the final score. */
/* Sits in the gap between the mode tag and the scoreboard. Absolute, not
   fixed, so it shares the tag and forfeit button's frame of reference — a
   percentage-from-top put it square on the score bar, which is the one thing
   you actually want to read when a streak fires. */
/* Waiting on the opponent after a blitzed match — deliberately calm. This is
   dead time by design, so it gets a slow pulse and their score still ticking,
   not a spinner that implies something is stuck. */
.duel-wait { display: grid; place-items: center; gap: 12px; padding: 42px 20px; text-align: center; }
.duel-wait h3 { margin: 0; font: 800 22px var(--font-head); color: #fff; }
.duel-wait .duel-sub { margin: 0; color: rgba(255, 255, 255, .72); font-size: 14px; }
.duel-wait-em { position: relative; display: grid; place-items: center; }
.duel-wait-pulse {
  position: absolute; inset: -14px; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .28);
  animation: duelWaitPulse 1.9s ease-out infinite;
}
@keyframes duelWaitPulse {
  0%   { transform: scale(.86); opacity: .85; }
  100% { transform: scale(1.22); opacity: 0; }
}
.duel-wait-pips { display: flex; gap: 6px; margin-top: 2px; }
.duel-wait-pips i {
  width: 9px; height: 9px; border-radius: 50%;
  background: rgba(255, 255, 255, .22);
  transition: background .3s ease, transform .3s ease;
}
.duel-wait-pips i.done { background: #FB7185; transform: scale(1.15); }
@media (prefers-reduced-motion: reduce) {
  .duel-wait-pulse { animation: none; opacity: .4; }
}

.duel-streak {
  position: absolute; left: 50%; top: 82px; z-index: 6; pointer-events: none;
  display: flex; align-items: baseline; gap: 9px;
  padding: 9px 22px; border-radius: var(--pill);
  background: linear-gradient(135deg, #F59E0B, #EC4899);
  box-shadow: 0 12px 38px rgba(236, 72, 153, .55), 0 0 0 1px rgba(255, 255, 255, .18) inset;
  animation: streakIn 1.3s var(--ease-out) both;
}
.duel-streak b { font: 900 27px var(--font-head); line-height: 1; }
.duel-streak span { font-size: 11px; font-weight: 900; letter-spacing: .2em; }
@keyframes streakIn {
  0%   { opacity: 0; transform: translateX(-50%) translateY(16px) scale(.4); }
  16%  { opacity: 1; transform: translateX(-50%) translateY(0) scale(1.14); }
  28%  { transform: translateX(-50%) translateY(0) scale(1); }
  78%  { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
  100% { opacity: 0; transform: translateX(-50%) translateY(-26px) scale(.92); }
}

/* --- Matchmaking radar ---------------------------------------------------- */
.duel-search { display: grid; justify-items: center; gap: 6px; padding: 60px 10px; text-align: center; }
.duel-search h3 { font: 800 25px var(--font-head); margin-top: 22px; letter-spacing: -.01em; }
.duel-sub { font-size: 14px; font-weight: 600; color: rgba(255, 255, 255, .62); }
.radar { position: relative; width: 132px; height: 132px; display: grid; place-items: center; }
.radar i {
  position: absolute; inset: 0; margin: auto;
  width: 132px; height: 132px; border-radius: 50%;
  border: 2px solid #818CF8;
  opacity: 0; animation: radarPing 2.1s var(--ease-out) infinite;
}
.radar i:nth-child(2) { animation-delay: .7s; }
.radar i:nth-child(3) { animation-delay: 1.4s; }
.radar-core {
  position: relative; width: 54px; height: 54px; border-radius: 50%;
  display: grid; place-items: center;
  background: linear-gradient(135deg, #6366F1, #A855F7);
  box-shadow: 0 0 34px rgba(129, 140, 248, .7);
  animation: corePulse 2.1s var(--ease-out) infinite;
}
.radar-core svg { width: 26px; height: 26px; color: #fff; }
/* Sweep hand, masked into an annulus so it reads as a radar rather than a
   spinning pie wedge. */
.radar-sweep {
  position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0 288deg,
    rgba(129, 140, 248, .32) 330deg, rgba(199, 210, 254, .85) 360deg);
  -webkit-mask-image: radial-gradient(closest-side, transparent 30%, #000 33%);
  mask-image: radial-gradient(closest-side, transparent 30%, #000 33%);
  animation: radarSweep 2.1s linear infinite;
}
@keyframes radarSweep { to { transform: rotate(360deg); } }
@keyframes radarPing { 0% { transform: scale(.3); opacity: .9; } 100% { transform: scale(1); opacity: 0; } }
@keyframes corePulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.09); } }
.duel-dots { display: flex; gap: 7px; margin-top: 16px; }
.duel-dots i {
  width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, .35);
  animation: dotBob 1.2s ease-in-out infinite;
}
.duel-dots i:nth-child(2) { animation-delay: .15s; }
.duel-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes dotBob { 0%, 100% { opacity: .3; transform: translateY(0); } 50% { opacity: 1; transform: translateY(-5px); } }

/* --- Match found: the lock-on beat --------------------------------------- */
.found {
  position: relative; display: grid; justify-items: center; gap: 2px;
  padding: 66px 10px; text-align: center;
}
.found-burst {
  position: absolute; left: 50%; top: 128px; width: 520px; height: 520px;
  margin: -260px 0 0 -260px; pointer-events: none;
  background: radial-gradient(closest-side, rgba(129, 140, 248, .55), transparent 70%);
  animation: foundBurst .8s var(--ease-out) both;
}
@keyframes foundBurst {
  0% { opacity: 0; transform: scale(.3); } 25% { opacity: 1; } 100% { opacity: 0; transform: scale(1.5); }
}
.found-ring {
  position: absolute; left: 50%; top: 128px; width: 120px; height: 120px;
  margin: -60px 0 0 -60px; border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, .85); pointer-events: none;
  animation: foundRing .9s var(--ease-out) both;
}
.found-ring.r2 { border-color: rgba(129, 140, 248, .75); animation-delay: .14s; }
@keyframes foundRing {
  0% { opacity: 1; transform: scale(.25); } 100% { opacity: 0; transform: scale(3.4); }
}
.found-em {
  position: relative;
  animation: foundEm .55s cubic-bezier(.2, .9, .25, 1) both;
}
.found-em::after {
  content: ''; position: absolute; inset: -22%; border-radius: 50%; z-index: -1;
  background: radial-gradient(closest-side, var(--c), transparent 72%); opacity: .5;
}
@keyframes foundEm {
  0%   { opacity: 0; transform: scale(1.7); }
  100% { opacity: 1; transform: scale(1); }
}
.found-k {
  margin-top: 22px; font-size: 11.5px; font-weight: 900;
  letter-spacing: .28em; text-indent: .28em; text-transform: uppercase;
  color: #A5B4FC; animation: rise .4s .2s var(--ease-out) both;
}
.found-n {
  font: 900 34px var(--font-head); letter-spacing: -.02em; margin-top: 4px;
  animation: rise .45s .28s var(--ease-out) both;
}
.found-r {
  font-size: 12.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  animation: rise .45s .34s var(--ease-out) both;
}
.found-sub {
  margin-top: 12px; font-size: 13px; font-weight: 600;
  color: rgba(255, 255, 255, .55); animation: rise .45s .42s var(--ease-out) both;
}

/* --- VS clash -------------------------------------------------------------
   A fighting-game curtain raiser: letterbox closes, both fighters ram in on
   angled panels, and the impact is a white quake with a shockwave and sparks
   out of the seam. Timings are hand-tuned against each other — the flash,
   quake, shockwave and VS all land on the same beat at ~480ms. */
/* Breaks out of the 780px stage column: the clash owns the whole viewport, or
   the fighters can't actually come from opposite edges of the screen. */
/* `overflow: hidden` is load-bearing, not tidiness: the two fighter panels fly
   in from translateX(±118%) and the speed lines cross 190vw, all of which sit
   outside the viewport for the first half-second. Unclipped they widen the
   scrollable area of `.duel-fs` above, which answers with a horizontal
   scrollbar and a pale gutter down the side of the arena — mid-intro, exactly
   when the screen is supposed to be at its most solid. */
/* Absolute against .duel-fs (itself a fixed, full-viewport box) rather than
   `fixed`. Identical geometry, but immune to the quake's transform on the
   stage — see the note in compete.js's vsIntro. */
.vs { position: absolute; inset: 0; z-index: 210; display: grid; place-items: center; overflow: hidden; }
/* Darkens the corners so the collision at centre carries the frame — without
   it two same-tier fighters wash the whole screen one flat colour. */
.vs::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: radial-gradient(76% 66% at 50% 50%, transparent 38%, rgba(3, 5, 14, .74));
}

/* Cinematic letterbox. One animation per bar rather than two, so the retract
   at the end doesn't fight the slide-in for control of `transform`. */
.vs-bar {
  position: absolute; left: 0; right: 0; height: 8vh; z-index: 7;
  background: #05070f; pointer-events: none;
}
.vs-bar.top { top: 0; animation: barTop 2s both; will-change: transform; }
.vs-bar.bot { bottom: 0; animation: barBot 2s both; will-change: transform; }
@keyframes barTop {
  0%   { transform: translate3d(0, -100%, 0); animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  18%  { transform: translate3d(0, 0, 0); }
  86%  { transform: translate3d(0, 0, 0); animation-timing-function: cubic-bezier(.7, 0, .84, 0); }
  100% { transform: translate3d(0, -100%, 0); }
}
@keyframes barBot {
  0%   { transform: translate3d(0, 100%, 0); animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  18%  { transform: translate3d(0, 0, 0); }
  86%  { transform: translate3d(0, 0, 0); animation-timing-function: cubic-bezier(.7, 0, .84, 0); }
  100% { transform: translate3d(0, 100%, 0); }
}

.vs-arena {
  position: absolute; inset: 0; z-index: 2;
  display: grid; grid-template-columns: 1fr 1fr;
}
/* Angled panels leaving a diagonal gap down the middle — the gap *is* the
   divider, so no separate element has to be aligned to it. */
.vs-panel {
  position: relative; overflow: hidden;
  padding: 40px 30px; text-align: center;
  display: grid; justify-items: center; align-content: center; gap: 2px;
}
.vs-panel::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(64% 62% at 50% 42%, var(--c), transparent 72%),
    linear-gradient(180deg, rgba(255, 255, 255, .08), transparent 55%);
  opacity: .58;
}
.vs-panel.left  { clip-path: polygon(0 0, 100% 0, calc(100% - 64px) 100%, 0 100%); animation: panelL .6s .05s cubic-bezier(.16, 1, .3, 1) both; will-change: transform, opacity; }
.vs-panel.right { clip-path: polygon(64px 0, 100% 0, 100% 100%, 0 100%); animation: panelR .6s .05s cubic-bezier(.16, 1, .3, 1) both; will-change: transform, opacity; }
@keyframes panelL {
  0%   { opacity: 0; transform: translate3d(-100%, 0, 0); }
  100% { opacity: 1; transform: translate3d(0, 0, 0); }
}
@keyframes panelR {
  0%   { opacity: 0; transform: translate3d(100%, 0, 0); }
  100% { opacity: 1; transform: translate3d(0, 0, 0); }
}

.vs-em { position: relative; }
.vs-em::after {
  content: ''; position: absolute; inset: -20%; border-radius: 50%; z-index: -1;
  background: radial-gradient(closest-side, var(--c), transparent 72%); opacity: .55;
}
.vs-nm {
  font: 900 clamp(17px, 2.4vw, 23px) var(--font-head); margin-top: 18px;
  letter-spacing: -.01em; text-shadow: 0 2px 16px rgba(0, 0, 0, .7);
}
.vs-rk {
  font-size: 11.5px; font-weight: 900; letter-spacing: .14em; text-transform: uppercase;
  color: var(--c); filter: brightness(1.35);
}

/* A light down the seam. Clipped as a parallelogram rather than skewed, so it
   tracks the panels' diagonal exactly at any viewport height — a skew angle
   would only line up at one aspect ratio. */
.vs-seam {
  position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: linear-gradient(180deg, transparent, rgba(255, 255, 255, .9) 45%, transparent);
  clip-path: polygon(calc(50% + 30px) 0, calc(50% + 34px) 0, calc(50% - 30px) 100%, calc(50% - 34px) 100%);
  animation: seamLit .8s .4s var(--ease-out) both;
}
@keyframes seamLit { 0% { opacity: 0; } 14% { opacity: 1; } 100% { opacity: .18; } }

.vs-mid {
  position: absolute; left: 50%; top: 50%; z-index: 5;
  font: 900 clamp(58px, 11vw, 118px) var(--font-head); letter-spacing: -.06em; line-height: 1;
  animation: vsSlam .6s .4s linear both; will-change: transform, opacity;
}
.vs-mid span {
  display: block;
  background: linear-gradient(180deg, #FFF7DA 6%, #FDE68A 34%, #F59E0B 70%, #B45309);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 22px rgba(245, 158, 11, .8));
}
/* The centring translate has to be repeated in every step — an animated
   transform replaces the static one outright, it doesn't compose with it.

   Scale and opacity only. This used to rotate and animate `filter: blur()`,
   and an animated filter is repainted on the CPU every frame — exactly the
   frames where the flash, the shockwave and the quake were all running too.
   The easing is per-keyframe so the big first leg is a plain ease-out and
   the settle lives in the second. */
@keyframes vsSlam {
  0%   { opacity: 0; transform: translate3d(-50%, -50%, 0) scale(2.4);
         animation-timing-function: cubic-bezier(.16, .84, .26, 1); }
  58%  { opacity: 1; transform: translate3d(-50%, -50%, 0) scale(.94);
         animation-timing-function: cubic-bezier(.3, 0, .2, 1); }
  100% { opacity: 1; transform: translate3d(-50%, -50%, 0) scale(1); }
}

.vs-flash {
  position: fixed; inset: 0; z-index: 6; pointer-events: none;
  background: radial-gradient(65% 55% at 50% 50%, #fff, rgba(199, 210, 254, .7) 52%, rgba(99, 102, 241, .25) 78%, transparent);
  animation: vsFlash .5s .4s var(--ease-out) both;
}
@keyframes vsFlash { 0% { opacity: 0; } 9% { opacity: 1; } 100% { opacity: 0; } }

.vs-shock {
  position: absolute; left: 50%; top: 50%; width: 240px; height: 240px; z-index: 4;
  margin: -120px 0 0 -120px; border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, .9); pointer-events: none;
  animation: vsShock .8s .42s cubic-bezier(.08, .8, .2, 1) both; will-change: transform, opacity;
}
@keyframes vsShock {
  0%   { opacity: .9; transform: scale(.1); }
  100% { opacity: 0; transform: scale(4.5); }
}

.vs-go {
  position: absolute; left: 0; right: 0; bottom: 8%; z-index: 6; text-align: center;
  font: 900 clamp(28px, 5.4vw, 48px) var(--font-head);
  letter-spacing: .3em; text-indent: .3em; color: #fff;
  text-shadow: 0 0 30px rgba(129, 140, 248, .9);
  animation: goSlam .45s 1.15s cubic-bezier(.16, .84, .26, 1) both; will-change: transform, opacity;
}
@keyframes goSlam {
  0%   { opacity: 0; transform: scale(1.8); }
  100% { opacity: 1; transform: scale(1); }
}

/* --- Arena scoreboard ----------------------------------------------------- */
.duel-score {
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; gap: 18px;
  padding: 16px 20px; margin-bottom: 18px;
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: var(--r-lg);
  background: rgba(255, 255, 255, .08);
  animation: rise .4s var(--ease-out) both;
}
.duel-side { display: flex; align-items: center; gap: 12px; }
.duel-side.them { justify-content: flex-end; }
.duel-meta { min-width: 0; flex: 1; }
.duel-meta.r { text-align: right; }
.duel-who { font-size: 12.5px; font-weight: 700; color: rgba(255, 255, 255, .68); margin-bottom: 5px; }
.duel-bar { height: 7px; border-radius: 4px; background: rgba(255, 255, 255, .14); overflow: hidden; }
.duel-bar i {
  display: block; height: 100%; border-radius: 4px; width: 0;
  background: linear-gradient(90deg, #34D399, #10B981);
  transition: width .45s var(--ease-out);
}
.duel-bar.foe { direction: rtl; }
.duel-bar.foe i { background: linear-gradient(90deg, #FB7185, #E11D48); }
.duel-n { font: 900 32px var(--font-head); line-height: 1; min-width: 30px; text-align: center; }
.duel-n.pop { animation: scorePop .45s var(--ease-out); }
@keyframes scorePop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.45); }
  100% { transform: scale(1); }
}
.duel-mid { display: grid; justify-items: center; gap: 7px; }
.duel-vs { font-size: 12px; font-weight: 800; color: rgba(255, 255, 255, .55); letter-spacing: .04em; }
.duel-pips { display: flex; gap: 5px; }
.duel-pips i {
  width: 7px; height: 7px; border-radius: 50%;
  background: rgba(255, 255, 255, .22);
  transition: background var(--t), transform var(--t);
}
.duel-pips i.done { background: #818CF8; }
.duel-pips i.now { background: #fff; transform: scale(1.5); box-shadow: 0 0 12px rgba(255, 255, 255, .8); }

/* --- Arena question ------------------------------------------------------- */
.duel-q {
  padding: 24px 26px 26px;
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: var(--r-lg);
  background: rgba(255, 255, 255, .07);
}
/* Only a genuinely new question rises in. The card is rebuilt to mark an
   answer and again on every click that browses another choice's explanation;
   re-running the entrance on those reads as the page reloading. */
.duel-q.enter { animation: rise .4s .06s var(--ease-out) both; }
.duel-qn {
  font-size: 11.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: #A5B4FC; margin-bottom: 10px;
}
.duel-q .stem { font-size: 16px; color: #fff; }
.duel-q .stem * { color: inherit; }

/* The passage or figure a question refers to.

   Capped and scrolled in its own right rather than left to grow: a reading
   passage is often taller than the viewport, and letting it push the choices
   below the fold means racing an opponent while hunting for the buttons. */
.duel-stim {
  max-height: 38vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin-bottom: 18px;
  padding: 16px 18px;
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .04);
  font-size: 15px;
  line-height: 1.62;
}
.duel-stim, .duel-stim * { color: rgba(255, 255, 255, .9); }
.duel-stim::-webkit-scrollbar { width: 10px; }
.duel-stim::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, .18); border-radius: 6px;
  border: 3px solid transparent; background-clip: content-box;
}
.duel-stim::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, .3); background-clip: content-box; }

/* Figures and tables arrive drawn for a white page — near-black SVG strokes,
   slate table ink — and bring their own white plate with them. The blanket
   white-ink rules above would paint their text out on that plate, so hand
   these back their light-theme colours and give the plate some margin so it
   doesn't sit flush against the artwork. */
.duel-q .qfig, .duel-stim .qfig { padding: 12px; }
.duel-q .qtable, .duel-q .qtable *,
.duel-stim .qtable, .duel-stim .qtable * { color: var(--slate-700); }
.duel-q .qtable th, .duel-stim .qtable th { color: var(--slate-900); }
/* The caption sits above the plate, on the dark card — so it is the one part
   of a table that keeps the arena's own ink rather than the slate above. */
.duel-q .qtable caption, .duel-stim .qtable caption { color: rgba(255, 255, 255, .92); }

/* Choices invert onto the dark arena. */
.duel-q .choice {
  background: rgba(255, 255, 255, .06);
  border-color: rgba(255, 255, 255, .16);
  color: #fff;
}
/* Rendered choice bodies (KaTeX spans, <p>, tables) carry the light-theme ink
   colour, which is invisible here — force everything inside onto white. */
.duel-q .choice, .duel-q .choice * { color: #fff; }
.duel-q .choice { position: relative; overflow: hidden; }
.duel-q .choice:hover { background: rgba(255, 255, 255, .13); border-color: #A5B4FC; }
.duel-q .choice .letter { background: rgba(255, 255, 255, .1); border-color: rgba(255, 255, 255, .28); color: #fff; }
.duel-q .choice.correct { background: rgba(16, 185, 129, .22); border-color: #34D399; }
.duel-q .choice.correct .letter { background: #10B981; border-color: #10B981; }
.duel-q .choice.wrong { background: rgba(225, 29, 72, .22); border-color: #FB7185; }
.duel-q .choice.wrong .letter { background: #E11D48; border-color: #E11D48; }
/* The verdict animates on the draw that reveals it, and only then — the
   colours below stay put while you click around reading the explanations. */
.duel-q .choices.verdict .choice.correct { animation: correctPop .55s var(--ease-out) both; }
.duel-q .choices.verdict .choice.wrong { animation: wrongJolt .4s var(--ease-out) both; }
@keyframes correctPop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.02); }
  100% { transform: scale(1); }
}
@keyframes wrongJolt {
  0%, 100% { transform: translateX(0); }
  22% { transform: translateX(-7px); } 44% { transform: translateX(6px); } 70% { transform: translateX(-3px); }
}
/* A light sweeping across the right answer, so the eye is pulled to it even
   when the wrong choice you picked is the one you're staring at. */
.duel-q .choices.verdict .choice.correct::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 32%, rgba(255, 255, 255, .38) 50%, transparent 68%);
  animation: choiceSweep .75s .08s var(--ease-out) both;
}
@keyframes choiceSweep { from { transform: translateX(-110%); } to { transform: translateX(110%); } }

/* Only the unanswered set staggers in — replaying it after a pick would make
   the reveal feel like a page change instead of a verdict. */
.duel-q .choices.stagger .choice { animation: choiceIn .36s calc(var(--i) * .06s + .08s) var(--ease-out) both; }
@keyframes choiceIn { from { opacity: 0; transform: translateY(12px); } }
.duel-next {
  background: linear-gradient(135deg, #6366F1, #A855F7); border: 0;
  box-shadow: 0 8px 24px rgba(99, 102, 241, .45);
}
.duel-next:hover { transform: translateY(-2px); box-shadow: 0 12px 30px rgba(99, 102, 241, .6); }

/* --- Finale --------------------------------------------------------------- */
.duel-end {
  position: relative; text-align: center; padding: 40px 10px;
  display: grid; justify-items: center; gap: 4px;
}
.duel-endflash {
  position: fixed; inset: 0; z-index: 5; pointer-events: none;
  background: radial-gradient(60% 50% at 50% 34%, #fff, rgba(253, 230, 138, .5) 50%, transparent 76%);
  animation: endFlash .7s var(--ease-out) both;
}
.duel-end.loss .duel-endflash {
  background: radial-gradient(120% 100% at 50% 50%, transparent 34%, rgba(225, 29, 72, .6));
}
@keyframes endFlash { 0% { opacity: 0; } 8% { opacity: 1; } 100% { opacity: 0; } }

/* Two ray fans turning against each other — a single fan reads as a spinning
   texture, a counter-rotating pair reads as light. */
.duel-rays {
  position: absolute; top: 4%; left: 50%; width: 620px; height: 620px;
  margin-left: -310px; pointer-events: none; opacity: .5;
  background: conic-gradient(from 0deg, transparent 0 6deg, rgba(255,255,255,.16) 6deg 12deg);
  -webkit-mask-image: radial-gradient(closest-side, #000 20%, transparent 72%);
  mask-image: radial-gradient(closest-side, #000 20%, transparent 72%);
  animation: raySpin 22s linear infinite;
}
.duel-rays.r2 {
  width: 460px; height: 460px; margin-left: -230px; top: 8%; opacity: .3;
  background: conic-gradient(from 0deg, transparent 0 10deg, rgba(253, 230, 138, .3) 10deg 20deg);
  animation: raySpinB 31s linear infinite;
}
.duel-rays { will-change: transform; }
.duel-rays.r2 { display: none; }
.duel-end.loss .duel-rays { opacity: .16; }
.duel-end.loss .duel-rays.r2 { display: none; }
@keyframes raySpin  { to { transform: rotate(360deg); } }
@keyframes raySpinB { to { transform: rotate(-360deg); } }
/* Must exclude the rays: they are absolutely positioned decoration, and
   promoting them to relative puts their 620px back in flow and shoves the
   whole result card off the bottom of the screen. */
.duel-end > *:not(.duel-rays) { position: relative; z-index: 1; }
.duel-end h3 {
  font: 900 clamp(40px, 7vw, 60px) var(--font-head); letter-spacing: .06em; margin-top: 14px;
  animation: verdictIn .55s .18s cubic-bezier(.2, 1.2, .38, 1) both;
}
.duel-end.win h3 {
  background: linear-gradient(180deg, #FFF7DA 8%, #FDE68A 40%, #F59E0B 78%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 22px rgba(245, 158, 11, .7));
}
.duel-end.loss h3 { color: #FB7185; text-shadow: 0 0 30px rgba(225, 29, 72, .55); }
.duel-end.draw h3 { color: rgba(255, 255, 255, .9); }
@keyframes verdictIn {
  0%   { opacity: 0; transform: scale(1.5); }
  60%  { opacity: 1; transform: scale(.97); }
  100% { opacity: 1; transform: scale(1); }
}

.duel-end-em {
  position: relative;
  animation: emblemIn .7s cubic-bezier(.2, 1.2, .36, 1) both;
}
@keyframes emblemIn {
  0%   { opacity: 0; transform: scale(1.9) rotate(-14deg); }
  100% { opacity: 1; transform: scale(1) rotate(0); }
}
/* Ring thrown off by the emblem landing. */
.end-shock {
  position: absolute; left: 50%; top: 50%; width: 110px; height: 110px;
  margin: -55px 0 0 -55px; border-radius: 50%; pointer-events: none;
  border: 3px solid rgba(255, 255, 255, .85);
  animation: endShock .8s .2s cubic-bezier(.1, .8, .2, 1) both; will-change: transform, opacity;
}
.duel-end.loss .end-shock { border-color: rgba(251, 113, 133, .7); }
@keyframes endShock {
  0%   { opacity: .9; transform: scale(.3); }
  100% { opacity: 0; transform: scale(3.6); }
}

.duel-final {
  display: flex; align-items: baseline; gap: 14px;
  font: 900 clamp(44px, 8vw, 62px) var(--font-head); letter-spacing: -.02em; margin-top: 4px;
  animation: rise .45s .3s var(--ease-out) both;
}
.duel-dash { opacity: .4; font-size: .6em; }
.duel-vsline { font-size: 14px; font-weight: 600; color: rgba(255, 255, 255, .6); animation: rise .45s .38s var(--ease-out) both; }
.duel-rating {
  display: flex; align-items: baseline; gap: 8px;
  margin-top: 18px; padding: 11px 22px; border-radius: var(--pill);
  border: 1px solid rgba(255, 255, 255, .16);
  background: rgba(255, 255, 255, .08);
  animation: rise .45s .46s var(--ease-out) both;
}

/* Where the new rating leaves you inside the tier — a win should visibly move
   something, not just print a number. */
.duel-prog {
  width: min(320px, 78vw); margin-top: 14px;
  animation: rise .45s .56s var(--ease-out) both;
}
.duel-prog-track {
  height: 7px; border-radius: var(--pill);
  background: rgba(255, 255, 255, .14); overflow: hidden;
}
.duel-prog-track > i {
  display: block; height: 100%; border-radius: var(--pill);
  background: linear-gradient(90deg, #818CF8, #C084FC);
  box-shadow: 0 0 14px rgba(129, 140, 248, .8);
  animation: progFill .9s .62s cubic-bezier(.2, .9, .25, 1) both;
}
/* Only a `from` keyframe: the 100% state is the inline width the view set. */
@keyframes progFill { from { width: 0; } }
.duel-prog-k {
  margin-top: 7px; font-size: 11.5px; font-weight: 700;
  color: rgba(255, 255, 255, .58); text-align: center;
}
.duel-prog-k b { color: #fff; }
.duel-delta { font: 900 24px var(--font-head); }
.duel-delta.win { color: #34D399; }
.duel-delta.loss { color: #FB7185; }
.duel-delta.draw { color: rgba(255, 255, 255, .75); }
.duel-rating-k { font-size: 12.5px; font-weight: 700; color: rgba(255, 255, 255, .6); }
.duel-total { font: 900 24px var(--font-head); color: #fff; margin-left: 4px; }
.duel-end .row { animation: rise .45s .72s var(--ease-out) both; }
.duel-btn-quiet {
  background: rgba(255, 255, 255, .08); border: 1px solid rgba(255, 255, 255, .18); color: #fff;
}
.duel-btn-quiet:hover { background: rgba(255, 255, 255, .16); }

/* Replaces the rating readout when a match was never going to cost anything —
   silence there would read as a bug, so the arena says so plainly. */
.duel-norank {
  margin-top: 16px; font-size: 13px; font-weight: 700;
  color: rgba(255, 255, 255, .62);
  animation: rise .45s .38s var(--ease-out) both;
}

/* --- Which mode am I actually in? --------------------------------------- */
.stage-tag {
  position: absolute; top: 18px; left: 20px; z-index: 9;
  display: flex; align-items: center; gap: 8px;
  padding: 7px 14px; border-radius: var(--pill);
  font-size: 12.5px; color: rgba(255, 255, 255, .9);
  background: linear-gradient(135deg, var(--from), var(--to));
  box-shadow: 0 6px 18px rgba(0, 0, 0, .28);
}
.stage-tag b { font-weight: 800; }
.stage-unranked {
  font-size: 9.5px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  background: rgba(0, 0, 0, .28); padding: 2px 8px; border-radius: var(--pill);
}

/* --- Training: progress strip and the post-answer explanation ------------ */
.train-bar {
  display: flex; align-items: center; gap: 14px;
  width: min(760px, 92vw); margin: 0 auto 18px;
  color: rgba(255, 255, 255, .8); font-size: 12.5px;
}
.train-count { font-weight: 800; color: #fff; flex: none; }
.train-track {
  flex: 1; height: 6px; border-radius: var(--pill);
  background: rgba(255, 255, 255, .16); overflow: hidden;
}
.train-track > i {
  display: block; height: 100%; border-radius: var(--pill);
  background: linear-gradient(90deg, #8B5CF6, #EC4899);
  transition: width .35s var(--ease-out);
}
.train-score { flex: none; }
.train-score b { color: #fff; font-weight: 800; }

.train-reveal {
  margin-top: 16px; padding: 14px 16px; border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .06);
  border-left: 3px solid rgba(255, 255, 255, .3);
  color: rgba(255, 255, 255, .82); font-size: 13.5px; line-height: 1.6;
  animation: rise .3s var(--ease-out) both;
}
.train-reveal.ok { border-left-color: #34D399; }
.train-reveal.no { border-left-color: #FB7185; }
.train-verdict {
  display: flex; align-items: center; gap: 7px;
  font-weight: 800; font-size: 13px; margin-bottom: 8px; color: #fff;
}
.train-reveal.ok .train-verdict { color: #34D399; }
.train-reveal.no .train-verdict { color: #FB7185; }
.train-reveal .rationale { color: rgba(255, 255, 255, .82); }

@media (max-width: 620px) {
  .stage-tag { top: 14px; left: 14px; font-size: 11.5px; padding: 6px 11px; }
  .vs-panel { padding: 30px 12px; }
  /* Two 108px emblems plus the VS don't fit across 375px — the glyph ends up
     sitting on top of them. */
  .vs-em svg { width: 74px; height: 74px; }
  .vs-nm { font-size: 15px; margin-top: 14px; }
  .vs-rk { font-size: 10px; }
  .vs-panel.left  { clip-path: polygon(0 0, 100% 0, calc(100% - 32px) 100%, 0 100%); }
  .vs-panel.right { clip-path: polygon(32px 0, 100% 0, 100% 100%, 0 100%); }
  .vs-seam { clip-path: polygon(calc(50% + 14px) 0, calc(50% + 17px) 0, calc(50% - 14px) 100%, calc(50% - 17px) 100%); }
  .vs-bar { height: 6vh; }
  /* At 375px the avatar, score and 18px gaps eat the row and the name/health
     column collapses to ~23px. Tighten everything so the bar keeps real width
     and the opponent's name stays on one line. */
  .duel-score { padding: 12px 12px; gap: 8px; }
  .duel-side { gap: 8px; }
  .duel-n { font-size: 24px; min-width: 20px; }
  .duel-who {
    font-size: 11.5px; margin-bottom: 4px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .duel-fx .fx-n { font-size: 52px; }
  .duel-fx.me { left: 8%; } .duel-fx.them { right: 8%; }
  .found-n { font-size: 27px; }
  /* A phone has far less height to give the passage before the choices are
     pushed off-screen, and the card's own padding is already eating the width. */
  .duel-stim { max-height: 34vh; padding: 13px 14px; font-size: 14.5px; }
}

/* The clash is the one screen that would be genuinely unpleasant with motion
   sensitivity, so the impact effects are removed outright rather than sped up. */
@media (prefers-reduced-motion: reduce) {
  .duel-rays, .radar-sweep { animation: none; }
  .vs-shock, .vs-flash, .vs-seam,
  .duel-endflash, .end-shock, .duel-fs.hit::after, .duel-fs.blown::after { display: none; }
  .duel-fs.quake .duel-stage, .duel-fs.shake .duel-stage { animation: none; }
  .vs-panel.left, .vs-panel.right, .vs-mid, .vs-go, .vs-bar,
  .duel-end h3, .duel-end-em, .duel-streak, .duel-q .choices.stagger .choice {
    animation-duration: .01ms; animation-delay: 0s;
  }
}

@media (max-width: 720px) {
  .rank-hero { grid-template-columns: auto minmax(0, 1fr); }
}

/* ==========================================================================
   Home lesson deck — one card per lesson, swiped or paged through. Every
   slide is exactly as tall as the tallest one, so paging never reflows.
   ========================================================================== */
.deck-view { position: relative; overflow: hidden; }
.deck-track {
  display: flex;
  transition: transform .34s var(--ease-out);
  will-change: transform;
}
.deck-slide {
  flex: 0 0 100%;
  min-width: 0;
  padding: 24px 26px 26px;
  text-align: center;
  background: #fff;
}

.deck-kicker {
  font-size: 12px; font-weight: 800; letter-spacing: .14em;
  text-transform: uppercase; color: var(--blue);
}
.deck-slide.eng .deck-kicker { color: #C1443C; }
.deck-title {
  font: 800 27px var(--font-head);
  letter-spacing: -.02em; line-height: 1.15;
  margin: 8px 0 2px;
  min-height: 63px;
  display: flex; align-items: center; justify-content: center;
}
.deck-sub { font-size: 12.5px; font-weight: 600; color: var(--ink-3); }

.deck-art { display: block; width: 100%; max-width: 320px; height: 196px; margin: 14px auto 16px; }

.deck-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  z-index: 2;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 50%;
  background: rgba(255, 255, 255, .92);
  color: var(--slate-600);
  cursor: pointer;
  transition: var(--t);
}
.deck-nav:hover { background: #fff; color: var(--blue-dark); box-shadow: var(--sh-xs); }
.deck-nav svg { width: 17px; height: 17px; }
.deck-nav.prev { left: 10px; }
.deck-nav.next { right: 10px; }

.deck-dots {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  padding: 12px 0 14px;
  background: #fff;
}
.deck-dot {
  width: 8px; height: 8px; padding: 0;
  border: none; border-radius: var(--pill);
  background: var(--slate-300);
  cursor: pointer;
  transition: var(--t);
}
.deck-dot:hover { background: var(--slate-400); }
.deck-dot.on { width: 22px; background: var(--ink); }

@media (max-width: 720px) {
  .deck-slide { padding: 16px 18px 18px; }
  .deck-title { font-size: 23px; min-height: 54px; }
  .deck-nav { display: none; }
}

/* --- Profile hero ---------------------------------------------------------
   Same colored-header language as the rank card and daily top bar, so the
   profile reads as part of the same product instead of a bare data page. --- */
.profile-hero {
  position: relative;
  padding: 28px 30px;
  color: #fff;
  background: linear-gradient(135deg, var(--indigo), var(--blue));
}
.profile-hero h2 { font-size: 24px; color: #fff; margin-bottom: 2px; }
.profile-hero-body { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.profile-hero-id { min-width: 0; }

/* Sits between the name and the level ring, and takes the slack so neither
   side has to stretch. */
.profile-hero-goal {
  flex: 1;
  display: flex; gap: 26px; flex-wrap: wrap;
  padding-left: 6px;
}
.hero-fact-k {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: rgba(255, 255, 255, .72);
}
.hero-fact-k svg { width: 13px; height: 13px; }
.hero-fact-v {
  margin-top: 3px;
  font: 800 20px var(--font-head);
  color: #fff;
}

@media (max-width: 980px) {
  .profile-hero-goal { flex-basis: 100%; padding-left: 0; }
}

/* Settings above, level ring below — one column, so neither can land on top
   of the other however long the display name gets. */
.profile-hero-aside {
  flex: none;
  display: grid; justify-items: end; gap: 10px;
}
.profile-settings-link {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px;
  border-radius: var(--pill);
  background: rgba(255, 255, 255, .16);
  color: rgba(255, 255, 255, .92); font-size: 13px; font-weight: 700;
  transition: background var(--t), color var(--t);
}
.profile-settings-link:hover { background: rgba(255, 255, 255, .28); color: #fff; }
.profile-settings-link svg { width: 15px; height: 15px; }

.profile-ring { display: grid; justify-items: center; gap: 5px; }
.profile-ring-lbl {
  font-size: 11px; font-weight: 700;
  color: rgba(255, 255, 255, .8);
  white-space: nowrap;
}

@media (max-width: 720px) {
  .profile-hero-body { justify-content: center; text-align: center; }
  .profile-hero-aside { justify-items: center; }
}

/* --- Home rank card ------------------------------------------------------ */
.home-rank {
  padding: 20px 22px;
  color: #fff;
  background: linear-gradient(135deg, var(--rank-edge), var(--rank));
}
.home-rank-top { display: flex; align-items: center; gap: 14px; }
.home-rank-n { font: 800 23px var(--font-head); letter-spacing: -.02em; line-height: 1.15; }
.home-rank-cta { background: #fff; color: var(--rank-edge); border: none; font-weight: 800; }
.home-rank-cta:hover { background: rgba(255, 255, 255, .88); }
.home-rank-ghost {
  background: rgba(0, 0, 0, .18); color: #fff;
  border: 1px solid rgba(255, 255, 255, .35); font-weight: 700;
}
.home-rank-ghost:hover { background: rgba(0, 0, 0, .28); }

/* --- Community study groups ---------------------------------------------- */
.group-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
  gap: 12px;
}
.group-tile {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start;
  padding: 14px;
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: #fff;
  min-width: 0;
  text-align: left; font: inherit;
  transition: var(--t);
}
.group-tile.mine { border-color: var(--indigo); background: var(--indigo-tint); }
/* How many people are waiting on this group's creator — the reason "Open"
   is worth a second look instead of scrolling past. */
.group-req-badge {
  position: absolute; top: -7px; right: -7px;
  min-width: 20px; height: 20px; padding: 0 5px;
  display: grid; place-items: center;
  border-radius: var(--pill);
  background: var(--amber-dark); color: #fff;
  font-size: 11px; font-weight: 800;
  box-shadow: 0 0 0 2px #fff;
}
.group-av {
  width: 34px; height: 34px; border-radius: var(--r-sm);
  display: grid; place-items: center;
  margin-bottom: 9px;
  font: 800 15px var(--font-head); color: #fff;
  background: hsl(var(--hue) 62% 55%);
}
.group-nm { font-size: 14px; font-weight: 700; color: var(--ink); max-width: 100%; }
/* What this group races on — the whole point of joining one rather than
   another, so it sits on the tile instead of hiding inside the modal. */
.group-metric {
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: 7px;
  padding: 3px 8px;
  border-radius: var(--pill);
  background: var(--slate-100);
  font-size: 10.5px; font-weight: 700; letter-spacing: .01em;
  color: var(--slate-600);
  white-space: nowrap;
}
.group-metric svg { width: 11px; height: 11px; flex: none; }
.group-tile.mine .group-metric { background: rgba(255, 255, 255, .72); color: var(--indigo); }

/* Profile-picture editor preview. */
.pic-preview { display: grid; place-items: center; padding: 4px 0; }

.group-tile.new {
  align-items: center; justify-content: center; text-align: center;
  border-style: dashed; cursor: pointer; gap: 2px;
}
.group-tile.new:hover { border-color: var(--blue); background: var(--blue-tint); }
.group-plus {
  display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--slate-100); color: var(--slate-600);
  margin-bottom: 7px;
}
.group-tile.new:hover .group-plus { background: var(--blue); color: #fff; }

/* --- Locked practice test — content stays in the DOM (real layout, real
   weight) but blurred and non-interactive under a lock veil. ------------- */
.exam-locked { position: relative; overflow: hidden; }
.exam-locked > .card-hd,
.exam-locked > .card-strip,
.exam-locked > .card-body {
  filter: blur(5px);
  user-select: none;
  pointer-events: none;
}
.exam-locked .card-body .btn { cursor: default; }
.exam-lock-veil {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .38);
  cursor: pointer;
}
.exam-lock-veil svg {
  width: 34px; height: 34px;
  color: var(--slate-700);
  filter: drop-shadow(0 2px 6px rgba(15, 23, 42, .25));
}

/* --- Locked community feed — blurred tabs/posts behind a centered unlock
   card, so the page still reads as "there's something here" not empty. --- */
.locked-panel { position: relative; min-height: 320px; }
.locked-blur { filter: blur(4px); user-select: none; pointer-events: none; }
.locked-card {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: min(88%, 340px);
  background: #fff; border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--sh-lg);
  padding: 32px 28px; text-align: center;
}
.locked-ic {
  width: 46px; height: 46px; margin: 0 auto 14px;
  display: grid; place-items: center;
  border-radius: 50%; background: var(--blue-tint); color: var(--blue);
}
.locked-card h3 { font-size: 18px; margin-bottom: 6px; }

/* ==========================================================================
   Study buddy

   Sits under the rank card on Home. The scene is a fixed-ratio SVG, so the
   card's height never depends on which stage the creature is at — it cannot
   shove the rest of the column around as the student levels up.
   ========================================================================== */
.pet-card { overflow: hidden; }

.pet-head {
  display: flex; align-items: center; gap: 7px;
  padding: 14px 16px 0;
}
.pet-name {
  font-family: var(--font-head);
  font-size: 19px; font-weight: 800; letter-spacing: -.01em;
  color: var(--ink);
}
.pet-rename {
  display: grid; place-items: center;
  width: 22px; height: 22px; padding: 0;
  border: 0; border-radius: 50%;
  background: none; color: var(--slate-300);
  cursor: pointer;
  transition: var(--t-fast);
}
.pet-rename svg { width: 13px; height: 13px; }
.pet-rename:hover { background: var(--slate-100); color: var(--slate-600); }
.pet-lvl {
  margin-left: auto;
  padding: 4px 11px;
  border-radius: var(--pill);
  background: var(--slate-100);
  font-size: 12.5px; font-weight: 800; color: var(--ink-2);
}

.pet-bar {
  height: 7px; margin: 11px 16px 0;
  border-radius: var(--pill);
  background: var(--slate-100);
  overflow: hidden;
}
.pet-bar > i {
  display: block; height: 100%;
  border-radius: var(--pill);
  background: linear-gradient(90deg, var(--blue), var(--indigo));
  transition: width .5s var(--ease-out);
}
.pet-count {
  padding: 7px 16px 12px;
  font-size: 13px; font-weight: 700; color: var(--ink-2);
}

.pet-scene {
  position: relative;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.pet-stage { display: block; width: 100%; height: auto; }

/* Idle breathing, and a squash-and-stretch when poked. Both are transforms on
   the creature group only, so the backdrop never moves. */
.pet-body {
  transform-origin: 206px 214px;
  animation: petIdle 3.6s ease-in-out infinite;
}
@keyframes petIdle {
  0%, 100% { transform: translateY(0) scale(1, 1); }
  50%      { transform: translateY(-4px) scale(1.012, .988); }
}
.pet-body.pat { animation: petPat .62s var(--spring); }
@keyframes petPat {
  0%   { transform: translateY(0) scale(1, 1); }
  28%  { transform: translateY(4px) scale(1.09, .9); }
  60%  { transform: translateY(-10px) scale(.95, 1.06); }
  100% { transform: translateY(0) scale(1, 1); }
}

/* --- The egg -------------------------------------------------------------
   Four independent loops, deliberately on different periods so they drift out
   of phase and the scene never visibly repeats.

   These animate the individual `rotate` / `scale` / `translate` properties
   rather than `transform`. Two animations on `transform` would fight — the
   later one replaces the earlier outright — whereas the individual properties
   compose, which is what lets the egg rock and kick at the same time.
   -------------------------------------------------------------------------- */
.pet-egg {
  transform-box: fill-box;
  transform-origin: 50% 94%;          /* where the shell meets the nest */
  animation: petRock 3.6s ease-in-out infinite,
             petKick 7s ease-in-out infinite;
}
@keyframes petRock {
  0%, 100% { rotate: -3.2deg; }
  50%      { rotate: 3.2deg; }
}
/* Every seven seconds, something inside shoves. */
@keyframes petKick {
  0%, 86%, 100% { translate: 0 0; scale: 1 1; }
  89% { translate: -3px 0; scale: 1.05 .95; }
  92% { translate: 3px 0;  scale: .96 1.05; }
  95% { translate: -2px 0; scale: 1.03 .97; }
}

.pet-halo {
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: petHalo 4.2s ease-in-out infinite;
}
@keyframes petHalo {
  0%, 100% { opacity: .4; scale: .93; }
  50%      { opacity: .85; scale: 1.05; }
}

/* A narrow gleam that crosses the shell, then waits most of the cycle out. */
.pet-sheen { animation: petSheen 5.5s ease-in-out infinite; }
@keyframes petSheen {
  0%   { translate: 0 0;     opacity: 0; }
  55%  { translate: 0 0;     opacity: 0; }
  62%  { translate: 20px 0;  opacity: .3; }
  84%  { translate: 130px 0; opacity: .3; }
  92%  { translate: 155px 0; opacity: 0; }
  100% { translate: 155px 0; opacity: 0; }
}

.pet-spark {
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: petSpark 2.8s ease-in-out infinite;
  animation-delay: calc(var(--i) * .55s);
}
@keyframes petSpark {
  0%, 100% { opacity: .15; scale: .55; rotate: 0deg; }
  50%      { opacity: 1;   scale: 1;   rotate: 45deg; }
}

.pet-heart {
  position: absolute;
  width: 15px; height: 15px;
  margin: -8px 0 0 -8px;
  pointer-events: none;
  background: #FF6B8A;
  clip-path: path('M7.5 14S0 9.4 0 4.7A4.2 4.2 0 0 1 7.5 2 4.2 4.2 0 0 1 15 4.7C15 9.4 7.5 14 7.5 14Z');
  animation: petHeart .9s var(--ease-out) forwards;
}
@keyframes petHeart {
  0%   { opacity: 0; transform: translateY(0) scale(.4); }
  25%  { opacity: 1; transform: translateY(-10px) scale(1.1); }
  100% { opacity: 0; transform: translateY(-46px) scale(.85); }
}

.pet-foot {
  display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap;
  padding: 13px 16px 15px;
  border-top: 1px solid var(--line);
}
.pet-stage-n {
  font-family: var(--font-head);
  font-size: 15px; font-weight: 800; color: var(--ink);
}
.pet-blurb { font-size: 12.5px; font-weight: 600; color: var(--ink-3); }

/* The egg is the whole creature at level 0, so poking it has to answer back
   the same way the bird does. Overriding `animation` here also parks the rock
   and the kick for the duration, which is what makes the squash read. */
.pet-egg.pat { animation: petPat .62s var(--spring); }

/* --- Ambient life -------------------------------------------------------
   Four worlds that each move differently: snow drifts, embers climb, pollen
   hangs, bubbles rise. Cheap transforms on a handful of shapes — enough that
   a scene never looks like a still image, never enough to pull focus off the
   creature standing in it.
   -------------------------------------------------------------------------- */
.bd-mote {
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: bdMote 9s ease-in-out infinite;
  animation-delay: calc(var(--i) * -.7s);
}
@keyframes bdMote {
  0%, 100% { translate: 0 0;        opacity: .2; }
  50%      { translate: 7px -16px;  opacity: .85; }
}
.bio-volcano .bd-mote { animation: bdEmber 6s linear infinite; animation-delay: calc(var(--i) * -.5s); }
@keyframes bdEmber {
  0%   { translate: 0 0;         opacity: 0; }
  18%  { opacity: .95; }
  100% { translate: -12px -84px; opacity: 0; }
}
.bd-bubble {
  animation: bdBubble 7.5s linear infinite;
  animation-delay: calc(var(--i) * -.65s);
}
@keyframes bdBubble {
  0%   { translate: 0 0;        opacity: 0; }
  12%  { opacity: .75; }
  100% { translate: 9px -238px; opacity: 0; }
}
.bd-lava { animation: bdLava 4.6s ease-in-out infinite; }
@keyframes bdLava { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }

.bd-shafts { animation: bdShafts 11s ease-in-out infinite; }
@keyframes bdShafts {
  0%, 100% { opacity: .5; translate: -9px 0; }
  50%      { opacity: 1;  translate: 11px 0; }
}

/* Creature parts that move on their own, so a standing bird still reads as
   alive between idle breaths. Each uses `rotate` rather than `transform` so it
   composes with the idle animation on the group above it. */
.bd-wing {
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: bdWing 2.4s ease-in-out infinite;
}
@keyframes bdWing {
  0%, 100% { rotate: calc(var(--s) * -6deg); }
  50%      { rotate: calc(var(--s) * 7deg); }
}
.bd-tail {
  transform-box: fill-box; transform-origin: 8% 62%;
  animation: bdTail 3.2s ease-in-out infinite;
}
@keyframes bdTail { 0%, 100% { rotate: -4deg; } 50% { rotate: 6deg; } }

/* Parts positioned in absolute stage coordinates set their own
   `transform-origin` inline, so they need the view-box box model rather than
   their own bounding box. */
.bd-frill, .bd-swish, .bd-ear, .bd-kelp { transform-box: view-box; }

.bd-frill {
  animation: bdFrill 2.9s ease-in-out infinite;
  animation-delay: calc(var(--i) * .19s);
}
@keyframes bdFrill { 0%, 100% { rotate: -6deg; } 50% { rotate: 7deg; } }

/* Tails, scarf tails and anything else that trails behind a moving animal. */
.bd-swish {
  animation: bdSwish 3.6s ease-in-out infinite;
  animation-delay: calc(var(--i) * .14s);
}
@keyframes bdSwish { 0%, 100% { rotate: -5deg; } 50% { rotate: 6deg; } }

/* Ears sit still, then flick — a constant sway reads as wind, a flick reads
   as an animal deciding to listen. */
.bd-ear {
  animation: bdEar 5.4s ease-in-out infinite;
  animation-delay: calc(var(--i) * .45s);
}
@keyframes bdEar {
  0%, 84%, 100% { rotate: 0deg; }
  88%  { rotate: calc(var(--s) * 10deg); }
  93%  { rotate: calc(var(--s) * -4deg); }
}

/* Blink. A lid in the surrounding skin colour, scaled to nothing from its top
   edge — steadier than animating the pupil, and most of the reason these read
   as alive rather than as illustrations. */
.bd-lid {
  transform-box: fill-box; transform-origin: 50% 0%;
  scale: 1 0;
  animation: bdBlink 6.4s ease-in-out infinite;
  animation-delay: calc(var(--i) * -1.7s);
}
@keyframes bdBlink {
  0%, 88%, 100% { scale: 1 0; }
  90.5%, 93%    { scale: 1 1; }
  95.5%         { scale: 1 0; }
}

/* --- World motion ------------------------------------------------------- */
.bd-star {
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: bdStar 4.4s ease-in-out infinite;
  animation-delay: calc(var(--i) * -.29s);
}
@keyframes bdStar {
  0%, 100% { opacity: .25; scale: .7; }
  50%      { opacity: 1;   scale: 1.2; }
}

.bd-aur {
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: bdAur 17s ease-in-out infinite;
  animation-delay: calc(var(--i) * -6s);
}
@keyframes bdAur {
  0%, 100% { translate: -16px 0; opacity: .5; }
  50%      { translate: 18px -5px; opacity: 1; }
}

.bd-smoke {
  transform-box: fill-box; transform-origin: 50% 100%;
  animation: bdSmoke 7.5s ease-out infinite;
  animation-delay: calc(var(--i) * -1.5s);
}
@keyframes bdSmoke {
  0%   { translate: 0 0;        scale: .45; opacity: 0; }
  22%  { opacity: .34; }
  100% { translate: -22px -70px; scale: 1.8; opacity: 0; }
}

.bd-fish {
  animation: bdFish 15s ease-in-out infinite;
  animation-delay: calc(var(--i) * -3.1s);
}
@keyframes bdFish {
  0%, 100% { translate: 0 0; }
  50%      { translate: calc(var(--d) * 52px) -14px; }
}

.bd-kelp {
  animation: bdKelp 5.6s ease-in-out infinite;
  animation-delay: calc(var(--i) * -.55s);
}
@keyframes bdKelp { 0%, 100% { rotate: -6deg; } 50% { rotate: 7deg; } }

.bd-glow {
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: bdGlow 4s ease-in-out infinite;
}
@keyframes bdGlow {
  0%, 100% { opacity: .6; scale: .94; }
  50%      { opacity: 1;  scale: 1.07; }
}

.bd-float {
  animation: bdFloat 4.6s ease-in-out infinite;
  animation-delay: calc(var(--i) * -1.2s);
}
@keyframes bdFloat { 0%, 100% { translate: 0 0; } 50% { translate: 0 -6px; } }

/* --- Ready to open -------------------------------------------------------
   The one state the card exists for. Progress stops being a bar and becomes a
   single gold button, because a milestone the student walks past without
   noticing was not a milestone.
   -------------------------------------------------------------------------- */
.pet-ready-note {
  display: flex; align-items: center; gap: 7px;
  margin: 11px 16px 0; padding: 8px 12px;
  border-radius: var(--pill);
  background: linear-gradient(90deg, #FFF4D2, #FFE7A8);
  border: 1px solid #F0CE7A;
  font-size: 12.5px; font-weight: 800; color: #7A5410;
}
.pet-ready-note svg { width: 15px; height: 15px; }

.pet-scene.ready { position: relative; }
.pet-scene.ready::after {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(ellipse at 54% 52%, rgba(255,231,150,.55), transparent 58%);
  animation: petReadyGlow 2.1s ease-in-out infinite;
  pointer-events: none;
}
@keyframes petReadyGlow { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

.pet-open-ft { padding: 12px 14px 14px; border-top: 1px solid var(--line); }
.pet-open {
  background: linear-gradient(135deg, #FFD75E, #F5A623);
  border-color: #E0940E;
  color: #4A2E00;
  letter-spacing: .06em;
  box-shadow: 0 6px 0 #D08A0C, 0 12px 24px rgba(224,148,14,.36);
  animation: petOpenPulse 1.9s ease-in-out infinite;
}
.pet-open:hover { background: linear-gradient(135deg, #FFE07E, #FFB53A); }
.pet-open:active { transform: translateY(3px); box-shadow: 0 3px 0 #D08A0C; }
@keyframes petOpenPulse {
  0%, 100% { box-shadow: 0 6px 0 #D08A0C, 0 12px 24px rgba(224,148,14,.30); }
  50%      { box-shadow: 0 6px 0 #D08A0C, 0 12px 34px rgba(255,190,60,.72); }
}

/* --- No buddy yet --------------------------------------------------------
   The card keeps its slot rather than vanishing, so Home has the same shape on
   day one as on day thirty — but everything on it points at the one decision
   that has to happen first.
   -------------------------------------------------------------------------- */
.pet-empty-body { padding: 22px 18px 20px; text-align: center; }
.pet-empty-eggs { display: flex; justify-content: center; gap: 2px; margin-bottom: 12px; }
.pet-empty-egg {
  display: block;
  animation: petEggBob 3.4s ease-in-out infinite;
  animation-delay: calc(var(--i) * .3s);
}
.pet-empty-egg svg { display: block; width: 54px; height: auto; }
@keyframes petEggBob {
  0%, 100% { transform: translateY(0) rotate(-3deg); }
  50%      { transform: translateY(-7px) rotate(3deg); }
}
.pet-empty-body h3 { font-family: var(--font-head); font-size: 18px; margin-bottom: 5px; }
.pet-empty-body p { font-size: 13px; font-weight: 600; color: var(--ink-3); line-height: 1.45; }

@media (prefers-reduced-motion: reduce) {
  .pet-body, .pet-body.pat,
  .pet-egg, .pet-egg.pat, .pet-halo, .pet-sheen, .pet-spark,
  .bd-mote, .bd-bubble, .bd-lava, .bd-shafts, .bd-wing, .bd-tail, .bd-frill,
  .bd-swish, .bd-ear, .bd-lid, .bd-star, .bd-aur, .bd-smoke, .bd-fish,
  .bd-kelp, .bd-glow, .bd-float,
  .pet-empty-egg, .pet-open, .pet-scene.ready::after { animation: none; }
  /* The blink lid is only ever invisible when parked, so park it closed-open. */
  .bd-lid { scale: 1 0; }
  .pet-heart { animation-duration: .01ms; }
}

/* ==========================================================================
   Choosing a buddy

   The starter pick. Four worlds side by side, one decision, and deliberately
   no way to skip it — a buddy the student was handed is a widget, a buddy they
   chose is theirs. Lives over the app rather than as a route so it can be
   raised from anywhere and always resolves.
   ========================================================================== */
body.bd-locked { overflow: hidden; }

.bd-scrim {
  position: fixed; inset: 0; z-index: 920;
  display: flex; align-items: center; justify-content: center;
  overflow-y: auto;
  padding: 28px 20px 40px;
  background: #070B1C;
  opacity: 0;
  transition: opacity .32s var(--ease);
}
.bd-scrim.in { opacity: 1; }

/* Slow drifting colour so the backdrop is never flat black. */
.bd-aurora { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.bd-aurora i {
  position: absolute; border-radius: 50%;
  filter: blur(90px); opacity: .5;
}
.bd-aurora .a1 { width: 46vw; height: 46vw; left: -8vw;  top: -12vw; background: #2C76FF; animation: bdDrift 19s ease-in-out infinite; }
.bd-aurora .a2 { width: 40vw; height: 40vw; right: -6vw; top: 8vh;   background: #F0562F; animation: bdDrift 23s ease-in-out infinite reverse; }
.bd-aurora .a3 { width: 52vw; height: 52vw; left: 22vw;  bottom: -22vw; background: #0EA5C6; animation: bdDrift 27s ease-in-out infinite; }
@keyframes bdDrift {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(6vw, -5vh) scale(1.14); }
}

.bd-panel {
  position: relative; z-index: 2;
  width: min(1080px, 100%);
  margin: auto;
  text-align: center;
}
.bd-hd { max-width: 640px; margin: 0 auto; }
.bd-kicker {
  display: inline-block; margin-bottom: 12px;
  padding: 5px 13px; border-radius: var(--pill);
  background: rgba(255,255,255,.1);
  border: 1px solid rgba(255,255,255,.16);
  font-size: 11px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: rgba(255,255,255,.86);
}
.bd-panel h1 {
  font-family: var(--font-head);
  font-size: clamp(25px, 4.2vw, 41px); font-weight: 800; letter-spacing: -.02em;
  color: #fff; margin-bottom: 9px;
}
.bd-panel > .bd-hd p, .bd-panel-name .bd-hd p {
  font-size: 14.5px; font-weight: 600; line-height: 1.5;
  color: rgba(255,255,255,.62);
}

.bd-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px; margin: 30px 0 26px;
}
.bd-pick {
  position: relative;
  display: flex; flex-direction: column;
  padding: 0; overflow: hidden;
  border: 2px solid rgba(255,255,255,.12);
  border-radius: 20px;
  background: rgba(255,255,255,.06);
  text-align: left; cursor: pointer;
  transition: transform .3s var(--ease-out), opacity .3s var(--ease),
              border-color .2s var(--ease), box-shadow .3s var(--ease);
  animation: bdRise .6s var(--ease-out) backwards;
  animation-delay: calc(var(--i) * 90ms);
}
@keyframes bdRise {
  from { opacity: 0; transform: translateY(34px) scale(.94); }
  to   { opacity: 1; transform: none; }
}
.bd-pick:hover { transform: translateY(-7px); border-color: rgba(255,255,255,.34); }
.bd-pick-art { position: relative; background: #000; }
.bd-pick-art .pet-stage { display: block; width: 100%; height: auto; }
.bd-pick-art::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 62%, rgba(7,11,28,.55));
}
.bd-pick-body { padding: 13px 15px 16px; }
.bd-el {
  display: inline-block; margin-bottom: 7px;
  padding: 3px 10px; border-radius: var(--pill);
  background: var(--acc); color: #fff;
  font-size: 10.5px; font-weight: 900; letter-spacing: .12em; text-transform: uppercase;
}
.bd-pick-body h3 { font-family: var(--font-head); font-size: 19px; color: #fff; margin-bottom: 5px; }
.bd-pick-body p {
  font-size: 12.5px; font-weight: 600; line-height: 1.45;
  color: rgba(255,255,255,.58); min-height: 36px;
}
.bd-perk {
  display: flex; align-items: center; gap: 6px;
  margin-top: 11px; padding-top: 11px;
  border-top: 1px solid rgba(255,255,255,.12);
  font-size: 11.5px; font-weight: 800; color: var(--acc);
}
.bd-perk svg { width: 14px; height: 14px; flex: none; }

.bd-check {
  position: absolute; top: 12px; right: 12px;
  display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--acc); color: #fff;
  opacity: 0; transform: scale(.4);
  transition: .24s var(--spring);
}
/* Once a pick lands the other three step back, so the screen holds one
   creature rather than four competing ones. */
.bd-grid.picked .bd-pick { opacity: .38; transform: scale(.95); }
.bd-grid.picked .bd-pick.on {
  opacity: 1; transform: translateY(-8px) scale(1.03);
  border-color: var(--acc);
  box-shadow: 0 0 0 4px rgba(255,255,255,.1), 0 26px 50px rgba(0,0,0,.55);
}
.bd-pick.on .bd-check { opacity: 1; transform: none; }

.bd-ft { display: flex; justify-content: center; }
/* The species accent has to survive :hover, which .btn:hover would otherwise
   drag back to brand blue — and the 3D shadow under it has to stop being blue
   too, or an orange button sits on a blue slab. */
.bd-cta, .hx-cta {
  --sh3d: rgba(0,0,0,.45);
  background: var(--acc, var(--blue));
  border-color: transparent;
  letter-spacing: .02em;
}
.bd-cta:hover, .hx-cta:hover { background: var(--acc, var(--blue)); filter: brightness(1.1); }
.bd-cta { min-width: 260px; }
.bd-cta:disabled { background: rgba(255,255,255,.14); color: rgba(255,255,255,.45); box-shadow: none; }

/* --- Naming step --------------------------------------------------------- */
.bd-panel-name { max-width: 520px; }
.bd-back {
  display: inline-flex; align-items: center; gap: 6px;
  margin-bottom: 14px; padding: 7px 13px;
  border: 1px solid rgba(255,255,255,.18); border-radius: var(--pill);
  background: rgba(255,255,255,.06); color: rgba(255,255,255,.8);
  font-size: 12.5px; font-weight: 700; cursor: pointer;
  transition: var(--t-fast);
}
.bd-back:hover { background: rgba(255,255,255,.14); color: #fff; }
.bd-back svg { width: 14px; height: 14px; }

.bd-name-art {
  width: 260px; margin: 0 auto 18px;
  border-radius: 22px; overflow: hidden;
  border: 2px solid rgba(255,255,255,.16);
  box-shadow: 0 24px 60px rgba(0,0,0,.5), 0 0 0 6px rgba(255,255,255,.05);
  animation: bdPop .6s var(--spring) backwards;
}
@keyframes bdPop { from { opacity: 0; transform: scale(.8); } to { opacity: 1; transform: none; } }
.bd-name-art .pet-stage { display: block; width: 100%; height: auto; }

.bd-name-input {
  width: 100%; max-width: 320px; margin: 20px auto 0;
  text-align: center;
  font-family: var(--font-head); font-size: 21px; font-weight: 800;
  background: rgba(255,255,255,.08);
  border-color: rgba(255,255,255,.2);
  color: #fff;
}
.bd-name-input:focus { border-color: var(--acc); background: rgba(255,255,255,.14); }

.bd-chips { display: flex; justify-content: center; flex-wrap: wrap; gap: 8px; margin: 14px 0 24px; }
.bd-chip {
  padding: 7px 15px; border-radius: var(--pill);
  border: 1px solid rgba(255,255,255,.18);
  background: rgba(255,255,255,.05); color: rgba(255,255,255,.75);
  font-size: 13px; font-weight: 700; cursor: pointer;
  transition: var(--t-fast);
}
.bd-chip:hover { background: rgba(255,255,255,.14); color: #fff; }
.bd-chip.on { background: #fff; color: #0B1020; border-color: #fff; }

/* The hand-off out of the picker: one white beat, then Home. */
.bd-scrim.flash::after {
  content: ''; position: absolute; inset: 0; z-index: 3;
  background: #fff; pointer-events: none;
  animation: bdFlash .42s var(--ease-out) forwards;
}
@keyframes bdFlash { from { opacity: 0; } 60% { opacity: .95; } to { opacity: 1; } }

@media (max-width: 900px) {
  .bd-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bd-pick-body p { min-height: 0; }
}
@media (max-width: 560px) {
  .bd-grid { grid-template-columns: 1fr; gap: 12px; }
  .bd-pick { flex-direction: row; align-items: stretch; }
  .bd-pick-art { width: 132px; flex: none; }
  .bd-pick-art .pet-stage { height: 100%; }
  .bd-pick-art::after { background: linear-gradient(90deg, transparent 60%, rgba(7,11,28,.5)); }
  .bd-perk { margin-top: 8px; padding-top: 8px; }
  .bd-cta { min-width: 0; width: 100%; }
  .bd-name-art { width: 200px; }
}

@media (prefers-reduced-motion: reduce) {
  .bd-aurora i, .bd-pick, .bd-name-art { animation: none; }
}

/* ==========================================================================
   The hatch ceremony

   Three taps, escalating. The shell cracks, the light behind it gets harder to
   look at, the whole screen kicks — and on the third the shell blows apart and
   whatever was inside is standing in its own world. The tap count is the whole
   design: a reveal you watch is a cutscene, a reveal you have to hit three
   times is yours.
   ========================================================================== */
.hx {
  position: fixed; inset: 0; z-index: 930;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 24px;
  background: rgba(5,8,22,.5);
  backdrop-filter: blur(3px) saturate(.9);
  -webkit-backdrop-filter: blur(3px) saturate(.9);
  opacity: 0;
  transition: opacity .3s var(--ease), background .5s var(--ease), backdrop-filter .5s var(--ease);
}
.hx.in { opacity: 1; }
/* Every tap pulls more of the room away, so by the third the egg is the only
   thing left on screen. */
.hx.t1 { background: rgba(5,8,22,.68); backdrop-filter: blur(7px) saturate(.85); -webkit-backdrop-filter: blur(7px) saturate(.85); }
.hx.t2 { background: rgba(5,8,22,.8);  backdrop-filter: blur(12px) saturate(.75); -webkit-backdrop-filter: blur(12px) saturate(.75); }
.hx.t3 { background: rgba(4,6,18,.9);  backdrop-filter: blur(18px) saturate(.7); -webkit-backdrop-filter: blur(18px) saturate(.7); }

.hx-body { display: flex; flex-direction: column; align-items: center; }

.hx-stage {
  position: relative;
  width: min(430px, 78vw); aspect-ratio: 1;
  display: grid; place-items: center;
  cursor: pointer; user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.hx-stage > * { grid-area: 1 / 1; }

.hx-rays {
  width: 165%; aspect-ratio: 1; border-radius: 50%;
  background: repeating-conic-gradient(from 0deg,
    rgba(255,255,255,.2) 0deg 5deg, transparent 5deg 17deg);
  -webkit-mask-image: radial-gradient(closest-side, #000 12%, rgba(0,0,0,.5) 46%, transparent 76%);
  mask-image: radial-gradient(closest-side, #000 12%, rgba(0,0,0,.5) 46%, transparent 76%);
  opacity: .3;
  animation: hxSpin 30s linear infinite;
  transition: opacity .45s var(--ease);
  pointer-events: none;
}
@keyframes hxSpin { to { rotate: 360deg; } }
.hx.t1 .hx-rays { opacity: .5;  animation-duration: 20s; }
.hx.t2 .hx-rays { opacity: .72; animation-duration: 12s; }
.hx.t3 .hx-rays { opacity: .95; animation-duration: 5s; }

.hx-halo {
  width: 70%; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle, var(--acc) 0%, transparent 66%);
  filter: blur(26px); opacity: .42;
  animation: hxBreathe 3.1s ease-in-out infinite;
  pointer-events: none;
}
@keyframes hxBreathe {
  0%, 100% { opacity: .34; transform: scale(.92); }
  50%      { opacity: .7;  transform: scale(1.06); }
}
.hx.t1 .hx-halo { opacity: .6; }
.hx.t2 .hx-halo { opacity: .85; filter: blur(34px); }
.hx.t3 .hx-halo { opacity: 1; filter: blur(44px); }

.hx-core-wrap { width: 100%; animation: hxIdle 2.6s ease-in-out infinite; pointer-events: none; }
.hx-core { display: block; width: 100%; height: auto; filter: drop-shadow(0 26px 40px rgba(0,0,0,.55)); }
@keyframes hxIdle {
  0%, 100% { transform: translateY(0) rotate(-2.4deg); }
  50%      { transform: translateY(-8px) rotate(2.4deg); }
}
.hx.t1 .hx-core-wrap { animation-duration: 1.5s; }
.hx.t2 .hx-core-wrap { animation-duration: .85s; }
.hx.open .hx-core-wrap { animation: hxGone .32s var(--ease) forwards; }
@keyframes hxGone { to { opacity: 0; transform: scale(1.28); } }

/* A ring that says "this is a button" until the first tap proves it. */
.hx-ping {
  width: 40%; aspect-ratio: 1; border-radius: 50%;
  border: 3px solid rgba(255,255,255,.55);
  animation: hxPing 1.9s ease-out infinite;
  pointer-events: none;
}
@keyframes hxPing {
  0%   { opacity: .7; transform: scale(.75); }
  100% { opacity: 0;  transform: scale(1.7); }
}
.hx.t1 .hx-ping { display: none; }

/* --- Cracks -------------------------------------------------------------- */
.hx-crack { opacity: 0; }
.hx-crack.on { animation: hxCrack .34s var(--ease-out) forwards; }
@keyframes hxCrack { from { opacity: 0; } to { opacity: 1; } }
.hx-crack .gl {
  fill: none; stroke: #FFF6D0; stroke-width: 11; stroke-linecap: round; stroke-linejoin: round;
  filter: blur(5px); opacity: .95;
}
.hx-crack .ln {
  fill: none; stroke: rgba(16,12,34,.86); stroke-width: 3.4; stroke-linecap: round; stroke-linejoin: round;
}

/* --- Impact -------------------------------------------------------------- */
.hx.kick1 { animation: hxKick .3s var(--ease-out); }
.hx.kick2 { animation: hxKick2 .38s var(--ease-out); }
.hx.kick3 { animation: hxKick3 .5s var(--ease-out); }
@keyframes hxKick {
  0%, 100% { transform: translate(0, 0); }
  25% { transform: translate(-6px, 3px); }
  60% { transform: translate(5px, -2px); }
}
@keyframes hxKick2 {
  0%, 100% { transform: translate(0, 0) rotate(0); }
  18% { transform: translate(-11px, 5px) rotate(-.5deg); }
  44% { transform: translate(10px, -6px) rotate(.5deg); }
  72% { transform: translate(-5px, 3px) rotate(0); }
}
@keyframes hxKick3 {
  0%, 100% { transform: translate(0, 0) rotate(0) scale(1); }
  12% { transform: translate(-18px, 9px) rotate(-1deg) scale(1.012); }
  34% { transform: translate(16px, -11px) rotate(1deg) scale(1.012); }
  58% { transform: translate(-11px, 6px) rotate(-.6deg) scale(1.006); }
  80% { transform: translate(6px, -3px) rotate(0) scale(1); }
}

.hx-flash {
  position: absolute; inset: 0; background: #fff;
  opacity: 0; pointer-events: none;
}
.hx.open .hx-flash { animation: hxFlash .72s var(--ease-out) forwards; }
@keyframes hxFlash {
  0%  { opacity: 0; }
  8%  { opacity: .96; }
  100%{ opacity: 0; }
}

/* Sparks on every tap, shell fragments on the last one. */
.hx-burst { pointer-events: none; }
.hx-bit, .hx-shard {
  position: absolute; left: 50%; top: 50%;
  pointer-events: none;
}
.hx-bit {
  width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 50%;
  animation: hxBit .7s var(--ease-out) forwards;
  animation-delay: var(--d);
}
@keyframes hxBit {
  0%   { opacity: 1; transform: translate(0, 0) scale(1); }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(.2); }
}
.hx-shard {
  width: 26px; height: 32px; margin: -16px 0 0 -13px;
  border-radius: 6px 10px 5px 12px;
  animation: hxShard 1.1s var(--ease-out) forwards;
  animation-delay: var(--d);
}
@keyframes hxShard {
  0%   { opacity: 1; transform: translate(0, 0) rotate(0) scale(1); }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) rotate(var(--r)) scale(.5); }
}

/* --- The reveal ---------------------------------------------------------- */
.hx-reveal {
  width: 92%;
  border-radius: 26px; overflow: hidden;
  border: 3px solid rgba(255,255,255,.22);
  box-shadow: 0 30px 70px rgba(0,0,0,.6), 0 0 0 8px rgba(255,255,255,.06);
  animation: hxReveal .8s var(--spring) backwards;
}
@keyframes hxReveal {
  from { opacity: 0; transform: scale(.35) rotate(-8deg); }
  to   { opacity: 1; transform: none; }
}
.hx-reveal .pet-stage { display: block; width: 100%; height: auto; }

.hx-copy { text-align: center; max-width: 460px; margin-top: 4px; }
.hx-title {
  font-family: var(--font-head);
  font-size: clamp(23px, 4.6vw, 36px); font-weight: 800; letter-spacing: -.02em;
  color: #fff;
}
.hx.done .hx-title { animation: hxTitle .5s var(--spring); }
@keyframes hxTitle { from { opacity: 0; transform: translateY(14px) scale(.9); } to { opacity: 1; transform: none; } }
.hx-sub {
  margin-top: 6px;
  font-size: 14px; font-weight: 600; color: rgba(255,255,255,.7);
}
.hx-sub b { color: #FFD75E; font-weight: 800; }

.hx-pips { display: flex; justify-content: center; gap: 9px; margin-top: 14px; }
.hx-pips i {
  width: 11px; height: 11px; border-radius: 50%;
  background: rgba(255,255,255,.2);
  transition: .3s var(--spring);
}
.hx-pips i.on { background: #FFD75E; transform: scale(1.35); box-shadow: 0 0 14px rgba(255,215,94,.8); }

.hx-ft { margin-top: 14px; min-height: 52px; }
.hx-cta {
  min-width: 220px;
  opacity: 0; transform: translateY(12px); pointer-events: none;
  transition: .4s var(--ease-out);
}
.hx.done .hx-cta { opacity: 1; transform: none; pointer-events: auto; transition-delay: .35s; }

@media (max-width: 560px) {
  .hx-stage { width: 84vw; }
  .hx-cta { min-width: 0; width: 100%; }
  .hx-ft { width: 100%; max-width: 340px; }
}

@media (prefers-reduced-motion: reduce) {
  .hx-rays, .hx-halo, .hx-core-wrap, .hx-ping,
  .hx.kick1, .hx.kick2, .hx.kick3 { animation: none; }
  .hx-reveal { animation-duration: .01ms; }
}

/* ==========================================================================
   Profile — statistics

   Four cards in a two-up grid, then the subtopic table across the full
   width. Every card is the same object (bold title, optional control on the
   right, padded body) so the page reads as one instrument panel rather than
   four unrelated widgets.
   ========================================================================== */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
  /* Cards pair up row by row, so the two in a row share a height rather than
     leaving one of them floating with a ragged edge beside the other. */
  align-items: stretch;
}
.stat-card { display: flex; flex-direction: column; overflow: hidden; }
.stat-body { display: flex; flex-direction: column; justify-content: center; }
.stat-hd {
  display: flex; align-items: center; gap: 12px;
  padding: 18px 20px 0;
}
.stat-hd h3 {
  font-family: var(--font-head); font-size: 20px; font-weight: 800;
  color: var(--ink); margin: 0; flex: 1; min-width: 0;
}
.stat-hd-tabs { padding: 0 20px; border-bottom: 1px solid var(--line); }
.stat-body { padding: 18px 20px 20px; flex: 1; min-height: 0; }
.stat-empty {
  padding: 28px 10px; text-align: center;
  font-size: 13px; font-weight: 600; color: var(--ink-3);
}

/* Range switcher — This Week / This Month / All Time. */
.stat-seg { display: flex; gap: 6px; flex: none; }
.stat-seg button {
  padding: 6px 12px;
  border: 1px solid var(--line); border-radius: var(--pill);
  background: #fff;
  font: 700 12.5px var(--font-body);
  color: var(--ink-3); cursor: pointer; white-space: nowrap;
  transition: var(--t-fast);
}
.stat-seg button:hover { color: var(--ink); border-color: var(--slate-300); }
.stat-seg button.on { background: var(--blue); border-color: var(--blue); color: #fff; }

/* Stepper for the heatmap's date window. */
.stat-nav { display: flex; align-items: center; gap: 4px; flex: none; }
.stat-range { font-size: 13px; font-weight: 700; color: var(--ink-3); white-space: nowrap; }
.stat-step {
  width: 26px; height: 26px; border-radius: 8px; flex: none;
  display: grid; place-items: center;
  border: 0; background: none; color: var(--ink-3); cursor: pointer;
  transition: var(--t-fast);
}
.stat-step:hover:not(:disabled) { background: var(--slate-100); color: var(--ink); }
.stat-step:disabled { opacity: .3; cursor: default; }

/* --- Donut ---------------------------------------------------------------- */
.donut { position: relative; flex: none; }
.donut-svg { width: 100%; height: 100%; display: block; }
.donut-mid {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; pointer-events: none;
}
.donut-mid b {
  font-family: var(--font-head); font-size: 26px; font-weight: 800; color: var(--ink);
  line-height: 1; font-variant-numeric: tabular-nums;
}
.donut-mid span { font-size: 11.5px; font-weight: 600; color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* --- Question Progress ---------------------------------------------------- */
.qp { display: flex; align-items: center; gap: 22px; }
.qp-rows { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 14px; }
.qp-row-hd { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
.qp-row-hd b { font-size: 14.5px; font-weight: 800; color: var(--ink); flex: 1; min-width: 0; }
.qp-count { font-size: 12.5px; font-weight: 700; color: var(--ink-3); }
.qp-acc { font-size: 12.5px; font-weight: 800; }
.qp-bar { height: 7px; border-radius: var(--pill); background: var(--slate-100); overflow: hidden; }
.qp-bar i { display: block; height: 100%; border-radius: var(--pill); transition: width .5s var(--ease); }

/* One accuracy scale for the whole page, so a colour always means the same. */
.good { color: var(--green-dark); }
.ok { color: var(--amber-dark); }
.bad { color: var(--red-dark); }
.qp-bar i.good, .sub-bar i.good { background: var(--green); }
.qp-bar i.ok, .sub-bar i.ok { background: var(--amber); }
.qp-bar i.bad, .sub-bar i.bad { background: var(--red); }

/* --- Recent Activity ------------------------------------------------------ */
.act { display: flex; flex-direction: column; max-height: 232px; overflow-y: auto; }
.act-row { display: flex; align-items: center; gap: 11px; padding: 9px 0; }
.act-row + .act-row { border-top: 1px solid var(--line); }
.act-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.act-dot.blue { background: var(--blue); }
.act-dot.violet { background: #8B5CF6; }
.act-dot.pink { background: #EC4899; }
.act-txt { flex: 1; min-width: 0; font-size: 14px; font-weight: 600; color: var(--ink); }
.act-when { font-size: 12.5px; font-weight: 600; color: var(--ink-3); white-space: nowrap; }

/* --- Study Activity heatmap ----------------------------------------------- */
.heat2 { display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto 1fr; gap: 6px 8px; }
.heat2-months {
  grid-column: 2; display: grid; grid-template-columns: repeat(13, 1fr);
  font-size: 11px; font-weight: 700; color: var(--ink-3);
}
.heat2-days {
  grid-column: 1; grid-row: 2;
  display: flex; flex-direction: column; justify-content: space-around;
  font-size: 10.5px; font-weight: 700; color: var(--ink-3);
}
.heat2-grid { grid-column: 2; grid-row: 2; display: grid; grid-template-columns: repeat(13, 1fr); gap: 4px; }
/* Flex, not a 7-row grid: `1fr` rows would fight the cells' aspect-ratio for
   who decides the column's height, and the cells would come out oblong. */
.heat2-col { display: flex; flex-direction: column; gap: 4px; }
.heat2-cell { aspect-ratio: 1; border-radius: 4px; background: var(--slate-100); display: block; }
/* Five buckets scaled against the daily XP goal — a "full" day is darkest. */
.heat2-cell.l0 { background: var(--slate-100); }
.heat2-cell.l1 { background: #DBEAFE; }
.heat2-cell.l2 { background: #93C5FD; }
.heat2-cell.l3 { background: #60A5FA; }
.heat2-cell.l4 { background: var(--blue); }
.heat2-cell.future { background: transparent; }
.heat2-key {
  display: flex; align-items: center; justify-content: flex-end; gap: 4px;
  margin-top: 12px; font-size: 11px; font-weight: 700; color: var(--ink-3);
}
.heat2-key .heat2-cell { width: 11px; height: 11px; aspect-ratio: auto; }
.heat2-key span:first-child { margin-right: 3px; }
.heat2-key span:last-child { margin-left: 3px; }

/* --- Time by Area --------------------------------------------------------- */
.tba { display: flex; align-items: center; gap: 22px; }
.tba-legend { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; max-height: 200px; overflow-y: auto; }
.tba-row { display: flex; align-items: center; gap: 9px; }
.tba-swatch { width: 11px; height: 11px; border-radius: 3px; flex: none; }
.tba-lbl { flex: 1; min-width: 0; font-size: 13.5px; font-weight: 600; color: var(--ink); }
.tba-v { font-size: 13.5px; font-weight: 800; white-space: nowrap; }

/* --- Subtopics ------------------------------------------------------------ */
.sub-tabs { display: flex; gap: 26px; }
.sub-tab {
  padding: 16px 0 13px;
  border: 0; border-bottom: 3px solid transparent; background: none;
  font-family: var(--font-head); font-size: 19px; font-weight: 800;
  color: var(--slate-300); cursor: pointer;
  transition: var(--t-fast);
}
.sub-tab:hover { color: var(--ink-3); }
.sub-tab.on { color: var(--ink); border-bottom-color: var(--ink); }

.sub-filters { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 16px; }
.sub-filter {
  text-align: left; padding: 12px 16px;
  border: 2px solid var(--line); border-radius: var(--r-sm);
  background: #fff; cursor: pointer; transition: var(--t-fast);
}
.sub-filter:hover { border-color: var(--slate-300); }
.sub-filter.on { border-color: var(--ink); }
.sub-filter-l { font-size: 14.5px; font-weight: 800; color: var(--ink); }
.sub-filter-n { font-size: 13px; font-weight: 600; color: var(--ink-3); margin-top: 2px; }
/* Each filter carries its subject's colour, the same one the rows use. */
.sub-filters .sub-filter:nth-child(2) .sub-filter-l { color: var(--blue); }
.sub-filters .sub-filter:nth-child(3) .sub-filter-l { color: #8B5CF6; }

.sub-list { display: flex; flex-direction: column; }
.sub-row {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 12px 11px 0;
  cursor: pointer; border-radius: var(--r-sm);
  transition: background var(--t);
}
.sub-row:hover { background: var(--slate-50); }
.sub-row + .sub-row { border-top: 1px solid var(--line); }
.sub-tick { width: 4px; align-self: stretch; border-radius: var(--pill); flex: none; }
.sub-tick.math { background: var(--blue); }
.sub-tick.eng { background: #8B5CF6; }
.sub-id { flex: 1; min-width: 0; }
.sub-name { font-size: 14.5px; font-weight: 800; color: var(--ink); }
.sub-meta { display: flex; align-items: center; gap: 8px; margin-top: 3px; font-size: 12px; font-weight: 600; color: var(--ink-3); }
.sub-badge { padding: 1px 7px; border-radius: var(--pill); font-size: 11px; font-weight: 800; }
.sub-badge.math { background: var(--blue-tint); color: var(--blue-dark); }
.sub-badge.eng { background: #F3E8FF; color: #7C3AED; }
.sub-bar { width: 120px; height: 7px; border-radius: var(--pill); background: var(--slate-100); overflow: hidden; flex: none; }
.sub-bar i { display: block; height: 100%; border-radius: var(--pill); }
.sub-pct { width: 42px; text-align: right; font-size: 13px; font-weight: 800; flex: none; }
.sub-go { width: 16px; height: 16px; color: var(--slate-300); flex: none; }

.sub-more {
  width: 100%; margin-top: 8px; padding: 12px;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  border: 0; border-top: 1px solid var(--line); background: none;
  font: 700 13.5px var(--font-body); color: var(--blue); cursor: pointer;
}
.sub-more:hover { background: var(--slate-50); }

@media (max-width: 1080px) {
  .stat-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 620px) {
  .qp, .tba { flex-direction: column; align-items: stretch; gap: 18px; }
  .qp .donut, .tba .donut { align-self: center; }
  .sub-filters { grid-template-columns: 1fr; }
  .sub-bar { width: 64px; }
}

/* ==========================================================================
   A study group's own page

   Laid out as a place rather than a report: an identity block at the top, the
   numbers that describe the group as a single band under it, then the race on
   the left and the room on the right.
   ========================================================================== */
.group-view { display: grid; gap: 22px; align-content: start; }

.group-back {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 13px; font-weight: 700; color: var(--ink-2);
  width: fit-content;
}
.group-back:hover { color: var(--blue); }

.group-loading {
  display: grid; justify-items: center; gap: 14px;
  padding: 64px 0; color: var(--ink-3); font-size: 13.5px; font-weight: 600;
}

/* ── Identity ─────────────────────────────────────────────────────────────── */
.group-hero { overflow: hidden; }
.group-hero-body {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  padding: 22px 24px;
}
.group-hero-av {
  flex: none;
  display: grid; place-items: center;
  width: 66px; height: 66px; border-radius: 20px;
  font-family: var(--font-head); font-weight: 800; font-size: 28px; color: #fff;
  background: linear-gradient(150deg, hsl(var(--hue) 82% 62%), hsl(var(--hue) 72% 47%));
  box-shadow: 0 8px 22px hsl(var(--hue) 70% 50% / .34);
}
.group-hero-txt { min-width: 0; flex: 1; display: grid; gap: 3px; }
.group-hero-txt h1 { font-size: 27px; line-height: 1.15; }
.group-hero-sub {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  font-size: 13px; color: var(--ink-2); font-weight: 600;
}
.group-hero-sub .dot { color: var(--ink-3); }
.group-hero-standing {
  margin-top: 5px; font-size: 13px; font-weight: 700; color: var(--ink-2);
}
/* Top three is worth saying out loud. */
.group-hero-standing.hot { color: var(--amber-dark); }
.group-hero-act { flex: none; }

/* ── The numbers band ─────────────────────────────────────────────────────── */
.group-stat-row {
  display: grid; gap: 14px;
  grid-template-columns: repeat(5, minmax(0, 1fr));
}
.group-stat {
  position: relative; overflow: hidden;
  padding: 16px 16px 14px;
  border: 1px solid var(--line); border-radius: var(--r-lg, 16px);
  background: var(--card);
  display: grid; gap: 1px; align-content: start;
}
.group-stat-ic {
  position: absolute; top: 12px; right: 12px;
  opacity: .18;
}
.group-stat-ic svg { width: 30px; height: 30px; }
.group-stat-v { font-family: var(--font-head); font-weight: 800; font-size: 26px; line-height: 1.1; color: var(--ink); }
.group-stat-k { font-size: 12.5px; font-weight: 700; color: var(--ink-2); }
.group-stat-s { font-size: 11.5px; color: var(--ink-3); line-height: 1.35; margin-top: 2px; }
.group-stat.blue   { border-top: 3px solid var(--blue); }
.group-stat.blue   .group-stat-ic { color: var(--blue); }
.group-stat.indigo { border-top: 3px solid var(--indigo); }
.group-stat.indigo .group-stat-ic { color: var(--indigo); }
.group-stat.green  { border-top: 3px solid var(--green); }
.group-stat.green  .group-stat-ic { color: var(--green); }
.group-stat.amber  { border-top: 3px solid var(--amber); }
.group-stat.amber  .group-stat-ic { color: var(--amber); }
.group-stat.violet { border-top: 3px solid var(--purple); }
.group-stat.violet .group-stat-ic { color: var(--purple); }

.split.group-split { grid-template-columns: minmax(0, 1fr) minmax(320px, 380px); }

/* ── Podium ───────────────────────────────────────────────────────────────── */
/* Second, first, third — the winner in the middle and raised, the way a real
   podium reads at a glance. Plinth heights carry the ranking, so the order
   survives even when the three names are the same length. */
.group-podium {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px; align-items: end;
}
.group-podium:has(.podium-slot:nth-child(2):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.podium-slot {
  display: grid; justify-items: center; gap: 6px; min-width: 0; width: 100%;
  padding: 14px 8px 0;
  border-radius: 16px 16px 0 0;
  text-align: center;
}
.podium-medal svg { width: 22px; height: 22px; }
.podium-slot.p1 { order: 2; }
.podium-slot.p2 { order: 1; }
.podium-slot.p3 { order: 3; }
.podium-slot.p1 .podium-medal { color: var(--gold); }
.podium-slot.p2 .podium-medal { color: var(--silver); }
.podium-slot.p3 .podium-medal { color: var(--bronze); }
.podium-nm { font-size: 13px; font-weight: 700; color: var(--ink); max-width: 100%; }
.podium-val {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12.5px; font-weight: 800; color: var(--ink-2);
}
.podium-val svg { width: 13px; height: 13px; }
.podium-step {
  display: grid; place-items: center;
  width: 100%; margin-top: 6px;
  font-family: var(--font-head); font-weight: 800; font-size: 17px; color: #fff;
  border-radius: 10px 10px 0 0;
}
.podium-slot.p1 .podium-step { height: 62px; background: linear-gradient(180deg, #F2C94C, var(--gold)); }
.podium-slot.p2 .podium-step { height: 46px; background: linear-gradient(180deg, #CFD4DB, var(--silver)); }
.podium-slot.p3 .podium-step { height: 34px; background: linear-gradient(180deg, #D9A16B, var(--bronze)); }
.podium-slot.me .podium-nm { color: var(--blue); }

/* ── About panel ──────────────────────────────────────────────────────────── */
.group-about-metric { display: flex; align-items: center; gap: 12px; }
.group-about-ic {
  flex: none; display: grid; place-items: center;
  width: 40px; height: 40px; border-radius: 12px;
  background: var(--indigo-tint); color: var(--indigo);
}
.group-about-facts { display: grid; gap: 8px; }
.group-fact {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 9px 12px; border-radius: 10px; background: var(--slate-50);
}
.group-fact .k { font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.group-fact .v { font-size: 13.5px; font-weight: 800; color: var(--ink); }

/* ── Members ──────────────────────────────────────────────────────────────── */
.group-members { display: grid; gap: 8px; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
.group-member {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 7px 10px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--card);
  font-size: 12.5px; font-weight: 600; color: var(--ink-2);
}
.group-member.me { border-color: var(--blue); background: var(--blue-tint); color: var(--blue-dark); font-weight: 700; }

/* ── Group chat ───────────────────────────────────────────────────────────── */
.group-chat-card { display: flex; flex-direction: column; }
.group-chat-list {
  display: flex; flex-direction: column; gap: 10px;
  height: 340px; padding: 16px;
  overflow-y: auto;
  background: var(--slate-50);
}
.group-chat-row { display: flex; align-items: flex-end; gap: 8px; max-width: 82%; }
.group-chat-row.mine { align-self: flex-end; flex-direction: row-reverse; max-width: 82%; }
.group-chat-bubble {
  padding: 8px 12px; border-radius: 14px;
  background: #fff; border: 1px solid var(--line);
  min-width: 0;
}
.group-chat-row.mine .group-chat-bubble { background: var(--blue); border-color: var(--blue); color: #fff; }
.group-chat-who { font-size: 11px; font-weight: 800; color: var(--indigo); margin-bottom: 2px; }
.group-chat-body { font-size: 13.5px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; }
.group-chat-t { font-size: 10px; margin-top: 3px; opacity: .6; }
.group-chat-compose {
  display: flex; align-items: flex-end; gap: 8px;
  padding: 12px 16px; border-top: 1px solid var(--line);
}
.group-chat-input {
  flex: 1; resize: none; max-height: 96px;
  padding: 9px 12px; line-height: 1.4;
}

@media (max-width: 1080px) {
  .split.group-split { grid-template-columns: minmax(0, 1fr); }
  .group-stat-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .group-stat-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .group-hero-body { gap: 14px; padding: 18px; }
  .group-hero-av { width: 54px; height: 54px; border-radius: 16px; font-size: 23px; }
  .group-hero-txt h1 { font-size: 22px; }
  .group-hero-act { width: 100%; }
  .group-hero-act .btn { width: 100%; }
}
/* Two across is still comfortable on a phone and keeps the whole band on one
   screen; one across turned five short numbers into a page of scrolling.
   Only a genuinely narrow window gives up the second column. */
@media (max-width: 360px) {
  .group-stat-row { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   Lessons

   A lesson is long, and the thing students do most is come back for one part
   of it rather than read it through. So this is built for scanning: a
   contents rail that follows down the page, section headers light enough to
   read past, and the one idea worth keeping pulled out where it can't be
   missed. The previous version gave every section a heavy coloured header
   bar, which produced five identical loud stripes all claiming to be the
   most important thing on the page.
   ========================================================================== */

/* --- Index ---------------------------------------------------------------- */

/* The hero is the one place on this page allowed to be loud. Soft blurred
   shapes rather than a flat panel, so the page opens with something to look
   at instead of a grey band. */
.les-top {
  position: relative; overflow: hidden;
  display: flex; align-items: center; justify-content: space-between; gap: 28px; flex-wrap: wrap;
  padding: 30px 34px; margin-bottom: 34px;
  border-radius: 22px;
  background: linear-gradient(120deg, #EEF3FF 0%, #F6F1FF 42%, #FFF6EE 100%);
  border: 1px solid rgba(47, 107, 255, .16);
}
.les-top-shapes { position: absolute; inset: 0; pointer-events: none; }
.les-top-shapes i { position: absolute; border-radius: 50%; filter: blur(22px); opacity: .5; }
.les-top-shapes i:nth-child(1) { width: 190px; height: 190px; right: -40px; top: -70px; background: rgba(47, 107, 255, .40); }
.les-top-shapes i:nth-child(2) { width: 150px; height: 150px; right: 150px; bottom: -80px; background: rgba(139, 92, 246, .34); }
.les-top-shapes i:nth-child(3) { width: 120px; height: 120px; left: 42%; top: -60px; background: rgba(232, 137, 12, .26); }
.les-top-l { position: relative; z-index: 1; min-width: 260px; }
.les-top-k {
  display: inline-flex; align-items: center; gap: 6px; margin-bottom: 8px;
  padding: 5px 12px; border-radius: 999px; background: rgba(255, 255, 255, .78);
  border: 1px solid rgba(47, 107, 255, .2);
  font: 700 11px var(--font-body); letter-spacing: .08em; text-transform: uppercase; color: var(--blue-dk);
}
.les-top-k svg { width: 13px; height: 13px; }
.les-top-l h1 { font: 800 clamp(30px, 4vw, 42px) var(--font-head); letter-spacing: -.035em; margin: 0 0 6px; line-height: 1.05; }
.les-top-l p { margin: 0; font-size: 15px; line-height: 1.55; color: var(--ink-2); max-width: 46ch; }
.les-top-r { position: relative; z-index: 1; display: grid; justify-items: center; gap: 6px; }
.les-top-s { font: 600 12px var(--font-body); color: var(--ink-2); }

/* Subject heading with a coloured dot, so Math and Reading read apart. */
.les-sec { margin-bottom: 34px; }
.les-sec-h { display: flex; align-items: center; gap: 10px; margin: 0 0 16px; }
.les-sec-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.les-sec-dot.math { background: linear-gradient(135deg, #2F6BFF, #7C3AED); }
.les-sec-dot.english { background: linear-gradient(135deg, #E11D6F, #0EA5A5); }
.les-sec-h h2 { font: 800 21px var(--font-head); margin: 0; letter-spacing: -.028em; }
.les-sec-n { font-size: 12.5px; color: var(--ink-3); margin-left: 2px; }

/* Paging arrows for the domain scroller. They sit at the end of the section
   header, disable at each end of the track, and vanish entirely when every
   domain already fits on screen. */
.les-arrows { margin-left: auto; display: flex; gap: 8px; }
.les-sec.static .les-arrows { display: none; }
.les-arrow {
  width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line-2); background: #fff; color: var(--ink-2);
  cursor: pointer; transition: var(--t-fast);
}
.les-arrow svg { width: 16px; height: 16px; }
.les-arrow:hover:not(:disabled) { background: var(--wash); color: var(--ink); border-color: var(--line-3, var(--line-2)); }
.les-arrow:disabled { opacity: .35; cursor: default; }

/* One horizontal band per subject. A wrapping grid stranded Math's fourth
   domain alone on a second row; a scroller keeps all four in one line at any
   width. The padding gives the cards' hover shadow room the overflow would
   otherwise clip. There is deliberately no scroll-snap: the arrows already
   page by exactly one card, and snapping cancelled those smooth scrolls
   part of the time. */
.les-doms {
  display: flex; gap: 20px;
  overflow-x: auto; overscroll-behavior-x: contain;
  padding: 8px 2px 16px; margin: -8px -2px -6px;
  scrollbar-width: thin; scrollbar-color: var(--line-2) transparent;
}
.les-doms::-webkit-scrollbar { height: 8px; }
.les-doms::-webkit-scrollbar-track { background: transparent; }
.les-doms::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 999px; }
.les-doms::-webkit-scrollbar-thumb:hover { background: var(--ink-3); }
.les-doms > .les-dom { flex: 0 0 420px; }

/* Each domain carries its own hue through the icon tile, the progress bar,
   the numbered markers and the hover state — one variable, --dc, set inline
   from the theme table in lessons.js. */
.les-dom {
  position: relative; overflow: hidden;
  border: 1px solid var(--line); border-radius: 18px; background: #fff;
  transition: box-shadow .25s ease, transform .25s var(--ease), border-color .25s ease;
}
.les-dom:hover { box-shadow: 0 12px 34px -16px color-mix(in srgb, var(--dc) 55%, transparent); border-color: color-mix(in srgb, var(--dc) 34%, var(--line)); }
.les-dom.done { border-color: color-mix(in srgb, var(--dc) 40%, var(--line)); }

.les-dom-hd {
  display: flex; align-items: center; gap: 14px;
  padding: 19px 20px 17px;
  background: linear-gradient(115deg, color-mix(in srgb, var(--dc) 12%, #fff), #fff 72%);
  border-bottom: 1px solid var(--line);
}
.les-dom-ic {
  width: 46px; height: 46px; flex: none; border-radius: 14px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--dc) 15%, #fff);
  color: var(--dc);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dc) 22%, transparent);
}
.les-dom-ic svg { width: 23px; height: 23px; }
.les-dom-t { flex: 1; min-width: 0; }
.les-dom-t b { display: block; font-size: 17px; letter-spacing: -.015em; line-height: 1.25; }
.les-dom-t span { font-size: 12.5px; color: var(--ink-3); }
.les-dom-pill {
  flex: none; display: inline-flex; align-items: center; gap: 4px;
  padding: 5px 11px; border-radius: 999px;
  border: 1px solid var(--line-2); background: #fff;
  font: 700 11.5px var(--font-num, var(--font-body)); color: var(--ink-3);
}
.les-dom-pill svg { width: 12px; height: 12px; }
.les-dom-pill.on { background: color-mix(in srgb, var(--dc) 14%, #fff); border-color: color-mix(in srgb, var(--dc) 38%, transparent); color: var(--dc); }

.les-dom-bar { height: 4px; background: color-mix(in srgb, var(--dc) 12%, #fff); }
.les-dom-bar i { display: block; height: 100%; background: var(--dc); transition: width .5s var(--ease); }

.les-list { display: grid; }
.les-row {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 20px; border-bottom: 1px solid var(--line);
  color: var(--ink); text-decoration: none; transition: var(--t-fast);
}
.les-row:last-child { border-bottom: 0; }
.les-row:hover { background: color-mix(in srgb, var(--dc) 7%, #fff); }
.les-row.missing { opacity: .5; }
.les-row > svg:last-child { width: 15px; height: 15px; color: var(--ink-3); flex: none; }
.les-row:hover > svg:last-child { color: var(--dc); }
.les-row-t { flex: 1; min-width: 0; }
.les-row-t b { display: block; font-size: 15px; line-height: 1.35; font-weight: 700; }
.les-row-t span { display: block; font-size: 12.5px; color: var(--ink-3); margin-top: 2px; line-height: 1.4; }

/* The marker carries the number until the lesson is read, then a tick. */
.les-num {
  width: 27px; height: 27px; flex: none; border-radius: 9px;
  display: grid; place-items: center;
  background: var(--wash); color: var(--ink-3);
  font: 800 11.5px var(--font-num, var(--font-body));
  transition: var(--t-fast);
}
.les-num svg { width: 14px; height: 14px; }
.les-row:hover .les-num { background: color-mix(in srgb, var(--dc) 16%, #fff); color: var(--dc); }
.les-row.done .les-num { background: var(--dc); color: #fff; }
.les-soon { font-size: 11px; color: var(--ink-3); font-style: italic; }

/* --- One lesson: hero ----------------------------------------------------- */
.les-view { max-width: 1180px; }
.les-back { margin-bottom: 18px; }
.les-hd { padding-bottom: 22px; border-bottom: 1px solid var(--line); margin-bottom: 26px; }
.les-hd-k { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 600; color: var(--ink-3); }
.les-hd-k a { color: var(--blue); text-decoration: none; font-weight: 700; }
.les-hd-k a:hover { text-decoration: underline; }
.les-title { font: 800 clamp(28px, 3.6vw, 38px) var(--font-head); letter-spacing: -.035em; margin: 6px 0 8px; line-height: 1.1; }
.les-lede { font-size: 16.5px; color: var(--ink-2); margin: 0 0 16px; line-height: 1.55; max-width: 62ch; }
.les-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.les-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--wash);
  font-size: 12.5px; font-weight: 600; color: var(--ink-2);
}
.les-chip.dim { color: var(--ink-3); }
.les-chip svg { width: 14px; height: 14px; }
.les-mark {
  margin-left: auto; display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 15px; border-radius: 999px;
  border: 1px solid var(--line-2); background: #fff;
  font: 700 12.5px var(--font-body); color: var(--ink-2); cursor: pointer; transition: var(--t-fast);
}
.les-mark:hover { border-color: var(--green); color: var(--green); }
.les-mark.on { background: var(--green-tint); border-color: rgba(14, 159, 110, .35); color: var(--green); }
.les-mark svg { width: 14px; height: 14px; }

/* --- Two-column body ------------------------------------------------------ */
.les-grid { display: grid; grid-template-columns: minmax(0, 1fr) 274px; gap: 40px; align-items: start; }
.les-main { min-width: 0; }

/* The single sentence worth keeping. Given its own treatment because in a
   3,000-word page it is the thing most worth not missing. */
.les-key {
  padding: 18px 22px; margin-bottom: 30px;
  border-radius: var(--r); border: 1px solid rgba(47, 107, 255, .26);
  background: linear-gradient(120deg, var(--blue-tint), #fff 75%);
}
.les-key-k {
  display: inline-flex; align-items: center; gap: 6px; margin-bottom: 6px;
  font: 800 10.5px var(--font-body); letter-spacing: .12em; text-transform: uppercase; color: var(--blue);
}
.les-key-k svg { width: 13px; height: 13px; }
.les-key p { margin: 0; font-size: 16px; line-height: 1.6; color: var(--ink); font-weight: 600; }

/* Section headers: a small icon and a rule, not a coloured bar. */
.les-s { margin-bottom: 34px; scroll-margin-top: 20px; }
.les-s-h { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.les-s-h h2 { font: 800 17px var(--font-head); margin: 0; letter-spacing: -.02em; }
.les-s-h::after { content: ''; flex: 1; height: 1px; background: var(--line); }
.les-s-ic {
  width: 26px; height: 26px; flex: none; border-radius: 8px;
  display: grid; place-items: center;
  background: var(--blue-tint); color: var(--blue);
}
.les-s-ic svg { width: 14px; height: 14px; }

.les-prose p { margin: 0 0 13px; font-size: 15.5px; line-height: 1.72; color: var(--ink-2); max-width: 68ch; }
.les-prose p:last-child { margin-bottom: 0; }
.les-prose b, .les-steps b, .les-tips b, .les-key b { color: var(--ink); font-weight: 700; }

/* Method: a title per step, with the detail underneath. */
.les-steps { margin: 0; padding: 0; list-style: none; counter-reset: step; display: grid; gap: 14px; }
.les-steps li {
  counter-increment: step; position: relative; padding-left: 40px;
}
.les-steps li::before {
  content: counter(step);
  position: absolute; left: 0; top: 0;
  width: 26px; height: 26px; border-radius: 8px;
  display: grid; place-items: center;
  background: var(--ink); color: #fff;
  font: 800 12.5px var(--font-num, var(--font-body));
}
.les-steps li b { display: block; font-size: 14.5px; margin-bottom: 2px; }
.les-steps li span { display: block; font-size: 14.5px; line-height: 1.62; color: var(--ink-2); }

/* Reference: a compact two-column key/value table. */
.les-refs { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: 8px; }
.les-ref {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 10px 14px; border-radius: var(--r-sm);
  background: var(--wash); border: 1px solid var(--line);
}
.les-ref-k { font-size: 12.5px; color: var(--ink-3); font-weight: 600; }
.les-ref-v { font: 700 13.5px var(--font-num, var(--font-body)); color: var(--ink); text-align: right; }

/* Worked examples: the part students copy, so it reads as one block of work. */
.les-exs { display: grid; gap: 16px; }
.les-ex {
  border: 1px solid var(--line); border-radius: var(--r);
  background: #fff; overflow: hidden;
}
.les-ex-hd {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 11px 18px; background: var(--wash); border-bottom: 1px solid var(--line);
}
.les-ex-n { font: 800 11.5px var(--font-body); letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); }
.les-ex-lv {
  padding: 3px 10px; border-radius: 999px;
  background: var(--blue-tint); color: var(--blue-dk);
  font: 700 11px var(--font-body);
}
.les-ex-q { margin: 0; padding: 16px 18px 0; font-size: 15px; font-weight: 700; color: var(--ink); line-height: 1.55; }
.les-ex-work { margin: 12px 0 0; padding: 0 18px 0 40px; display: grid; gap: 7px; }
.les-ex-work li { font-size: 14.5px; line-height: 1.62; color: var(--ink-2); }
.les-ex-work li::marker { color: var(--ink-3); font-weight: 700; }
.les-ex-a {
  display: inline-flex; align-items: center; gap: 8px; margin: 14px 18px 16px;
  padding: 9px 15px; border-radius: 10px;
  background: var(--green-tint); border: 1px solid rgba(14, 159, 110, .3);
  font-size: 14.5px; font-weight: 700; color: var(--green);
}
.les-ex-a svg { width: 15px; height: 15px; flex: none; }
.les-ex-note {
  margin: 0; padding: 12px 18px; border-top: 1px solid var(--line);
  background: var(--wash); font-size: 13px; line-height: 1.6; color: var(--ink-2);
}

.les-traps { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 11px; }
.les-trap { padding: 13px 15px; border-radius: var(--r-sm); background: var(--red-tint); border-left: 3px solid var(--red); }
.les-trap b { display: block; font-size: 13.5px; color: var(--red-dark); margin-bottom: 3px; }
.les-trap span { font-size: 13.5px; line-height: 1.6; color: var(--ink-2); }

.les-tips { margin: 0; padding-left: 20px; display: grid; gap: 10px; }
.les-tips li { font-size: 14.5px; line-height: 1.65; color: var(--ink-2); }
.les-tips li::marker { color: var(--gold); }

.les-cta {
  display: flex; align-items: center; justify-content: space-between; gap: 18px; flex-wrap: wrap;
  padding: 20px 24px; margin: 30px 0 18px;
  border-radius: var(--r); border: 1px solid var(--line);
  background: linear-gradient(115deg, var(--blue-tint), #fff 65%);
}
.les-cta-t b { display: block; font: 800 17px var(--font-head); letter-spacing: -.02em; }
.les-cta-t span { font-size: 13.5px; color: var(--ink-2); }

.les-nav { display: flex; justify-content: space-between; gap: 12px; }
.les-nav-a {
  display: inline-flex; align-items: center; gap: 9px; max-width: 49%;
  padding: 12px 16px; border-radius: var(--r-sm);
  border: 1px solid var(--line); background: #fff;
  color: var(--ink); text-decoration: none; transition: var(--t-fast);
}
.les-nav-a:hover { border-color: var(--blue); background: var(--blue-tint); }
.les-nav-a.r { margin-left: auto; text-align: right; }
.les-nav-a i { display: block; font-style: normal; font-size: 10.5px; color: var(--ink-3); font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.les-nav-a b { display: block; font-size: 13.5px; line-height: 1.3; }
.les-nav-a svg { width: 15px; height: 15px; flex: none; color: var(--ink-3); }

/* --- Sticky rail ---------------------------------------------------------- */
.les-rail { position: sticky; top: 20px; display: grid; gap: 14px; }
.les-rail-box { padding: 16px 18px; border: 1px solid var(--line); border-radius: var(--r); background: #fff; }
.les-rail-k {
  font: 800 10.5px var(--font-body); letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: 10px;
}
.les-toc { display: grid; gap: 2px; }
.les-toc a {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 9px; margin: 0 -9px; border-radius: 8px;
  font-size: 13px; font-weight: 600; color: var(--ink-2); text-decoration: none;
  transition: var(--t-fast);
}
.les-toc a:hover { background: var(--blue-tint); color: var(--blue-dk); }
.les-toc svg { width: 14px; height: 14px; color: var(--ink-3); flex: none; }
.les-toc a:hover svg { color: var(--blue); }

.les-asked { margin: 0; padding: 0; list-style: none; display: grid; gap: 9px; }
.les-asked li {
  font-size: 12.5px; line-height: 1.5; color: var(--ink-2); font-style: italic;
  padding-left: 12px; border-left: 2px solid var(--line-2);
}

.les-rail-cta { background: linear-gradient(140deg, var(--blue-tint), #fff 70%); }
.les-rail-cta b { display: block; font: 800 19px var(--font-head); letter-spacing: -.02em; }
.les-rail-cta > span { display: block; font-size: 12.5px; color: var(--ink-2); margin-bottom: 12px; }

@media (max-width: 1080px) {
  /* The rail becomes a strip above the content rather than a column beside
     it — a 270px sidebar squeezed into a narrow window is worse than none. */
  .les-grid { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .les-rail { position: static; grid-row: 1; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
}
@media (max-width: 720px) {
  .les-doms > .les-dom { flex-basis: min(86vw, 420px); }
  .les-traps { grid-template-columns: 1fr; }
  .les-refs { grid-template-columns: 1fr; }
  .les-mark { margin-left: 0; }
  .les-nav-a { max-width: 100%; }
  .les-cta { flex-direction: column; align-items: stretch; }
  .les-ex-work { padding-left: 34px; }
}

/* --- Lessons: second-pass sections ---------------------------------------- */

/* The forms the question takes. */
.les-vars { display: grid; gap: 10px; }
.les-var { display: flex; gap: 12px; padding: 12px 14px; border-radius: var(--r-sm); background: var(--wash); border: 1px solid var(--line); }
.les-var-n {
  width: 22px; height: 22px; flex: none; border-radius: 7px;
  display: grid; place-items: center; background: #fff; border: 1px solid var(--line-2);
  font: 800 11px var(--font-num, var(--font-body)); color: var(--ink-3);
}
.les-var b { display: block; font-size: 14px; margin-bottom: 1px; }
.les-var span { display: block; font-size: 13.5px; line-height: 1.55; color: var(--ink-2); }

/* Try one yourself. The answer stays hidden until a choice is committed to,
   because a question you have actually answered teaches more than one you
   have read the solution to. */
.les-try { border: 1px solid var(--line); border-radius: var(--r); padding: 18px 20px; background: #fff; }
.les-try-q { margin: 0 0 14px; font-size: 15px; font-weight: 700; line-height: 1.55; color: var(--ink); }
.les-try-cs { display: grid; gap: 8px; }
.les-try-c {
  display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  padding: 11px 14px; border-radius: 11px;
  border: 1px solid var(--line-2); background: #fff;
  font: 500 14px var(--font-body); color: var(--ink); cursor: pointer;
  transition: var(--t-fast);
}
.les-try-c:hover:not(:disabled) { border-color: var(--blue); background: var(--blue-tint); }
.les-try-c:disabled { cursor: default; }
.les-try-l {
  width: 24px; height: 24px; flex: none; border-radius: 50%;
  display: grid; place-items: center; border: 1.5px solid var(--line-2);
  font: 800 11.5px var(--font-body); color: var(--ink-3);
}
.les-try-c.right { border-color: var(--green); background: var(--green-tint); }
.les-try-c.right .les-try-l { background: var(--green); border-color: var(--green); color: #fff; }
.les-try-c.wrong { border-color: var(--red); background: var(--red-tint); }
.les-try-c.wrong .les-try-l { background: var(--red); border-color: var(--red); color: #fff; }
.les-try-hint { margin: 12px 0 0; font-size: 12.5px; color: var(--ink-3); font-style: italic; }
.les-try-a {
  margin-top: 14px; padding: 13px 15px; border-radius: var(--r-sm);
  background: var(--red-tint); border-left: 3px solid var(--red);
}
.les-try-a.ok { background: var(--green-tint); border-left-color: var(--green); }
.les-try-a b { display: block; font-size: 13.5px; margin-bottom: 3px; color: var(--red-dark); }
.les-try-a.ok b { color: var(--green); }
.les-try-a span { font-size: 13.5px; line-height: 1.6; color: var(--ink-2); }

/* If you get stuck. */
.les-stuck { padding: 16px 18px; border-radius: var(--r); background: linear-gradient(120deg, #FFF8EC, #fff 70%); border: 1px solid rgba(232, 137, 12, .24); }
.les-stuck-i { margin: 0 0 10px; font-size: 13.5px; color: var(--ink-2); }
.les-stuck ul { margin: 0; padding-left: 20px; display: grid; gap: 9px; }
.les-stuck li { font-size: 14px; line-height: 1.6; color: var(--ink-2); }
.les-stuck li::marker { color: var(--gold); }

/* Read next. */
.les-rel { display: grid; gap: 6px; }
.les-rel a {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; margin: 0 -10px; border-radius: 8px;
  font-size: 12.5px; font-weight: 600; color: var(--ink-2); text-decoration: none;
  line-height: 1.35; transition: var(--t-fast);
}
.les-rel a:hover { background: var(--blue-tint); color: var(--blue-dk); }
.les-rel svg { width: 14px; height: 14px; flex: none; color: var(--ink-3); }
.les-rel a:hover svg { color: var(--blue); }

/* ==========================================================================
   Desmos guide

   The figures imitate the real calculator's layout — numbered expression
   rows on the left, graph paper on the right — because a student who has
   seen that shape here recognises it instantly in Bluebook. The graph itself
   is always white with black axes whatever the app theme is doing: Desmos is
   white in the test, and a dark-mode graph would be teaching the wrong
   picture.
   ========================================================================== */
.les-sec-dot.desmos { background: linear-gradient(135deg, #2d70b3, #388c46); }

/* --- The band of guide cards on the index ------------------------------ */
.dg-track > .dg-card { flex: 0 0 340px; }
.dg-card {
  display: flex; flex-direction: column;
  text-decoration: none; color: var(--ink);
  border: 1px solid var(--line); border-radius: 18px; background: #fff;
  overflow: hidden;
  transition: box-shadow .25s ease, border-color .25s ease;
}
.dg-card:hover { box-shadow: 0 12px 34px -16px color-mix(in srgb, var(--dc) 55%, transparent); border-color: color-mix(in srgb, var(--dc) 34%, var(--line)); }
.dg-card-fig {
  height: 132px; overflow: hidden; border-bottom: 1px solid var(--line);
  background: #fff; display: grid; place-items: center;
}
.dg-card-fig svg { width: 100%; height: 100%; display: block; }
.dg-card-b { padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 10px; flex: 1; }
.dg-card-hd { display: flex; align-items: center; gap: 12px; }
.dg-card-p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--ink-2); flex: 1; }
.dg-card-go {
  display: flex; align-items: center; gap: 5px;
  font: 700 12.5px var(--font-body); color: var(--dc);
}
.dg-card-go svg { width: 14px; height: 14px; transition: transform .2s var(--ease); }
.dg-card:hover .dg-card-go svg { transform: translateX(3px); }

/* --- A figure ----------------------------------------------------------- */
.dg-calc {
  margin: 20px 0; border: 1px solid var(--line-2); border-radius: 14px;
  overflow: hidden; background: #fff;
  box-shadow: 0 2px 10px -6px rgba(16, 24, 40, .35);
}
.dg-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 13px; background: #f7f8fa; border-bottom: 1px solid var(--line);
}
.dg-dots { display: flex; gap: 5px; }
.dg-dots i { width: 9px; height: 9px; border-radius: 50%; background: #d3d7de; }
.dg-bar-t { font: 600 12px var(--font-body); color: #6b7280; }
.dg-bar-k { margin-left: auto; color: #9aa3b2; display: grid; }
.dg-bar-k svg { width: 15px; height: 15px; }

.dg-body { display: flex; align-items: stretch; }
.dg-calc.narrow .dg-body,
.dg-calc.stacked .dg-body { display: block; }
.dg-calc.stacked .dg-exprs { border-right: 0; border-bottom: 1px solid var(--line); }
/* Across the top, the rows sit side by side rather than stacking. */
.dg-calc.stacked .dg-exprs { display: flex; flex-wrap: wrap; }
.dg-calc.stacked .dg-row { border-bottom: 0; border-right: 1px solid var(--line); flex: 1 1 190px; }
.dg-calc.stacked .dg-row:last-child { border-right: 0; }

/* The expression list. Monospace-ish numerals and a hairline between rows,
   which is what makes it read as a list of lines rather than a paragraph. */
.dg-exprs { flex: 0 0 236px; border-right: 1px solid var(--line); background: #fff; }
.dg-calc.narrow .dg-exprs { flex: none; border-right: 0; }
.dg-row { display: flex; align-items: flex-start; gap: 8px; padding: 9px 10px; border-bottom: 1px solid var(--line); min-height: 38px; }
.dg-row:last-child { border-bottom: 0; }
.dg-rn { flex: none; width: 15px; text-align: right; font: 600 11px var(--font-num, var(--font-body)); color: #b0b6c0; padding-top: 2px; }
.dg-rc { flex: none; width: 11px; height: 11px; border-radius: 50%; margin-top: 4px; }
.dg-rb { flex: 1; min-width: 0; }
.dg-rt { font: 500 13.5px var(--font-num, var(--font-body)); color: #1f2430; line-height: 1.5; word-break: break-word; }
.dg-rt sup, .dg-rt sub { font-size: .72em; }
.dg-rt .dg-op { color: #c74440; font-weight: 700; }
.dg-rt .dg-sqrt { border-top: 1.3px solid currentColor; padding: 0 2px 0 1px; margin-left: -1px; }
.dg-rv { font: 600 13px var(--font-num, var(--font-body)); color: #388c46; margin-top: 3px; }
.dg-rnote { font-size: 11px; color: var(--ink-3); margin-top: 3px; font-style: italic; }
.dg-row-new { opacity: .45; }

.dg-slider { display: flex; align-items: center; margin-top: 7px; height: 12px; }
.dg-slider i { flex: 1; height: 3px; border-radius: 2px; background: #dfe3e9; }
.dg-slider b { width: 11px; height: 11px; border-radius: 50%; background: #fa7e19; margin-left: -5px; }

/* The little readout Desmos prints under a regression. */
.dg-stats { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 7px; padding-top: 7px; border-top: 1px dashed var(--line-2); }
.dg-stats span { display: inline-flex; align-items: baseline; gap: 5px; }
.dg-stats i { font-style: normal; font-size: 11.5px; color: var(--ink-3); }
.dg-stats b { font: 600 12px var(--font-num, var(--font-body)); color: #1f2430; }

.dg-row-t { display: block; }
.dg-tbl { margin-left: 23px; margin-top: -20px; }
.dg-tbl-h, .dg-tbl-r { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
.dg-tbl-h span { font: 600 11.5px var(--font-num, var(--font-body)); color: #6b7280; padding: 3px 6px; background: #f4f5f7; border-radius: 4px; text-align: center; }
.dg-tbl-r span { font: 500 12px var(--font-num, var(--font-body)); color: #1f2430; padding: 2px 6px; text-align: center; }

/* The graph. White and black regardless of theme — see the block comment. */
.dg-plots { flex: 1; min-width: 0; display: grid; }
.dg-plots.split { grid-template-columns: 1fr 1fr; }
.dg-plot { min-width: 0; border-left: 1px solid var(--line); }
.dg-plot:first-child { border-left: 0; }
.dg-svg { display: block; width: 100%; height: auto; }
.dg-grid line { stroke: #e7e9ee; stroke-width: 1; }
.dg-axes line { stroke: #5b616e; stroke-width: 1.4; }
.dg-nums text { fill: #8b919c; font: 400 10px var(--font-num, sans-serif); }
.dg-plab { fill: #1f2430; font: 600 11px var(--font-num, sans-serif); paint-order: stroke; stroke: #fff; stroke-width: 3.5px; }

.dg-calc figcaption {
  padding: 11px 15px; font-size: 12.5px; line-height: 1.6; color: var(--ink-2);
  background: var(--wash); border-top: 1px solid var(--line);
}
.dg-calc figcaption b { color: var(--ink); }

/* --- Definition lists ---------------------------------------------------
   The lesson pages' .les-refs is a formula sheet: short key, short
   right-aligned value. Here the values are sentences, so the key becomes a
   heading and the text runs normally underneath it. */
.dg-keys { display: grid; gap: 9px; margin: 16px 0; }
.dg-key {
  padding: 12px 15px; border-radius: 11px;
  background: var(--wash); border: 1px solid var(--line);
}
/* Direct child only — the value text uses <b> inline for emphasis, and a
   block-level <b> there breaks the sentence across two lines. */
.dg-key > b {
  display: block; margin-bottom: 4px;
  font: 700 13px var(--font-body); color: var(--dc, var(--ink));
  letter-spacing: -.005em;
}
.dg-key > span { display: block; font-size: 13.5px; line-height: 1.6; color: var(--ink-2); }
.dg-key code, .les-prose code, .dg-aside code, .les-ex code, .les-trap code, .les-tips code, .les-try code {
  font: 600 .92em var(--font-num, monospace);
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  padding: 1px 5px; border-radius: 5px;
}

/* --- Asides and typed syntax -------------------------------------------- */
.dg-aside {
  display: flex; gap: 11px; align-items: flex-start;
  margin: 18px 0; padding: 13px 15px; border-radius: 12px;
  font-size: 14px; line-height: 1.65;
  border: 1px solid transparent;
}
.dg-aside svg { flex: none; width: 17px; height: 17px; margin-top: 2px; }
.dg-aside.tip { background: color-mix(in srgb, #0e9f6e 8%, #fff); border-color: color-mix(in srgb, #0e9f6e 24%, transparent); color: #14603f; }
.dg-aside.warn { background: color-mix(in srgb, #e8890c 10%, #fff); border-color: color-mix(in srgb, #e8890c 28%, transparent); color: #7a4a05; }
.dg-aside code { background: rgba(255, 255, 255, .7); }

.dg-code {
  display: flex; align-items: center; gap: 12px;
  margin: 18px 0; padding: 14px 16px; border-radius: 12px;
  background: #1f2430; color: #f2f4f7;
}
.dg-code code { flex: 1; font: 600 15px var(--font-num, monospace); letter-spacing: .01em; background: none; color: inherit; padding: 0; }
.dg-code .dg-op { color: #ff8a80; }
.dg-copy {
  flex: none; display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 8px; cursor: pointer;
  background: rgba(255, 255, 255, .1); border: 0; color: #cfd4dc;
  transition: var(--t-fast);
}
.dg-copy:hover { background: rgba(255, 255, 255, .2); color: #fff; }
.dg-copy svg { width: 15px; height: 15px; }

/* The "all calculator guides" rail marks where you are. */
.les-rel a.on { background: color-mix(in srgb, var(--dc) 12%, #fff); color: var(--dc); font-weight: 700; }

@media (max-width: 900px) {
  .dg-body { display: block; }
  .dg-exprs { flex: none; border-right: 0; border-bottom: 1px solid var(--line); }
  .dg-plot { border-left: 0; }
  .dg-plots.split { grid-template-columns: 1fr; }
  .dg-plots.split .dg-plot + .dg-plot { border-top: 1px solid var(--line); }
  .dg-track > .dg-card { flex-basis: min(86vw, 340px); }
}
