/* StudyBuddy — layout & components. Consumes css/tokens.css. */

* { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  font-family: var(--font-body);
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  color: var(--ink);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, .display { font-family: var(--font-display); line-height: var(--lh-tight); font-weight: 700; }
h1 { font-size: var(--fs-xxl); }
h2 { font-size: var(--fs-xl); }
h3 { font-size: var(--fs-lg); }

a { color: var(--brand-ink); }

.tabular { font-variant-numeric: tabular-nums; }

:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-radius: var(--r-sm);
}

/* Elements with tabindex="-1" are only ever focused programmatically — we move
   focus to a view's heading on navigation so keyboard and screen-reader users
   start at the new content. A focus ring there is noise: the user didn't press
   anything, and they can't Tab to it either. Genuine focus rings are untouched. */
[tabindex="-1"]:focus,
[tabindex="-1"]:focus-visible {
  outline: none;
  box-shadow: none;
}

/* Visible only to assistive tech. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

.skiplink {
  position: absolute; left: 50%; top: 0; transform: translate(-50%, -120%);
  z-index: 100; background: var(--brand); color: #fff;
  padding: var(--s-2) var(--s-4); border-radius: 0 0 var(--r-md) var(--r-md);
  font-weight: 700; text-decoration: none;
  transition: transform var(--dur-fast) var(--ease-out);
}
.skiplink:focus { transform: translate(-50%, 0); }

/* Dark ink on the bright orange, not white — white on this amber is only
   2.7:1. Keeps the colour, passes AA. */
.streakbadge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px var(--s-3); border-radius: var(--r-full);
  background: var(--retry); color: #2B2B3A;
  font-size: var(--fs-sm); font-weight: 700; text-decoration: none;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--retry) 60%, transparent),
              0 2px 16px -3px color-mix(in srgb, var(--retry) 85%, transparent);
  transition: box-shadow var(--dur-fast), transform var(--dur-fast) var(--ease-spring);
}
a.streakbadge:hover {
  transform: translateY(-1px);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--retry) 75%, transparent),
              0 3px 22px -3px color-mix(in srgb, var(--retry) 95%, transparent);
}
:root[data-theme="dark"] .streakbadge { color: #21170C; }
/* At risk: a freeze is standing by. Cool blue instead of the warm streak amber. */
.streakbadge--risk {
  background: var(--info); color: #fff;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--info) 60%, transparent),
              0 2px 16px -3px color-mix(in srgb, var(--info) 80%, transparent);
}
:root[data-theme="dark"] .streakbadge--risk { color: #08222E; }

.resume h3 { margin-bottom: 0; }

/* ---------- app shell ---------- */
#app { min-height: 100%; display: flex; flex-direction: column; }
.shell { flex: 1; display: flex; align-items: stretch; }
.shell__main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* Left sidebar — the whole nav on desktop. Hidden below 900px, where the
   topbar (and its ⋮ menu) covers the same ground. */
.sidebar { display: none; }
.sidebar__brand {
  display: flex; align-items: center; gap: var(--s-2);
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-lg);
  color: var(--ink); text-decoration: none;
  padding: 0 var(--s-2); margin-bottom: var(--s-4);
}
.sidebar__brand img { width: 28px; height: 28px; }
.sidebar__nav { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.sidebar__link {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 9px var(--s-3); border-radius: var(--r-md);
  color: var(--ink-soft); text-decoration: none; font-weight: 600; font-size: var(--fs-sm);
  transition: background var(--dur-fast), color var(--dur-fast);
}
.sidebar__link svg { flex: none; }
.sidebar__link:hover { background: var(--surface-sunk); color: var(--ink); }
.sidebar__link.is-active { background: var(--brand-tint); color: var(--brand-ink); }
.sidebar__link.is-active svg { color: var(--brand-ink); }
.sidebar__group {
  margin: var(--s-3) var(--s-3) 4px; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint);
}
.sidebar__nav > .sidebar__group:first-child { margin-top: 0; }
.sidebar__div { height: 1px; margin: var(--s-3) var(--s-3) var(--s-2); background: var(--line); }
.sidebar__foot { display: flex; flex-direction: column; gap: var(--s-2); margin-top: var(--s-3); }

/* Fuller streak row (icon + the day count in words) — sidebar only, the
   topbar keeps the compact .streakbadge pill. */
.sidebar__streak {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3); border-radius: var(--r-md);
  background: var(--surface-sunk); color: var(--ink);
  font-size: var(--fs-sm); font-weight: 700; text-decoration: none;
  transition: background var(--dur-fast);
}
.sidebar__streak:hover { background: var(--line); }
/* The flame disc breathes a warm glow — an ember, not a whole-button halo. */
.sidebar__streak-icon {
  width: 32px; height: 32px; flex: none; border-radius: var(--r-full);
  display: grid; place-items: center; color: var(--retry); background: var(--retry-tint);
  --glow: var(--retry);
  box-shadow: 0 0 8px 0 color-mix(in srgb, var(--glow) 40%, transparent);
  animation: streak-ember 2.4s var(--ease-out) infinite;
}
@keyframes streak-ember {
  0%, 100% { box-shadow: 0 0 7px 0 color-mix(in srgb, var(--glow) 42%, transparent); }
  50%      { box-shadow: 0 0 18px 3px color-mix(in srgb, var(--glow) 70%, transparent); }
}
.sidebar__streak--risk .sidebar__streak-icon {
  color: var(--info); background: var(--info-tint); --glow: var(--info);
}
/* Zero-streak: same fixed spot in the footer, just muted rather than the
   vivid orange — no ember until there's a streak to celebrate. */
.sidebar__streak--none { color: var(--ink-soft); }
.sidebar__streak--none .sidebar__streak-icon {
  color: var(--ink-faint); background: var(--surface); box-shadow: none; animation: none;
}

/* Segmented light/system/dark switcher, sidebar footer. */
.sidebar__theme { display: flex; gap: 2px; padding: 3px; border-radius: var(--r-full); background: var(--surface-sunk); }
.sidebar__theme-btn {
  flex: 1; display: grid; place-items: center; height: 30px; font: inherit;
  border: none; border-radius: var(--r-full); background: transparent; color: var(--ink-faint);
  cursor: pointer; transition: background var(--dur-fast), color var(--dur-fast);
}
.sidebar__theme-btn:hover { color: var(--ink); }
.sidebar__theme-btn[aria-pressed="true"] { background: var(--surface); color: var(--brand-ink); box-shadow: var(--shadow-1); }

@media (min-width: 900px) {
  .sidebar {
    display: flex; flex-direction: column; flex: none;
    width: 236px; position: sticky; top: var(--s-4); align-self: flex-start;
    height: calc(100vh - var(--s-4) * 2);
    padding: var(--s-5) var(--s-3);
    margin: var(--s-4) 0 var(--s-4) var(--s-4);
    border-radius: var(--r-lg);
    background: var(--surface); border: 1px solid var(--line);
    box-shadow: var(--shadow-1);
  }
  /* Brand stays put; everything below it scrolls on its own so the logo
     never scrolls out of view. Still scrolls (wheel/trackpad/keyboard) if
     the nav outgrows the viewport — just without a visible track/thumb. */
  .sidebar__brand { flex: none; }
  .sidebar__scroll {
    flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    scrollbar-width: none;       /* Firefox */
    display: flex; flex-direction: column;
  }
  .sidebar__scroll::-webkit-scrollbar { display: none; }
  /* Topbar stays on desktop but collapses to just language + bell + account,
     floating top-right over the content — the sidebar carries brand/nav/
     streak, so brand and streak are hidden here; language lives only here
     now, not duplicated in the sidebar footer. */
  .topbar { background: transparent; backdrop-filter: none; border-bottom: none; }
  .topbar__inner { justify-content: flex-end; padding-top: var(--s-4); padding-right: var(--s-6); }
  .topbar .brand,
  .topbar .streakbadge { display: none; }
}

.topbar {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--canvas) 88%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
.topbar__inner {
  max-width: var(--maxw); margin: 0 auto;
  padding: var(--s-3) var(--s-4);
  display: flex; align-items: center; gap: var(--s-4);
}
.brand {
  display: flex; align-items: center; gap: var(--s-2);
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-lg);
  color: var(--ink); text-decoration: none;
}
.brand img { width: 30px; height: 30px; }
.topbar__spacer { flex: 1; }

/* Bottom tab bar — mobile's primary nav (see js/main.js tabBar()). Fixed,
   thumb-reachable, always visible — the sidebar covers this ground on
   desktop, where this is hidden (see the min-width:900px block above). */
.tabbar {
  display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 25;
  background: color-mix(in srgb, var(--surface) 97%, transparent);
  backdrop-filter: blur(8px);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom, 0);
}
.tabbar__item {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; padding: 8px 0 7px; border: none; background: none; font: inherit; cursor: pointer;
  color: var(--ink-faint); text-decoration: none;
}
.tabbar__item svg { flex: none; }
.tabbar__item span { font-size: 10.5px; font-weight: 600; }
.tabbar__item.is-active { color: var(--brand-ink); }
.tabbar__more { position: relative; flex: 1; display: flex; }

/* The "Meny" tab's popover — the full nav, opened upward from the bottom
   bar instead of downward from a topbar icon. */
.topmenu__list {
  position: absolute; right: 8px; bottom: calc(100% + 10px); z-index: 30;
  min-width: 190px; padding: 6px;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--r-md); box-shadow: var(--shadow-2);
  display: flex; flex-direction: column; gap: 2px;
}
.topmenu__item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border-radius: var(--r-md);
  color: var(--ink); text-decoration: none; font-size: var(--fs-sm); font-weight: 600;
}
.topmenu__item:hover { background: var(--surface-sunk); }
.topmenu__item svg { flex: none; color: var(--ink-soft); }
.topmenu__item.is-active { background: var(--brand-tint); color: var(--brand-ink); }
.topmenu__item.is-active svg { color: var(--brand-ink); }
.topmenu__group {
  margin: 8px 10px 2px; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint);
}
.topmenu__list > .topmenu__group:first-child { margin-top: 2px; }
.topmenu__div { height: 1px; margin: 6px 10px; background: var(--line); }
/* Theme switcher tucked in the "Meny" popover's footer — the sidebar
   carries it on desktop, but there's no sidebar on mobile. */
.topmenu__foot { padding: 2px 10px 6px; }
.topmenu__foot .topmenu__group { margin: 4px 0 6px; }
.topmenu__foot .sidebar__theme { width: 100%; }

@media (max-width: 899.98px) {
  /* Room for the fixed tab bar so page content — and anything else that
     floats at the bottom, like the solve-screen hint — never sits under it. */
  .content { padding-bottom: calc(70px + env(safe-area-inset-bottom, 0)); }
}
/* The sidebar covers this ground on desktop — placed after .tabbar's own
   base rule (not inside the earlier min-width:900px block) so this actually
   wins the cascade instead of being overridden by it. */
@media (min-width: 900px) {
  .tabbar { display: none; }
}

@media (max-width: 560px) {
  .topbar__inner { gap: var(--s-2); padding-left: var(--s-3); padding-right: var(--s-3); }
  .topbar__inner .brand { font-size: var(--fs-md); }
  .topbar__inner .brand img { width: 26px; height: 26px; }
  /* Bell + account need the room; the streak already shows in the "Idag"
     panel and the language toggle stays. */
  .topbar__inner > .streakbadge { display: none; }
}

/* "← Home" control at the top of every sub-screen. */
.homebtn {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-soft);
  padding: 5px 12px 5px 8px; border-radius: var(--r-full);
  border: 1px solid var(--line-strong); background: var(--surface);
  margin-bottom: var(--s-4);
}
.homebtn:hover { color: var(--brand); border-color: var(--brand); }
.homebtn svg { flex: none; }
.psheet__bar .homebtn { margin-bottom: 0; }

.iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: var(--r-full);
  border: 1px solid var(--line-strong); background: var(--surface);
  color: var(--ink-soft); cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-spring), background var(--dur-fast);
}
.iconbtn:hover { transform: translateY(-1px); background: var(--surface-sunk); }

/* Language toggle: the globe alone is ambiguous, so it carries the code it
   will switch to. */
.langbtn { position: relative; width: auto; min-width: 40px; gap: 5px; padding: 0 10px; }
.langbtn__flag { display: inline-flex; flex: none; }
.langbtn__flag svg { width: 18px; height: auto; display: block; border-radius: 2px; }
.langbtn__code { font-size: 11px; font-weight: 700; letter-spacing: .03em; }

.content {
  flex: 1;
  max-width: var(--maxw); width: 100%; margin: 0 auto;
  padding: var(--s-6) var(--s-4) var(--s-8);
}

/* Bottom of every page — About/Terms/Privacy, deliberately not in the main
   nav. Shares .content's max-width by living inside it. */
.sitefooter {
  margin-top: var(--s-8); padding-top: var(--s-5); border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-3);
  font-size: var(--fs-sm); color: var(--ink-faint);
}
.sitefooter__brand {
  display: flex; align-items: center; gap: var(--s-2);
  font-family: var(--font-display); font-weight: 700; color: var(--ink-soft);
}
.sitefooter__brand img { width: 20px; height: 20px; }
.sitefooter__links { display: flex; flex-wrap: wrap; gap: var(--s-4); }
.sitefooter__links a { color: var(--ink-faint); text-decoration: none; }
.sitefooter__links a:hover { color: var(--ink-soft); text-decoration: underline; }
.sitefooter__copy { width: 100%; font-size: 12px; order: 3; }
@media (min-width: 620px) { .sitefooter__copy { width: auto; order: 0; } }

/* ---------- buttons ---------- */
.btn {
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-md);
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: var(--s-3) var(--s-5); border-radius: var(--r-full);
  border: none; cursor: pointer; text-decoration: none;
  background: var(--brand); color: #fff;
  box-shadow: var(--shadow-1);
  transition: transform var(--dur-fast) var(--ease-spring), box-shadow var(--dur-fast), background var(--dur-fast);
}
.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }
.btn:active { transform: translateY(0); }
.btn--ghost { background: var(--surface); color: var(--ink); border: 1px solid var(--line-strong); box-shadow: none; }
.btn--ghost:hover { background: var(--surface-sunk); }
.btn--ok { background: var(--ok); }
.btn--danger { background: var(--c-berry-ink); color: #fff; }
.btn--sm { padding: var(--s-2) var(--s-4); font-size: var(--fs-sm); }
/* Not opacity — 0.5 on a coloured button drops the label to ~2.3:1 and reads as
   broken rather than "not yet". Explicit muted colours stay legible. */
.btn:disabled {
  cursor: not-allowed; transform: none; box-shadow: none;
  background: var(--surface-sunk); color: var(--ink-faint);
  /* Softer edge than a ghost button's --line-strong, so "disabled" and
     "secondary action" do not end up looking like the same control. */
  border: 1px solid var(--line);
}
.btn:disabled:hover { transform: none; box-shadow: none; background: var(--surface-sunk); }

/* ---------- cards & panels ---------- */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-1);
}
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--s-5); }

/* ---------- menu / home ---------- */
.home__head { margin-bottom: var(--s-5); }
.home__hi { color: var(--ink-soft); margin-top: 2px; }
/* Solve / Library / New-set — a row on its own, between the "Idag" panel
   and "Dina set". */
.home__actions { display: flex; gap: var(--s-2); flex-wrap: wrap; margin-bottom: var(--s-5); }

.tabs { display: inline-flex; background: var(--surface-sunk); border-radius: var(--r-full); padding: 4px; gap: 4px; }
.tab {
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-sm);
  border: none; background: transparent; color: var(--ink-soft);
  padding: var(--s-2) var(--s-4); border-radius: var(--r-full); cursor: pointer;
  transition: background var(--dur-fast), color var(--dur-fast);
}
.tab[aria-selected="true"] { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-1); }

.chips { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: 0 0 var(--s-4); }
.chip {
  font-size: var(--fs-sm); font-weight: 600;
  border: 1px solid var(--line-strong); background: var(--surface);
  color: var(--ink-soft); padding: 6px var(--s-3); border-radius: var(--r-full); cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-spring);
  display: inline-flex; align-items: center; gap: 6px;
}
.chip:hover { transform: translateY(-1px); }
.chip__dot { width: 10px; height: 10px; border-radius: var(--r-full); background: var(--subject, var(--ink-faint)); }
.chip[aria-pressed="true"] { color: #fff; background: var(--subject-ink, var(--brand)); border-color: transparent; }
.chip[aria-pressed="true"] .chip__dot { background: rgba(255,255,255,.85); }
/* A subject the user pre-added — no sets under it yet. */
.chip--empty:not([aria-pressed="true"]) { opacity: .5; }
/* "+ add subject" control at the end of the row, and its inline input. */
.chip--add { color: var(--ink-faint); border-style: dashed; padding-inline: 9px; }
.chip--add:hover { color: var(--brand); border-color: var(--brand); }
.chip--add svg { display: block; }
.chip--addinput { width: 130px; font: inherit; font-size: var(--fs-sm); font-weight: 600; padding: 5px var(--s-3); color: var(--ink); }
.chip--addinput:focus-visible { border-color: var(--brand); outline: none; }

/* ---------- today strip ---------- */
.today { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: var(--s-3); margin-bottom: var(--s-4); }
.tile {
  display: flex; align-items: center; gap: var(--s-3); text-decoration: none; color: inherit;
  padding: var(--s-3) var(--s-4); border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-1);
  transition: transform var(--dur-fast) var(--ease-spring), box-shadow var(--dur-fast);
}
.tile:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }
.tile strong { display: block; font-family: var(--font-display); font-size: var(--fs-md); }
.tile__sub { display: block; font-size: var(--fs-sm); color: var(--ink-soft); }
.tile__icon {
  width: 36px; height: 36px; flex: none; border-radius: var(--r-full);
  display: grid; place-items: center; background: var(--surface-sunk); color: var(--ink-soft);
}
.tile--accent { border-color: var(--brand); background: var(--brand-tint); }
.tile--accent .tile__icon { background: var(--brand); color: #fff; }

/* "Continue where you left off" — the loudest tile on the strip. */
.tile--resume {
  border-color: var(--brand); border-left-width: 4px;
  background: var(--brand-tint);
  box-shadow: 0 3px 18px -5px color-mix(in srgb, var(--brand) 55%, transparent);
}
.tile--resume:hover { box-shadow: 0 6px 24px -6px color-mix(in srgb, var(--brand) 60%, transparent); }
.tile--resume .tile__icon { background: var(--brand); color: #fff; }
.tile--resume strong { color: var(--brand-ink); }

/* Streak / goal / weak-spot tiles all get the same glowing treatment as the
   top-bar streak badge, each in its own colour. */
.tile--streak {
  border-color: color-mix(in srgb, var(--retry) 55%, var(--line));
  box-shadow: 0 2px 16px -4px color-mix(in srgb, var(--retry) 60%, transparent);
}
.tile--streak .tile__icon { background: var(--retry); color: #2B2B3A; }
:root[data-theme="dark"] .tile--streak .tile__icon { color: #21170C; }

.tile--goal {
  border-color: color-mix(in srgb, var(--ok-bright) 55%, var(--line));
  box-shadow: 0 2px 16px -4px color-mix(in srgb, var(--ok-bright) 60%, transparent);
}
.tile--goal:hover { box-shadow: 0 5px 22px -5px color-mix(in srgb, var(--ok-bright) 65%, transparent); }

.tile--weak {
  border-color: color-mix(in srgb, var(--c-berry) 55%, var(--line));
  box-shadow: 0 2px 16px -4px color-mix(in srgb, var(--c-berry) 60%, transparent);
}
.tile--weak:hover { box-shadow: 0 5px 22px -5px color-mix(in srgb, var(--c-berry) 65%, transparent); }
.tile--weak .tile__icon { background: var(--c-berry); color: #fff; }
:root[data-theme="dark"] .tile--weak .tile__icon { color: #3B1E2B; }

/* Calendar day chooser: subject dot in each row. */
.daymenu { z-index: 60; min-width: 190px; }
.daymenu__dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }

/* ---------- home: "Today" + "Your sets" panels ---------- */
.home-panel {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-1);
  padding: var(--s-4) var(--s-5); margin-bottom: var(--s-5);
}
.home-panel__label {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-md);
  color: var(--ink); margin-bottom: var(--s-3);
}
/* Quieter link-style text on the home page specifically (the achievements
   count, "switch to Tests", "Show all") — same elsewhere (Study, Progress,
   Settings, the Kommande dialog), just not underlined here. */
.home-panel .linkbtn, .home-panel .upcoming__more { text-decoration: none; }

/* Two-column home page: the panels on the left, a sticky rail (upcoming
   deadlines + achievements teaser) on the right. Falls back to one column
   below 1100px, or whenever homeRail() has nothing to show. */
.home-layout { display: grid; grid-template-columns: minmax(0, 1fr) 288px; gap: var(--s-5); align-items: start; }
.home-layout--solo { grid-template-columns: minmax(0, 1fr); }
.home-main { min-width: 0; }
.home-rail { display: flex; flex-direction: column; gap: var(--s-5); position: sticky; top: calc(var(--s-4) + 16px); }
.home-rail .home-panel { margin-bottom: 0; }
.home-rail .upcoming { margin-bottom: 0; }
@media (max-width: 1100px) {
  .home-layout { grid-template-columns: minmax(0, 1fr); }
  .home-rail { position: static; }
}

/* Achievements teaser: the badge closest to unlocking, with a slim bar. */
.ach-next { display: flex; gap: var(--s-3); align-items: flex-start; }
.ach-next__emoji { font-size: 26px; line-height: 1.1; flex: none; }
.ach-next__bar {
  height: 6px; border-radius: var(--r-full); background: var(--surface-sunk);
  overflow: hidden; margin: 6px 0 4px;
}
.ach-next__fill { height: 100%; background: var(--brand); border-radius: inherit; }

/* "Continue where you left off" — the wide banner at the top of Today. */
.continue-banner {
  display: flex; align-items: center; gap: var(--s-3); text-decoration: none;
  padding: var(--s-3) var(--s-4); border-radius: var(--r-md);
  background: var(--brand-tint); border: 1px solid var(--brand); border-left-width: 4px;
  color: inherit; margin-bottom: var(--s-3);
  transition: box-shadow var(--dur-fast);
}
.continue-banner:hover { box-shadow: 0 4px 20px -6px color-mix(in srgb, var(--brand) 55%, transparent); }
.continue-banner__ic {
  width: 34px; height: 34px; flex: none; border-radius: var(--r-full);
  display: grid; place-items: center; background: var(--brand); color: #fff;
}
.continue-banner__body { flex: 1; min-width: 0; }
.continue-banner__body strong { display: block; font-family: var(--font-display); color: var(--brand-ink); }
.continue-banner__body span { display: block; font-size: var(--fs-sm); color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.continue-banner__go { flex: none; font-family: var(--font-display); font-weight: 700; font-size: var(--fs-sm); color: var(--brand-ink); }
.continue-banner__go::after { content: " ›"; }

/* the small stat pills below the banner */
.pillrow { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.pill {
  display: inline-flex; align-items: center; gap: var(--s-2); text-decoration: none;
  font-size: var(--fs-sm); font-weight: 700; color: var(--ink-soft);
  padding: 6px var(--s-3); border-radius: var(--r-full);
  background: var(--surface); border: 1px solid var(--line-strong);
  transition: transform var(--dur-fast) var(--ease-spring);
}
.pill:hover { transform: translateY(-1px); color: var(--ink); }
.pill__ic { width: 18px; height: 18px; flex: none; border-radius: var(--r-full); display: grid; place-items: center; background: var(--surface-sunk); color: var(--ink-soft); }
.pill .ring { width: 26px; height: 26px; flex: none; }
.pill--due .pill__ic { background: var(--brand); color: #fff; }
.pill--weak { border-color: color-mix(in srgb, var(--c-berry) 45%, var(--line-strong)); }
.pill--weak .pill__ic { background: var(--c-berry); color: #fff; }
/* The streak pill glows in the same warm amber as the top-bar badge — a
   running streak should read as "lit", not just another stat. */
.pill--streak {
  border-color: color-mix(in srgb, var(--retry) 55%, var(--line-strong));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--retry) 30%, transparent),
              0 2px 16px -4px color-mix(in srgb, var(--retry) 60%, transparent);
}
.pill--streak:hover {
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--retry) 45%, transparent),
              0 4px 22px -4px color-mix(in srgb, var(--retry) 78%, transparent);
}
.pill--streak .pill__ic { background: var(--retry); color: #2B2B3A; }
.pill--goal { border-color: color-mix(in srgb, var(--ok-bright) 45%, var(--line-strong)); }
:root[data-theme="dark"] .pill--streak .pill__ic { color: #21170C; }

/* "Filter" toggle + the collapsible drawer holding sort + subject chips */
.filtertoggle .caret { display: inline-block; margin-left: 4px; transition: transform var(--dur-fast); }
.filtertoggle.is-on .caret { transform: rotate(180deg); }
.filterdrawer { display: flex; flex-direction: column; gap: var(--s-3); margin: var(--s-2) 0 var(--s-3); }
.filterdrawer .sortsel { align-self: flex-start; }

/* calendar / upcoming, shown in a dialog off the Today panel */
.caldialog { max-width: 460px; }
.caldialog__head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); margin-bottom: var(--s-3); }
.caldialog__head h3 { display: flex; align-items: center; gap: var(--s-2); }
.caldialog .upcoming { margin-bottom: 0; }

/* Dedicated #/calendar page — same content as the dialog, capped to the
   same width so the month grid doesn't stretch across a wide screen. */
.calendarpage { max-width: 460px; }

@media (max-width: 480px) {
  /* In the calendar dialog on a phone the month grid is more bulk than help —
     the Upcoming list already says when everything is due. */
  .caldialog .cal { display: none; }
}

/* ---------- upcoming deadlines ---------- */
.upcoming { margin-bottom: var(--s-4); }
.upcoming__title {
  display: flex; align-items: center; gap: var(--s-2);
  font-size: var(--fs-md); margin-bottom: var(--s-3); color: var(--ink-soft);
}
.upcoming .cal { margin-bottom: var(--s-4); }
.upcoming__list { display: flex; flex-direction: column; gap: var(--s-2); }
.upcoming__row {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 8px var(--s-3); border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--line);
  text-decoration: none; color: inherit;
  transition: border-color var(--dur-fast), background var(--dur-fast);
}
.upcoming__row:hover { border-color: var(--brand); }
.upcoming__row.is-soon { border-color: var(--retry); }
.upcoming__row.is-overdue { border-color: var(--retry); background: var(--retry-tint); }
.upcoming__dot {
  width: 8px; height: 8px; flex: none; border-radius: var(--r-full);
  background: var(--subject, var(--brand));
}
.upcoming__main { flex: 1; min-width: 0; }
.upcoming__main strong {
  display: block; font-family: var(--font-display); font-weight: 600; font-size: var(--fs-sm);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.upcoming__meta { display: block; font-size: 12px; color: var(--ink-soft); }
.upcoming__row.is-soon .upcoming__meta,
.upcoming__row.is-overdue .upcoming__meta { color: var(--retry-ink); }
.upcoming__go { flex: none; color: var(--ink-faint); display: grid; place-items: center; }
.upcoming__row:hover .upcoming__go { color: var(--brand); }
.upcoming__more {
  margin-top: var(--s-2); padding: 6px 2px;
  border: none; background: none; cursor: pointer;
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-sm);
  color: var(--brand-ink); text-decoration: underline; text-underline-offset: 3px;
}
.upcoming__more:hover { color: var(--ink); }

/* Home-rail calendar collapse — a single, navigable week by default (the
   "Show full month" link sits in the panel label, next to "Upcoming"); a
   note up top when the week in view has nothing due. The dialog version
   gets neither. Kept plain (no underline, regular weight) so the label row
   stays quiet next to the bold "Upcoming" heading. */
.cal-collapse__toggle { font-weight: 400; text-decoration: none; }
.cal-empty { margin: 0 0 var(--s-2); }

/* Countdown + one-tap study shortcut to the soonest test, directly under
   the calendar. Built like an .upcoming__row, tinted red once it's within
   a day of the deadline. */
.next-test-wrap { display: flex; flex-direction: column; gap: 4px; margin: 0 0 var(--s-3); }
a.next-test {
  display: grid; grid-template-columns: 1fr auto; gap: 1px var(--s-2);
  padding: 8px var(--s-3);
  border-radius: var(--r-md); background: var(--surface); border: 1px solid var(--line);
  text-decoration: none; color: inherit;
  transition: border-color var(--dur-fast), background var(--dur-fast);
}
.next-test__prep {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 4px; font-size: 12px; font-weight: 600;
  color: var(--brand-ink); text-decoration: none;
}
.next-test__prep:hover { text-decoration: underline; }
.next-test__prep svg { flex: none; }
a.next-test:hover { border-color: var(--brand); }
.next-test__when {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; color: var(--ink-soft);
}
.next-test__when svg { flex: none; color: var(--ink-faint); }
.next-test__title {
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-sm);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.next-test__go {
  grid-column: 2; grid-row: 1 / 3; align-self: center;
  color: var(--ink-faint); display: grid; place-items: center;
}
a.next-test:hover .next-test__go { color: var(--brand); }
a.next-test--soon { border-color: var(--retry); background: var(--retry-tint); }
.next-test--soon .next-test__when,
.next-test--soon .next-test__when svg { color: var(--retry-ink); }

.acard__tag--due { background: var(--surface-sunk); color: var(--ink-soft); }
.acard__tag--overdue { background: var(--retry-tint); color: var(--retry-ink); }

/* ---------- daily goal ring ---------- */
.ring--goal { width: 34px; height: 34px; }
.ring--goal .ring__fg { stroke: var(--brand); }
.ring--goal .ring__label { font-size: 13px; fill: var(--ink); }
/* Goal met: full ring goes green and the count is replaced by a check (the
   number moves to the label beside the ring). */
.ring--goal-done .ring__fg { stroke: var(--ok); }
.ring--goal .ring__check { stroke: var(--ok); }
.tile--goal .ring { flex: none; }

/* ---------- calendar (js/components/calendar.js) ---------- */
.cal__nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--s-2); }
.cal__month {
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-sm);
  text-transform: capitalize; letter-spacing: .01em;
}
.cal__navbtn {
  width: 30px; height: 30px; flex: none; border-radius: var(--r-sm);
  border: 1px solid var(--line-strong); background: var(--surface);
  color: var(--ink-soft); cursor: pointer; font-size: 18px; line-height: 1;
  display: grid; place-items: center;
}
.cal__navbtn:hover { background: var(--surface-sunk); color: var(--ink); }
.cal__week, .cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.cal__week { margin-bottom: 4px; }
.cal__wd {
  text-align: center; font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; color: var(--ink-faint); padding: 4px 0;
}
.cal__grid { gap: 2px; }
.cal__cell {
  position: relative; aspect-ratio: 1; min-height: 34px;
  display: grid; place-items: center;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: none; font: inherit; font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
  color: var(--ink); cursor: default;
}
button.cal__cell { cursor: pointer; }
button.cal__cell:hover:not(:disabled) { background: var(--surface-sunk); }
.cal__cell.is-outside { color: var(--ink-faint); }
.cal__cell.is-today { font-weight: 700; box-shadow: inset 0 0 0 1px var(--line-strong); }
.cal__cell.is-selected {
  background: var(--brand); color: #fff; font-weight: 700;
  box-shadow: none;
}
.cal__cell:disabled { color: var(--ink-faint); opacity: .4; }
.cal__cell:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.cal__dot {
  position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%);
  width: 5px; height: 5px; border-radius: var(--r-full); background: var(--brand);
}
/* More than one deadline that day — a wider pill hints "there's a few". */
.cal__dot--multi { width: 12px; }
.cal__cell.is-marked { color: var(--brand-ink); font-weight: 700; }
.cal--mini .cal__cell.is-marked:hover { background: var(--brand-tint); }

/* Empty future day — a faint "+" on hover/focus says "tap to add a set here". */
.cal__cell.is-addable .cal__add {
  position: absolute; bottom: 2px; left: 50%; transform: translateX(-50%);
  font-size: 12px; line-height: 1; color: var(--ink-faint); opacity: 0;
  transition: opacity var(--dur-fast);
}
.cal__cell.is-addable:hover .cal__add,
.cal__cell.is-addable:focus-visible .cal__add { opacity: 1; }
.cal__cell.is-addable:hover { background: var(--brand-tint); color: var(--brand-ink); }

.datepick { display: block; }
.datepick__chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: var(--s-3); }
.datepick__chip {
  font-size: var(--fs-sm); font-weight: 600; font-family: var(--font-display);
  border: 1px solid var(--line-strong); background: var(--surface);
  color: var(--ink-soft); padding: 5px var(--s-3); border-radius: var(--r-full);
  cursor: pointer; transition: transform var(--dur-fast) var(--ease-spring), border-color var(--dur-fast);
}
.datepick__chip:hover { transform: translateY(-1px); border-color: var(--brand); color: var(--ink); }

/* ---------- search & sort ---------- */
/* Tabs on the left, search + sort on the right, wrapping to two rows when
   there is not enough width for both. */
.librarybar {
  display: flex; align-items: center; gap: var(--s-3);
  flex-wrap: wrap; margin-bottom: var(--s-3);
}
.librarybar .tabs { flex: none; }
.librarybar .tools { flex: 1; min-width: 260px; margin-bottom: 0; justify-content: flex-end; }
.tools { display: flex; gap: var(--s-3); margin-bottom: var(--s-4); flex-wrap: wrap; }
.search { position: relative; display: flex; align-items: center; flex: 1; min-width: 180px; color: var(--ink-faint); }
.search svg { position: absolute; left: 12px; pointer-events: none; }
.search__input {
  width: 100%; font: inherit; color: var(--ink);
  padding: var(--s-2) var(--s-3) var(--s-2) 38px;
  border-radius: var(--r-full); border: 1px solid var(--line-strong); background: var(--surface);
}
.search__input:focus-visible { border-color: var(--brand); box-shadow: none; }
.linkbtn {
  font: inherit; font-size: inherit; padding: 0; border: none; background: none;
  color: var(--brand-ink); text-decoration: underline; cursor: pointer;
}
.linkbtn:hover { color: var(--brand); }

.sortsel {
  font: inherit; padding: var(--s-2) var(--s-3); border-radius: var(--r-full);
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink);
}

.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--s-4); }

.acard {
  position: relative; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line);
  border-left: 6px solid var(--subject, var(--brand));
  border-radius: var(--r-md); padding: var(--s-4);
  display: flex; flex-direction: column; gap: var(--s-3); min-height: 148px;
  box-shadow: var(--shadow-1);
  transition: transform var(--dur-mid) var(--ease-spring), box-shadow var(--dur-mid);
  animation: pop-in var(--dur-mid) var(--ease-out) both;
}
.acard:hover { transform: translateY(-4px); box-shadow: var(--shadow-2); }
.acard:hover .acard__go { transform: translateX(3px); }
.acard__tag {
  align-self: flex-start; font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: 3px 8px; border-radius: var(--r-full);
  background: var(--subject-tint, var(--brand-tint)); color: var(--subject-ink, var(--brand-ink));
}
.acard__tag--open { background: var(--ok-tint); color: var(--ok-ink); }
.acard__title { font-family: var(--font-display); font-weight: 600; font-size: var(--fs-lg); }
.acard__meta { margin-top: auto; display: flex; align-items: center; justify-content: space-between; color: var(--ink-faint); font-size: var(--fs-sm); }
.acard__go { transition: transform var(--dur-mid) var(--ease-spring); }

.acard--new {
  border: 2px dashed var(--line-strong); border-left: 2px dashed var(--line-strong);
  align-items: center; justify-content: center; color: var(--ink-soft);
  font-family: var(--font-display); font-weight: 600; gap: var(--s-2); box-shadow: none;
}
.acard--new:hover { border-color: var(--brand); color: var(--brand-ink); }

.empty { text-align: center; color: var(--ink-soft); padding: var(--s-7) var(--s-4); }
.empty svg { margin-bottom: var(--s-3); }

/* ---------- card ⋮ menu ---------- */
.acard { position: relative; }
.acard__menu {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  width: 30px; height: 30px; border-radius: var(--r-full);
  display: grid; place-items: center; cursor: pointer;
  border: none; background: transparent; color: var(--ink-faint);
  opacity: 0; transition: opacity var(--dur-fast), background var(--dur-fast);
}
.acard:hover .acard__menu, .acard__menu:focus-visible { opacity: 1; }
.acard__menu:hover { background: var(--surface-sunk); color: var(--ink); }
@media (hover: none) { .acard__menu { opacity: 1; } }

.cardmenu {
  position: absolute; z-index: 60; min-width: 180px;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--r-md); box-shadow: var(--shadow-2);
  padding: 6px; display: flex; flex-direction: column; gap: 2px;
}
.cardmenu__item {
  display: flex; align-items: center; gap: var(--s-3);
  font: inherit; font-size: var(--fs-sm); text-align: left;
  padding: var(--s-2) var(--s-3); border: none; border-radius: var(--r-sm);
  background: transparent; color: var(--ink); cursor: pointer;
}
.cardmenu__item:hover { background: var(--surface-sunk); }
.cardmenu__item--danger { color: var(--retry-ink); }
.cardmenu__item--danger:hover { background: var(--retry-tint); }

.iconbtn--sm { width: 30px; height: 30px; }

/* ---------- mastery ring (small, on cards) ---------- */
.ring { --v: 0; width: 38px; height: 38px; flex: none; }
.ring circle { fill: none; stroke-width: 5; }
.ring__label {
  font-family: var(--font-display); font-weight: 700; font-size: 11px;
  fill: var(--ink-soft); font-variant-numeric: tabular-nums;
}
.ring .ring__bg { stroke: var(--line); }
.ring .ring__fg { stroke: var(--subject, var(--ok)); stroke-linecap: round;
  stroke-dasharray: 100 100; stroke-dashoffset: calc(100 - var(--v));
  transition: stroke-dashoffset var(--dur-slow) var(--ease-out); }

/* ---------- session ---------- */
.session__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); margin-bottom: var(--s-2); flex-wrap: wrap;
}
.session__headright { display: flex; align-items: center; gap: var(--s-2); }
/* The shortcuts button is the only affordance for the keyboard layer, so it
   stays visible at every width rather than hiding on small screens. */
.shortcutsbtn, .readingbtn { width: 36px; height: 36px; flex: none; }
/* Keyboard shortcuts are desktop-only value; on a phone the reading control
   is the one that earns its place. */
@media (max-width: 560px) { .shortcutsbtn { display: none; } }

/* Reading-comfort popover (anchored from the session header) */
.reading__t { font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-faint); padding: 4px 6px 6px; margin: 0; }
.reading__themes { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 6px; padding: 0 4px 6px; }
.reading__sw {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 8px 4px 6px; border-radius: 10px; border: 1px solid var(--line-strong);
  background: var(--surface); cursor: pointer; font: inherit; font-size: 11px; font-weight: 600; color: var(--ink-soft);
}
.reading__chip { width: 100%; height: 20px; border-radius: 6px; border: 1px solid var(--line); }
.reading__sw--light .reading__chip { background: #F5F7FC; }
.reading__sw--paper .reading__chip { background: #F1E7D0; }
.reading__sw--dark  .reading__chip { background: #0A0C11; }
.reading__sw.is-on { border-color: var(--brand); color: var(--brand-ink); box-shadow: 0 0 0 1px var(--brand); }
.reading__row { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); padding: 8px 6px; border-top: 1px solid var(--line); }
.reading__k { font-size: var(--fs-sm); color: var(--ink-soft); }
.reading__seg { display: inline-flex; gap: 2px; padding: 2px; border-radius: var(--r-full); background: var(--surface-sunk); }
.reading__seg button { min-width: 30px; padding: 3px 0; border: none; background: transparent; border-radius: var(--r-full); cursor: pointer; color: var(--ink-faint); font-family: var(--font-display); line-height: 1; }
.reading__seg button.is-on { background: var(--surface); color: var(--brand-ink); font-weight: 700; box-shadow: var(--shadow-1); }
.reading__toggle { width: 40px; height: 22px; border-radius: var(--r-full); border: none; background: var(--line-strong); cursor: pointer; position: relative; flex: none; transition: background var(--dur-fast); }
.reading__toggle.is-on { background: var(--brand); }
.reading__knob { position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: transform var(--dur-fast); }
.reading__toggle.is-on .reading__knob { transform: translateX(18px); }

.session { display: grid; grid-template-columns: 1fr 380px; gap: var(--s-5); align-items: start; }
/* The empty track was 1.05:1 against the page — invisible until it had fill.
   The border gives the shape an edge without shouting. */
.progressbar {
  height: 10px; border-radius: var(--r-full); overflow: hidden; margin-bottom: var(--s-2);
  background: color-mix(in srgb, var(--ink) 20%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--ink) 52%, var(--surface));
}
.progressbar__fill { height: 100%; border-radius: var(--r-full);
  background: linear-gradient(90deg, var(--c-sky), var(--c-grape));
  width: 0%; transition: width var(--dur-slow) var(--ease-spring); }
.progress-label { font-size: var(--fs-sm); color: var(--ink-faint); }

.question { margin-top: var(--s-4); }
.question__topline { display: flex; align-items: flex-start; gap: var(--s-3); margin-bottom: var(--s-4); }
.question__topline .question__prompt { margin-bottom: 0; flex: 1; min-width: 0; }
.question__prompt { font-size: var(--fs-lg); font-family: var(--font-display); font-weight: 600; margin-bottom: var(--s-4); }
/* Read-aloud button on the question card. */
.q-speak {
  flex: none; width: 32px; height: 32px; border-radius: var(--r-full);
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink-soft);
  display: grid; place-items: center; cursor: pointer; margin-top: 2px;
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.q-speak:hover { color: var(--brand); border-color: var(--brand); }
.q-speak.is-on { background: var(--brand); border-color: var(--brand); color: #fff; }
.reading__row--stack { flex-direction: column; align-items: stretch; gap: 6px; }
.reading__voice { width: 100%; font: inherit; font-size: var(--fs-sm); padding: 6px 8px; border-radius: var(--r-sm); border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink); }

.choices { display: flex; flex-direction: column; gap: var(--s-3); }
.choice {
  text-align: left; font: inherit; cursor: pointer;
  padding: var(--s-3) var(--s-4); border-radius: var(--r-md);
  border: 2px solid var(--line-strong); background: var(--surface);
  display: flex; align-items: center; gap: var(--s-3);
  transition: border-color var(--dur-fast), background var(--dur-fast), transform var(--dur-fast) var(--ease-spring);
}
.choice:hover { transform: translateY(-1px); border-color: var(--brand); }
.choice__key {
  width: 28px; height: 28px; flex: none; border-radius: var(--r-full);
  display: grid; place-items: center; font-weight: 700; font-family: var(--font-display);
  background: var(--surface-sunk); color: var(--ink-soft);
}
.choice[aria-pressed="true"] { border-color: var(--brand); background: var(--brand-tint); }
.choice.is-correct { border-color: var(--ok); background: var(--ok-tint); animation: pop var(--dur-mid) var(--ease-spring); }
.choice.is-wrong  { border-color: var(--retry); background: var(--retry-tint); animation: nudge var(--dur-mid) var(--ease-out); }
.choice.is-correct .choice__key { background: var(--ok); color: #fff; }
.choice.is-wrong .choice__key { background: var(--retry); color: #fff; }

/* The question screen, tinted to the assignment's own subject colour — the
   one screen a student stares at for most of a session, so it shouldn't be
   the flattest one. Right/wrong feedback stays green/amber regardless —
   correctness is a separate signal from "whose subject this is". */
.session-page--tinted .progressbar__fill { background: linear-gradient(90deg, var(--subject-tint), var(--subject)); }
.session-page--tinted .choice:hover { border-color: var(--subject); }
.session-page--tinted .choice[aria-pressed="true"] { border-color: var(--subject); background: var(--subject-tint); }

.answerbox {
  width: 100%; font: inherit; padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md); border: 2px solid var(--line-strong);
  background: var(--surface); resize: vertical; min-height: 92px;
}
.answerbox:focus-visible { border-color: var(--brand); box-shadow: none; }

.feedback { margin-top: var(--s-4); padding: var(--s-4); border-radius: var(--r-md); font-size: var(--fs-sm); }
.feedback.ok { background: var(--ok-tint); color: var(--ok-ink); }
.feedback.retry { background: var(--retry-tint); color: var(--retry-ink); }

.flashcard { perspective: 1200px; }
.flashcard__inner {
  position: relative; min-height: 200px; border-radius: var(--r-lg);
  transition: transform var(--dur-slow) var(--ease-spring); transform-style: preserve-3d; cursor: pointer;
}
.flashcard.is-flipped .flashcard__inner { transform: rotateY(180deg); }
.flashcard__face {
  position: absolute; inset: 0; backface-visibility: hidden;
  display: grid; place-items: center; text-align: center; padding: var(--s-5);
  border-radius: var(--r-lg); border: 2px solid var(--line-strong); background: var(--surface);
  font-size: var(--fs-lg); font-family: var(--font-display); font-weight: 600;
}
.flashcard__face--back { transform: rotateY(180deg); background: var(--brand-tint); }
.selfrate { display: flex; gap: var(--s-2); margin-top: var(--s-4); flex-wrap: wrap; }

/* "how sure were you?" row after a practice answer */
.confrow { display: flex; align-items: center; gap: var(--s-2); margin-top: var(--s-4); flex-wrap: wrap; }
.confrow__q { font-size: var(--fs-sm); font-weight: 700; color: var(--ink-soft); }
.confrow .btn.is-picked { background: var(--brand); color: #fff; border-color: transparent; }

/* cloze fill-in-the-blank */
.cloze { font-size: var(--fs-md); line-height: 2.1; }
.cloze__blank {
  font: inherit; width: auto; min-width: 60px;
  border: none; border-bottom: 2px solid var(--brand);
  background: var(--surface-sunk); border-radius: var(--r-sm) var(--r-sm) 0 0;
  padding: 2px 6px; margin: 0 2px; color: var(--ink);
}
.cloze__blank:focus-visible { outline: none; background: var(--brand-tint); }
.cloze__blank.is-correct { border-color: var(--ok); background: var(--ok-tint); color: var(--ok-ink); }
.cloze__blank.is-wrong { border-color: var(--retry); background: var(--retry-tint); color: var(--retry-ink); }

/* math keypad */
.mathpad {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
  gap: 4px; margin-top: var(--s-3); max-width: 340px;
}
.mathpad__key {
  font: inherit; font-size: var(--fs-md); cursor: pointer;
  aspect-ratio: 1; border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink);
}
.mathpad__key:hover { background: var(--surface-sunk); border-color: var(--brand); }

/* adaptive-pacing note in a session */
.adaptive:not(:empty) { margin-bottom: var(--s-3); }

/* test-mode banner + its "turn off / turn on" toggle */
.testbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px 16px; flex-wrap: wrap; margin-bottom: var(--s-3);
}
.testbar .btn { flex: none; }

/* Pomodoro countdown in the session header */
.pomo {
  font-variant-numeric: tabular-nums; font-weight: 700; font-size: var(--fs-sm);
  padding: 4px var(--s-2); border-radius: var(--r-sm);
  background: var(--surface-sunk); color: var(--ink-soft);
}
.pomo.is-up { background: var(--retry-tint); color: var(--retry-ink); }

/* exam clock in the session header */
.examtimer {
  display: inline-flex; align-items: center; gap: 5px;
  font-variant-numeric: tabular-nums; font-weight: 700; font-size: var(--fs-sm);
  padding: 4px var(--s-2); border-radius: var(--r-sm);
  background: var(--surface-sunk); color: var(--ink-soft);
}
.examtimer--warn { background: var(--retry-tint); color: var(--retry-ink); }
.examtimer svg { flex: none; }

/* editor: drag handle + reorder */
.qedit__grip { cursor: grab; color: var(--ink-faint); font-size: 16px; user-select: none; padding: 0 4px; }
.qedit.is-dragging { opacity: .5; }
.qedit.is-dragover { outline: 2px dashed var(--brand); outline-offset: 2px; }

/* sample gallery */
.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--s-4); }
.gallery__card {
  display: flex; flex-direction: column; gap: 6px; align-items: flex-start;
  padding: var(--s-4); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface);
}
.gallery__card h3 { font-size: var(--fs-md); }
.gallery__card .btn { margin-top: auto; }
.gallery__preview { font-style: italic; color: var(--ink-soft); font-size: var(--fs-sm); }

/* practice library */
.libgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: var(--s-3); margin-top: var(--s-4); }
.libcard {
  border: 1px solid var(--line); border-left: 4px solid var(--subject, var(--line)); border-radius: var(--r-md); padding: var(--s-4);
  background: var(--surface); display: flex; flex-direction: column; gap: var(--s-3);
  justify-content: space-between; min-width: 0;
}
.libcard__title { font-family: var(--font-display); font-weight: 600; font-size: var(--fs-md); }
.libcard__foot { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); flex-wrap: wrap; }
/* An already-added set: clear "in your library" state + Study as the primary. */
.libcard--added { border-color: color-mix(in srgb, var(--ok-bright) 38%, var(--line)); }
.libcard__added { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-sm); font-weight: 700; color: var(--ok-ink); }
.libcard__added svg { flex: none; }
.libcard__count { font-weight: 400; color: var(--ink-faint); }
/* "Exam-mode options" disclosure above the set grid. */
.libexam { margin-top: var(--s-3); }
.libexam summary, .set-ai-how summary {
  cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 6px;
  font-weight: 600; font-size: var(--fs-sm); color: var(--ink-soft);
}
.libexam summary::-webkit-details-marker, .set-ai-how summary::-webkit-details-marker { display: none; }
.libexam summary::before, .set-ai-how summary::before {
  content: "▸"; font-size: 10px; color: var(--ink-faint); transition: transform var(--dur-fast);
}
.libexam[open] summary::before, .set-ai-how[open] summary::before { transform: rotate(90deg); }
.libexam summary svg { flex: none; }

/* first-run walkthrough */
.onb .modal__card { max-width: 400px; text-align: center; position: relative; }
.onb__emoji { font-size: 44px; line-height: 1; margin-bottom: var(--s-3); }
.onb__body h2 { font-size: var(--fs-lg); margin-bottom: var(--s-2); }
.onb__body p { color: var(--ink-soft); }
.onb__dots { display: flex; gap: 6px; justify-content: center; margin: var(--s-4) 0; }
.onb__dot { width: 7px; height: 7px; border-radius: var(--r-full); background: var(--line-strong); }
.onb__dot.is-on { background: var(--brand); }
.onb__nav { display: flex; align-items: center; gap: var(--s-2); }
.onb__x { position: absolute; top: 8px; right: 12px; border: none; background: none; font-size: 20px; cursor: pointer; color: var(--ink-faint); }

/* command palette */
.cmd { align-items: flex-start; padding-top: 12vh; }
.cmd__card { background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--r-lg); box-shadow: var(--shadow-2); width: 100%; max-width: 480px; overflow: hidden; }
.cmd__input { width: 100%; border: none; border-bottom: 1px solid var(--line); padding: var(--s-4); font: inherit; font-size: var(--fs-md); background: var(--surface); color: var(--ink); }
.cmd__input:focus-visible { outline: none; }
.cmd__list { max-height: 320px; overflow-y: auto; }
.cmd__row { width: 100%; display: flex; justify-content: space-between; gap: var(--s-3); align-items: center; padding: 10px var(--s-4); border: none; background: none; font: inherit; color: var(--ink); cursor: pointer; text-align: left; }
.cmd__row.is-sel { background: var(--brand-tint); }
.cmd__sub { font-size: 12px; color: var(--ink-faint); flex: none; }

/* Weekly recap — a slim line at the top of the Today panel */
.recap {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  padding: 6px var(--s-3); margin-bottom: var(--s-3);
  border-radius: var(--r-sm); border: 1px solid var(--line);
  background: var(--surface-sunk); font-size: var(--fs-sm);
}
.recap > div { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; min-width: 0; }
.recap strong { font-family: var(--font-display); }
.recap__body { color: var(--ink-soft); }
.recap__x {
  flex: none; border: none; background: none; cursor: pointer;
  font-size: 18px; line-height: 1; color: var(--ink-faint); padding: 2px 4px;
}
.recap__x:hover { color: var(--ink); }
/* In the "Idag" panel the recap sits last now — after the resume banner and
   the stat pills — so it needs a top gap, not a bottom one. */
.home-panel--today > .recap { margin: var(--s-3) 0 0; }

.nav-row { display: flex; justify-content: space-between; gap: var(--s-3); margin-top: var(--s-5); }

/* ---------- tutor chat ---------- */
.mascot { position: relative; display: inline-flex; flex: none; }
.mascot__dot {
  position: absolute; right: -2px; bottom: -2px; width: 10px; height: 10px;
  border-radius: var(--r-full); border: 2px solid var(--surface);
}
.mascot__dot--pulse { animation: mascot-pulse 1.1s ease-in-out infinite; }
@keyframes mascot-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

.tutor { position: sticky; top: 76px; display: flex; flex-direction: column; max-height: calc(100vh - 100px); }
.tutor__head { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-4); border-bottom: 1px solid var(--line); }
.tutor__title { font-family: var(--font-display); font-weight: 600; }
.tutor__sub { font-size: var(--fs-sm); color: var(--ink-faint); }
.tutor__log { flex: 1; overflow-y: auto; padding: var(--s-4); display: flex; flex-direction: column; gap: var(--s-3); }
.msg { max-width: 92%; padding: var(--s-3) var(--s-4); border-radius: var(--r-md); font-size: var(--fs-sm); line-height: 1.5; }
.msg p + p { margin-top: .5em; }
.msg.ai { background: var(--surface-sunk); align-self: flex-start; border-bottom-left-radius: 4px; }
.msg.me { background: var(--brand); color: #fff; align-self: flex-end; border-bottom-right-radius: 4px; }
.msg.ai code, .msg.me code { background: rgba(0,0,0,.08); padding: 1px 4px; border-radius: 4px; }
.tutor__form { display: flex; gap: var(--s-2); padding: var(--s-3); border-top: 1px solid var(--line); }
.tutor__input { flex: 1; font: inherit; padding: var(--s-2) var(--s-3); border-radius: var(--r-full); border: 1px solid var(--line-strong); background: var(--surface); }
.tutor__input:focus-visible { border-color: var(--brand); box-shadow: none; }
.voice-btn { position: relative; color: var(--ink-faint); }
.voice-btn:hover { color: var(--ink-soft); }
.voice-btn:disabled { opacity: .4; cursor: not-allowed; }
.voice-btn.is-listening {
  color: var(--retry-ink); background: var(--retry);
  animation: voicepulse 1.3s ease-in-out infinite;
}
@keyframes voicepulse { 0%, 100% { box-shadow: 0 0 0 0 var(--retry); } 50% { box-shadow: 0 0 0 5px transparent; } }
@media (prefers-reduced-motion: reduce) { .voice-btn.is-listening { animation: none; } }
.voice-soon {
  position: absolute; bottom: -3px; right: -3px;
  font-size: 8px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase;
  background: var(--retry); color: #2B2B3A; padding: 1px 4px; border-radius: var(--r-full);
  line-height: 1.3;
}
.tooltip { position: relative; }
.tooltip[data-tip]:hover::after {
  content: attr(data-tip); position: absolute; bottom: calc(100% + 6px); right: 0;
  background: var(--ink); color: #fff; font-size: 12px; font-weight: 600;
  padding: 4px 8px; border-radius: 6px; white-space: nowrap;
}
.tutor__locked { padding: var(--s-4); text-align: center; color: var(--ink-soft); }
.tutor__locked p:first-child { font-family: var(--font-display); font-weight: 600; margin-bottom: var(--s-2); }

.typing span { display: inline-block; width: 6px; height: 6px; margin: 0 1px; border-radius: 50%; background: var(--ink-faint); animation: blink 1.2s infinite both; }
.typing span:nth-child(2) { animation-delay: .2s; }
.typing span:nth-child(3) { animation-delay: .4s; }

/* ---------- site help chat (floating widget, any page) ---------- */
.sitechat__fab {
  position: fixed; right: var(--s-4); bottom: var(--s-4); z-index: 40;
  width: 56px; height: 56px; border-radius: var(--r-full);
  display: grid; place-items: center; border: none; cursor: pointer;
  background: var(--brand); color: #fff; box-shadow: var(--shadow-2);
  transition: transform var(--dur-fast) var(--ease-spring);
}
.sitechat__fab:hover { transform: translateY(-2px) scale(1.05); }
.sitechat__panel {
  position: fixed; right: var(--s-4); bottom: calc(var(--s-4) + 56px + var(--s-3)); z-index: 40;
  width: min(360px, calc(100vw - var(--s-4) * 2));
  height: min(520px, calc(100vh - 160px));
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-2); overflow: hidden;
}
.sitechat__head { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-4); border-bottom: 1px solid var(--line); }
.sitechat__title { font-family: var(--font-display); font-weight: 700; }
.sitechat__sub { font-size: var(--fs-sm); color: var(--ink-faint); }
.sitechat__log { flex: 1; overflow-y: auto; padding: var(--s-4); display: flex; flex-direction: column; gap: var(--s-3); }
.sitechat__form { display: flex; gap: var(--s-2); padding: var(--s-3); border-top: 1px solid var(--line); }
.sitechat__input { flex: 1; font: inherit; padding: var(--s-2) var(--s-3); border-radius: var(--r-full); border: 1px solid var(--line-strong); background: var(--surface); }
.sitechat__input:focus-visible { border-color: var(--brand); box-shadow: none; }
.sitechat__input:disabled { opacity: .6; }
.sitechat__form .iconbtn:disabled { opacity: .4; cursor: not-allowed; }
.sitechat__dormant { padding: var(--s-4); text-align: center; color: var(--ink-soft); }
.sitechat__dormant p:first-child { font-family: var(--font-display); font-weight: 600; margin-bottom: var(--s-2); color: var(--ink); }
/* Clear of the fixed bottom tab bar on mobile. */
@media (max-width: 899.98px) {
  .sitechat__fab { bottom: calc(70px + var(--s-3) + env(safe-area-inset-bottom, 0)); }
  .sitechat__panel { bottom: calc(70px + 56px + var(--s-4) + env(safe-area-inset-bottom, 0)); }
}
@media (max-width: 480px) {
  .sitechat__panel { right: var(--s-3); left: var(--s-3); width: auto; }
}
/* A running session has its own bottom action row (Skip/Next/Finish) in the
   same corner the widget floats in — hide it there rather than fight for
   the same few pixels. body.session-active is kept in sync by main.js. */
body.session-active .sitechat__fab,
body.session-active .sitechat__panel { display: none; }

/* ---------- landing page (#/welcome) ----------
   Rendered without the app shell, so this section owns its own header,
   footer and rhythm. Everything still comes from the app's tokens, so it
   follows theme (light / paper / dark) like every other screen. */
.btn--lg { padding: var(--s-4) var(--s-6); font-size: var(--fs-lg); }

.lp { position: relative; min-height: 100vh; display: flex; flex-direction: column; overflow-x: clip; }
/* One soft wash behind the fold instead of a hard gradient band — reads as
   depth rather than decoration, and survives all three themes. */
.lp-glow {
  position: absolute; inset: -20% -10% auto; height: 900px; z-index: 0; pointer-events: none;
  background:
    radial-gradient(48% 42% at 22% 30%, color-mix(in srgb, var(--brand) 20%, transparent), transparent 70%),
    radial-gradient(42% 38% at 82% 12%, color-mix(in srgb, var(--c-grape) 17%, transparent), transparent 72%),
    radial-gradient(38% 34% at 62% 48%, color-mix(in srgb, var(--c-sky) 12%, transparent), transparent 75%);
}
.lp > *:not(.lp-glow) { position: relative; z-index: 1; }

/* header */
.lp-head { padding: var(--s-5) var(--s-4) 0; }
.lp-head__inner {
  max-width: 1120px; margin: 0 auto;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
}
.lp-brand {
  display: inline-flex; align-items: center; gap: var(--s-2);
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-lg);
  letter-spacing: -.01em; color: var(--ink); text-decoration: none;
}
.lp-brand img { width: 30px; height: 30px; }
.lp-head__actions { display: flex; align-items: center; gap: var(--s-3); }
.lp-head__actions .btn { white-space: nowrap; }
.lp-lang {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: var(--r-full);
  border: 1px solid var(--line-strong); background: var(--surface);
  font: inherit; font-size: 12px; font-weight: 700; letter-spacing: .03em;
  color: var(--ink-soft); cursor: pointer;
  transition: background var(--dur-fast), color var(--dur-fast);
}
.lp-lang:hover { background: var(--surface-sunk); color: var(--ink); }
.lp-lang__flag svg { width: 18px; height: auto; display: block; border-radius: 2px; }

.lp-main { flex: 1; width: 100%; max-width: 1120px; margin: 0 auto; padding: 0 var(--s-4); }

/* hero */
.lp-hero {
  display: grid; grid-template-columns: 1fr; gap: var(--s-7);
  align-items: center; padding: var(--s-8) 0 var(--s-8);
}
@media (min-width: 900px) {
  .lp-hero { grid-template-columns: 1.05fr .95fr; gap: var(--s-8); padding: 84px 0 96px; }
}
.lp-chip {
  display: inline-flex; align-items: center; gap: 7px; margin-bottom: var(--s-5);
  padding: 6px 14px; border-radius: var(--r-full);
  background: var(--brand-tint); color: var(--brand-ink);
  font-size: 12.5px; font-weight: 700; letter-spacing: .01em;
}
.lp-h1 {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(2.3rem, 6vw, 3.9rem); line-height: 1.04; letter-spacing: -.035em;
  text-wrap: balance; color: var(--ink); margin: 0;
}
.lp-lead {
  margin-top: var(--s-5); max-width: 34em;
  font-size: clamp(1rem, 1.5vw, 1.19rem); line-height: 1.6; color: var(--ink-soft);
}
.lp-cta { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-6); }
.lp-fineprint { margin-top: var(--s-4); font-size: var(--fs-sm); color: var(--ink-faint); }

/* hero mock */
.lp-hero__art { display: flex; justify-content: center; }
.lp-mock {
  width: 100%; max-width: 420px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-2); overflow: hidden;
}
@media (min-width: 900px) {
  .lp-mock { transform: rotate(-1.4deg); }
}
.lp-mock__bar {
  display: flex; gap: 6px; padding: var(--s-3) var(--s-4);
  background: var(--surface-sunk); border-bottom: 1px solid var(--line);
}
.lp-mock__dot { width: 9px; height: 9px; border-radius: 50%; background: var(--line-strong); }
.lp-mock__body { padding: var(--s-5); }
.lp-mock__meta { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
.lp-mock__tag {
  font-size: 10px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
  color: var(--c-leaf-ink); background: var(--c-leaf-tint); padding: 3px 9px; border-radius: var(--r-full);
}
.lp-mock__count { font-size: 11.5px; font-weight: 600; color: var(--ink-faint); }
.lp-mock__track { height: 5px; border-radius: 3px; background: var(--surface-sunk); margin: var(--s-4) 0 var(--s-5); overflow: hidden; }
.lp-mock__track i { display: block; width: 62%; height: 100%; border-radius: 3px; background: var(--c-leaf); }
.lp-mock__q {
  font-family: var(--font-display); font-weight: 700; font-size: 1.02rem;
  line-height: 1.4; color: var(--ink); margin: 0 0 var(--s-4);
}
.lp-mock__opts { display: flex; flex-direction: column; gap: var(--s-2); }
.lp-mock__opt {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 11px var(--s-4); border-radius: var(--r-md);
  border: 1px solid var(--line); background: var(--surface);
  font-size: var(--fs-sm); color: var(--ink-soft);
}
.lp-mock__opt b {
  flex: none; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center; font-size: 11px; font-weight: 800;
  background: var(--surface-sunk); color: var(--ink-faint);
}
.lp-mock__opt.is-right {
  border-color: color-mix(in srgb, var(--ok) 55%, var(--line));
  background: var(--ok-tint); color: var(--ok-ink); font-weight: 600;
}
.lp-mock__opt.is-right b { background: var(--ok); color: #fff; }
.lp-mock__opt.is-right svg { margin-left: auto; color: var(--ok-ink); }
.lp-mock__note {
  display: flex; align-items: center; gap: 7px; margin-top: var(--s-4);
  font-size: 12px; color: var(--brand-ink);
}

/* sections */
.lp-sec { padding: var(--s-8) 0; border-top: 1px solid var(--line); }
.lp-h2 {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(1.6rem, 3.2vw, 2.25rem); line-height: 1.12; letter-spacing: -.025em;
  text-wrap: balance; color: var(--ink); margin: 0;
}
.lp-sub { margin-top: var(--s-3); max-width: 52ch; color: var(--ink-soft); }

.lp-grid { display: grid; grid-template-columns: 1fr; gap: var(--s-4); margin-top: var(--s-6); }
@media (min-width: 640px) { .lp-grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1000px) { .lp-grid { grid-template-columns: repeat(4, 1fr); gap: var(--s-3); } }
.lp-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--s-5);
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast), border-color var(--dur-fast);
}
.lp-card:hover {
  transform: translateY(-3px); box-shadow: var(--shadow-1);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}
.lp-card__ic {
  display: grid; place-items: center; width: 44px; height: 44px;
  border-radius: var(--r-md); background: var(--accent-tint); color: var(--accent-ink);
  margin-bottom: var(--s-4);
}
.lp-card h3 {
  font-family: var(--font-display); font-weight: 700; font-size: 1.03rem;
  line-height: 1.3; color: var(--ink); margin: 0 0 6px;
}
.lp-card p { font-size: var(--fs-sm); line-height: 1.55; color: var(--ink-soft); margin: 0; }

/* steps */
.lp-steps { list-style: none; margin: var(--s-6) 0 0; padding: 0; display: grid; gap: var(--s-5); }
@media (min-width: 820px) { .lp-steps { grid-template-columns: repeat(3, 1fr); gap: var(--s-6); } }
.lp-step { display: flex; gap: var(--s-4); align-items: flex-start; }
.lp-step__n {
  flex: none; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-sm);
  background: var(--brand); color: #fff; box-shadow: var(--shadow-1);
}
.lp-step h3 {
  font-family: var(--font-display); font-weight: 700; font-size: 1.03rem;
  color: var(--ink); margin: 5px 0 6px;
}
.lp-step p { font-size: var(--fs-sm); line-height: 1.55; color: var(--ink-soft); margin: 0; }

/* trust strip */
.lp-trust {
  display: flex; flex-wrap: wrap; gap: var(--s-4) var(--s-6);
  padding: var(--s-5) var(--s-5);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
}
.lp-trust__item {
  display: inline-flex; align-items: center; gap: var(--s-2);
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-soft);
}
.lp-trust__item svg { color: var(--ok); flex: none; }

/* closer */
.lp-closer {
  margin: var(--s-8) 0; padding: var(--s-8) var(--s-5);
  text-align: center; border-radius: var(--r-lg);
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--brand) 12%, var(--surface)),
    color-mix(in srgb, var(--c-grape) 10%, var(--surface)));
  border: 1px solid color-mix(in srgb, var(--brand) 22%, var(--line));
}
.lp-closer .lp-sub { margin: var(--s-3) auto var(--s-6); }
.lp-closer .lp-h2 { margin-inline: auto; max-width: 26ch; }

/* footer */
.lp-foot { border-top: 1px solid var(--line); padding: var(--s-6) var(--s-4); }
.lp-foot__inner {
  max-width: 1120px; margin: 0 auto;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-3) var(--s-5);
  font-size: var(--fs-sm); color: var(--ink-faint);
}
.lp-foot__brand {
  display: inline-flex; align-items: center; gap: var(--s-2);
  font-family: var(--font-display); font-weight: 700; color: var(--ink-soft);
}
.lp-foot__brand img { width: 20px; height: 20px; }
.lp-foot__links { display: flex; flex-wrap: wrap; gap: var(--s-4); }
.lp-foot__links a { color: var(--ink-faint); text-decoration: none; }
.lp-foot__links a:hover { color: var(--ink-soft); text-decoration: underline; }
.lp-foot__copy { width: 100%; font-size: 12px; }
@media (min-width: 760px) { .lp-foot__copy { width: auto; } }

/* The chat bubble is app furniture — it has no place on the front page, and
   its "not connected yet" state is the worst possible first impression. */
body.no-chrome .sitechat__fab,
body.no-chrome .sitechat__panel { display: none; }

@media (prefers-reduced-motion: reduce) {
  .lp-card:hover { transform: none; }
  .lp-mock { transform: none; }
}

/* ---------- results ---------- */
.results { text-align: center; max-width: 560px; margin: 0 auto; }
.scorering { width: 180px; height: 180px; margin: var(--s-4) auto; }
.scorering circle { fill: none; stroke-width: 14; }
.scorering .bg { stroke: var(--surface-sunk); }
.scorering .fg { stroke: var(--ok); stroke-linecap: round; transform: rotate(-90deg); transform-origin: 50% 50%;
  transition: stroke-dashoffset 900ms var(--ease-out); }
.scorering text { font-family: var(--font-display); font-weight: 700; fill: var(--ink); }
.delta-list { display: flex; flex-direction: column; gap: var(--s-2); margin: var(--s-5) 0; text-align: left; }
.delta { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); padding: var(--s-3) var(--s-4); border-radius: var(--r-md); background: var(--surface); border: 1px solid var(--line); }
.delta__bar { flex: 1; height: 8px; border-radius: var(--r-full); background: var(--surface-sunk); overflow: hidden; margin: 0 var(--s-3); }
.delta__bar i { display: block; height: 100%; background: var(--ok); border-radius: inherit; transition: width var(--dur-slow) var(--ease-out); }
.delta__n { font-size: var(--fs-sm); font-weight: 700; }
.delta__n.up { color: var(--ok); } .delta__n.down { color: var(--retry-ink); }

/* Wrong-answer review on the results screen — the correct answer + any
   authored explanation, reusing the .delta-list card look but stacked
   instead of the topic-mastery rows' left/right layout. */
.delta-list--review .delta--review { flex-direction: column; align-items: flex-start; gap: 6px; }
.delta__prompt { font-weight: 600; }
.delta__answer, .delta__explain { margin: 0; font-size: var(--fs-sm); }
.delta__explain { color: var(--ink-faint); }

/* "Scheduled for review" summary on the results screen. */
.results .srs-next { color: var(--ink); font-weight: 700; }

/* ---------- progress dashboard ---------- */
.dash { display: grid; gap: var(--s-5); }
.streak { display: flex; gap: 6px; flex-wrap: wrap; }
.streak__day { width: 30px; height: 30px; flex: none; border-radius: var(--r-sm); background: var(--surface-sunk); display: grid; place-items: center; font-size: 11px; color: var(--ink-faint); }
.streak__day.on { background: var(--ok); color: #fff; font-weight: 700; }
.streak__day.frozen { background: var(--info); color: #fff; font-weight: 700; }
/* "is-today", not ".today" — a bare .today rule elsewhere is a 210px grid. */
.streak__day.is-today { outline: 2px solid var(--brand); outline-offset: 1px; }

/* A banked streak freeze, shown next to the streak badge. */
.freezechip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px var(--s-2); border-radius: var(--r-full);
  background: var(--info-tint); color: var(--info);
  font-size: var(--fs-sm); font-weight: 700;
}

/* Achievements shelf */
.badges { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: var(--s-3); }
.badge-card {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4); border-radius: var(--r-md);
  border: 1px solid var(--line); background: var(--surface);
}
.badge-card__emoji { font-size: 26px; flex: none; line-height: 1; }
.badge-card__text { display: flex; flex-direction: column; min-width: 0; }
.badge-card__text strong { font-family: var(--font-display); font-size: var(--fs-md); }
.badge-card.is-locked { background: var(--surface-sunk); border-style: dashed; }
.badge-card.is-locked .badge-card__emoji { filter: grayscale(1); opacity: .45; }
.badge-card.is-locked .badge-card__text strong { color: var(--ink-soft); }

/* 12-week study heatmap — 7 rows (Mon-Sun), columns are weeks, oldest left. */
.heatmap {
  display: grid; grid-template-rows: repeat(7, 13px); grid-auto-flow: column;
  grid-auto-columns: 13px; gap: 3px; width: max-content; max-width: 100%;
}
.heatmap__cell { width: 13px; height: 13px; border-radius: 3px; background: var(--surface-sunk); }
.heatmap__cell.on { background: var(--ok); }
.heatmap__cell.frozen { background: var(--info); }
.heatmap__cell.is-today { outline: 2px solid var(--brand); outline-offset: 1px; }
.meter { display: grid; grid-template-columns: 120px 1fr 44px 26px; align-items: center; gap: var(--s-3); padding: var(--s-2) 0; }
.meter__track { height: 10px; border-radius: var(--r-full); background: var(--surface-sunk); overflow: hidden; }
.meter__fill { height: 100%; border-radius: inherit; background: var(--subject, var(--brand)); transition: width var(--dur-slow) var(--ease-out); }
/* "A long-term measure — your last result was X%" under a subject's meter, so
   the mastery % doesn't read as contradicting a recent test score. */
.meter__context { margin: 2px 0 6px; font-size: 12px; color: var(--ink-faint); }
.due-list { display: flex; flex-direction: column; gap: var(--s-2); }
.due-item { display: flex; justify-content: space-between; gap: var(--s-3); padding: var(--s-3) var(--s-4); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }
.due-item__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.due-item__why { font-size: var(--fs-sm); color: var(--ink-faint); }

/* Results "what you'll still remember" — two forgetting curves. */
.retention { width: 100%; max-width: 380px; height: auto; display: block; }
.retention__grid { stroke: var(--line); stroke-width: 1; }
.retention__lab { fill: var(--ink-faint); font-size: 9px; font-family: var(--font-body); }
.retention__without { fill: none; stroke: var(--retry); stroke-width: 2; stroke-dasharray: 4 3; stroke-linecap: round; }
.retention__with { fill: none; stroke: var(--brand); stroke-width: 2.5; stroke-linecap: round; }
.retention__dot { fill: var(--brand); }
.retention__legend { display: flex; gap: var(--s-4); flex-wrap: wrap; font-size: var(--fs-sm); color: var(--ink-soft); margin-top: 4px; }
.retention__k { display: inline-block; width: 16px; border-top: 2px solid; vertical-align: middle; margin-right: 6px; }
.retention__k--without { border-top-style: dashed; color: var(--retry); }
.retention__k--with { color: var(--brand); }
.retention__cap { font-size: 12px; color: var(--ink-faint); margin-top: 6px; }

/* Review-recall sparkline — bare line chart, scales to the panel width. */
.sparkline { width: 100%; height: auto; display: block; }
.sparkline polyline { fill: none; stroke: var(--brand); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.sparkline circle { fill: var(--brand); }
.sparkline circle.last { fill: var(--ok); }

/* ---------- exam prep ---------- */
.exam-prep { display: grid; gap: var(--s-4); max-width: 640px; }
.exam-prep h1 { margin: 0; }
.exam-prep .panel { margin: 0; }
.exam-prep__head { border-left: 3px solid var(--brand); }
.exam-prep__when { margin: 0; font-weight: 700; display: flex; align-items: center; gap: 6px; }
.exam-prep__when svg { flex: none; color: var(--brand-ink); }
.exam-prep__sets { display: flex; flex-direction: column; gap: var(--s-2); }
.exam-prep__set {
  display: flex; align-items: center; gap: var(--s-2);
  padding: 4px 8px 4px var(--s-3); border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--line);
  transition: border-color var(--dur-fast);
}
.exam-prep__set:hover { border-color: var(--brand); }
.exam-prep__set-link { display: flex; align-items: center; gap: var(--s-3); flex: 1; min-width: 0; text-decoration: none; color: inherit; padding: 6px 0; }
.exam-prep__set-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.exam-prep__set-pct { flex: none; font-weight: 700; color: var(--ink-soft); }
.exam-prep__set svg { flex: none; color: var(--ink-faint); }
.exam-prep__actions { display: flex; flex-wrap: wrap; gap: var(--s-3); align-items: center; }
.exam-prep__mock { display: flex; gap: var(--s-2); align-items: flex-end; flex-wrap: wrap; }
.exam-prep__pick { display: flex; flex-direction: column; gap: var(--s-2); margin-top: var(--s-3); }
.exam-prep__pick-card {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4); border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--line);
  border-left: 3px solid var(--subject, var(--brand));
  text-decoration: none; color: inherit;
  transition: border-color var(--dur-fast), background var(--dur-fast);
}
.exam-prep__pick-card:hover { background: var(--surface-sunk); }
.exam-prep__pick-name { flex: 1; min-width: 0; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.exam-prep__pick-when {
  flex: none; font-size: 12px; font-weight: 600; color: var(--ink-soft);
  background: var(--surface-sunk); padding: 2px 8px; border-radius: var(--r-full);
}
.exam-prep__pick-pct { flex: none; font-weight: 700; color: var(--ink-soft); }
.exam-prep__pick-card svg { flex: none; color: var(--ink-faint); }

/* Subject % sits in the heading; the body is a per-topic breakdown, weakest
   first — one whole-subject bar isn't much to prep from. */
.exam-prep__mastery-head { display: flex; align-items: baseline; gap: var(--s-2); flex-wrap: wrap; }
.exam-prep__pct { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-md); color: var(--ink-soft); }
.exam-prep__topics { display: flex; flex-direction: column; gap: 2px; margin-top: var(--s-2); }
.exam-prep__topics .meter { grid-template-columns: minmax(88px, 42%) 1fr 44px; }

/* The dated study plan — today → test day, one task per row. */
.exam-prep__plan { border-left: 3px solid var(--brand); }
.exam-prep__days { list-style: none; margin: var(--s-3) 0 0; padding: 0; display: grid; gap: 2px; }
.exam-prep__day {
  display: grid; grid-template-columns: 66px 1fr auto; align-items: center;
  gap: var(--s-3); padding: 8px 10px; border-radius: var(--r-sm); font-size: var(--fs-sm);
}
.exam-prep__day-when { color: var(--ink-faint); font-weight: 700; font-size: 12px; text-transform: capitalize; }
.exam-prep__day-task { min-width: 0; color: var(--ink-soft); }
.exam-prep__day-min { color: var(--ink-faint); font-size: 12px; flex: none; }
.exam-prep__day.is-today { background: var(--brand-tint); }
.exam-prep__day.is-today .exam-prep__day-task { color: var(--ink); font-weight: 600; }
.exam-prep__day.is-today .exam-prep__day-when { color: var(--brand-ink); }
.exam-prep__day.is-test .exam-prep__day-task { color: var(--ink-faint); font-style: italic; }
.exam-prep__day .btn--sm { padding: 4px 12px; white-space: nowrap; }

/* ---------- formula sheet ---------- */
.ref { max-width: 760px; }
.ref__tabs { margin-bottom: var(--s-4); flex-wrap: wrap; }
.ref__group { margin-bottom: var(--s-5); }
.ref__group h3 { font-size: var(--fs-md); color: var(--ink-soft); margin-bottom: var(--s-3); }
.ref__items { display: grid; gap: var(--s-2); }
.ref__item {
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface);
  padding: var(--s-3) var(--s-4);
}
.ref__item-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-4); flex-wrap: wrap; }
.ref__name { font-weight: 600; font-size: var(--fs-sm); }
.ref__formula { font-size: var(--fs-md); overflow-x: auto; max-width: 100%; }
.ref__note { margin: 6px 0 0; font-size: 12px; color: var(--ink-faint); }

/* ---------- calculator & graph plotter ---------- */
.calc { max-width: 560px; }
.calc__screen { background: var(--surface-sunk); border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--s-3); }
.calc__screentop { display: flex; gap: var(--s-2); align-items: center; }
.calc__input {
  flex: 1; min-width: 0; font: inherit; font-size: var(--fs-md); font-family: ui-monospace, "SF Mono", Menlo, monospace;
  border: 1px solid var(--line-strong); border-radius: var(--r-sm); padding: 8px 10px;
  background: var(--surface); color: var(--ink);
}
.calc__output {
  margin-top: var(--s-2); text-align: right; font-size: var(--fs-xl); font-weight: 700;
  font-family: ui-monospace, "SF Mono", Menlo, monospace; color: var(--ink);
  overflow-x: auto; min-height: 1.4em;
}
.calc__output.is-error { color: var(--retry-ink); font-size: var(--fs-md); font-weight: 500; }
.calc__pad { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin-top: var(--s-3); }
.calc__key {
  font: inherit; font-size: var(--fs-md); font-weight: 600; padding: 12px 0;
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink); cursor: pointer;
  transition: background var(--dur-fast);
}
.calc__key:hover { background: var(--surface-sunk); }
.calc__key--op { color: var(--brand-ink); }
.calc__key--eq { background: var(--brand); color: #fff; border-color: var(--brand); }
.calc__key--eq:hover { background: var(--brand-bright); }
.calc__history { margin-top: var(--s-3); display: grid; gap: 4px; }
.calc__hrow {
  display: flex; justify-content: space-between; gap: var(--s-3); width: 100%;
  border: none; background: none; cursor: pointer; padding: 4px 6px; border-radius: var(--r-sm);
  font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12px; color: var(--ink-soft); text-align: left;
}
.calc__hrow:hover { background: var(--surface-sunk); }
.calc__hval { color: var(--ink); font-weight: 700; flex: none; }
.calc__grange { display: flex; gap: var(--s-3); align-items: end; flex-wrap: wrap; margin-bottom: var(--s-3); }
.calc__grange label { font-size: var(--fs-sm); color: var(--ink-soft); display: flex; flex-direction: column; gap: 4px; }
.calc__num { width: 90px; font: inherit; padding: 6px 8px; border: 1px solid var(--line-strong); border-radius: var(--r-sm); background: var(--surface); color: var(--ink); }
.calc__canvaswrap { border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; background: var(--surface); }
.calc__canvas { display: block; width: 100%; height: auto; }
.calc__gmsg.is-error { color: var(--retry-ink); }

/* ---------- create flow ---------- */
.steps { display: flex; gap: var(--s-2); margin-bottom: var(--s-5); flex-wrap: wrap; }
.step { font-size: var(--fs-sm); font-weight: 700; color: var(--ink-faint); display: flex; align-items: center; gap: 6px; }
.step.on { color: var(--brand-ink); }
.step__n { width: 22px; height: 22px; border-radius: var(--r-full); background: var(--surface-sunk); display: grid; place-items: center; font-size: 12px; }
.step.on .step__n { background: var(--brand); color: #fff; }

.source-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--s-3); }
.source-opt { position: relative; cursor: pointer; padding: var(--s-5) var(--s-4); border-radius: var(--r-md); border: 2px solid var(--line-strong); background: var(--surface); text-align: center; font-family: var(--font-display); font-weight: 600; transition: transform var(--dur-fast) var(--ease-spring), border-color var(--dur-fast); }
.source-opt:hover { transform: translateY(-2px); border-color: var(--brand); }
.source-opt svg { display: block; margin: 0 auto var(--s-2); }
/* An AI-generated source with no server to run it — still openable (you can
   prepare the material), just clearly marked as not ready to generate. Dimmed
   enough to read as "not now" at a glance, and the hover stays neutral
   (no brand-blue invitation) so it doesn't compete with the sources that
   actually work right now. */
.source-opt--locked { border-style: dashed; border-color: var(--line); opacity: .6; }
.source-opt--locked svg { opacity: .7; }
.source-opt--locked:hover { transform: none; border-color: var(--line-strong); }

/* Library's subject picker only — every subject otherwise looked identical
   (same brand-blue book icon), which read as flat. Same colour-accent idiom
   .acard already uses (a solid stripe, not a full-saturation border all
   round), so it matches how subjects look everywhere else in the app. */
.source-opt--subject { border-left: 6px solid var(--subject, var(--line-strong)); }
.source-opt--subject svg { color: var(--subject, var(--brand)); }
.source-opt--subject:hover { border-color: var(--subject, var(--brand)); }
.source-opt__tag {
  display: inline-flex; align-items: center; gap: 4px; margin-top: var(--s-2); font-size: 11px; font-weight: 700;
  color: var(--ink-faint); background: var(--surface-sunk);
  padding: 2px 8px; border-radius: var(--r-full);
}
.source-opt__tag svg { margin: 0; flex: none; }

/* Subject field: text input + one-tap chips for the subjects that exist. */
.subjectfield { display: flex; flex-direction: column; gap: var(--s-2); }
.subjchips { display: flex; flex-wrap: wrap; gap: 6px; }
.subjchips .chip { font-size: var(--fs-sm); font-weight: 600; }

.field { display: block; margin-bottom: var(--s-4); }
.field > span { display: block; font-weight: 700; font-size: var(--fs-sm); margin-bottom: var(--s-2); }
.field input[type=text], .field input[type=number], .field input[type=email], .field input[type=password], .field select, .field textarea {
  width: 100%; font: inherit; padding: var(--s-3); border-radius: var(--r-md);
  border: 1px solid var(--line-strong); background: var(--surface);
}
.field textarea { min-height: 160px; resize: vertical; }

/* Bare (non-.field) date inputs — the HP prov-date picker today — dressed to
   match the rest of the app instead of raw browser chrome. color-scheme is
   already set per-theme on :root, so the native calendar icon/popup follow
   light/dark/paper on their own. */
input[type=date] {
  font: inherit; font-size: var(--fs-sm); color: var(--ink);
  padding: 9px var(--s-3); border-radius: var(--r-md);
  border: 1px solid var(--line-strong); background: var(--surface);
}
input[type=date]:focus-visible { border-color: var(--brand); }
input[type=date]::-webkit-calendar-picker-indicator { cursor: pointer; border-radius: var(--r-sm); }

.qedit { border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--s-4); margin-bottom: var(--s-3); background: var(--surface); }
.qedit__row { display: flex; gap: var(--s-2); align-items: center; margin-bottom: var(--s-2); }
.badge { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 2px 8px; border-radius: var(--r-full); background: var(--surface-sunk); color: var(--ink-soft); }
.dot { display: inline-block; width: 8px; height: 8px; flex: none; border-radius: 50%; }

.spinner { width: 42px; height: 42px; border-radius: 50%; border: 4px solid var(--surface-sunk); border-top-color: var(--brand); animation: spin .8s linear infinite; margin: var(--s-6) auto; }

/* ---------- settings ---------- */

/* The three "how it looks and sounds" controls sit side by side and wrap on
   narrow screens, instead of stacking as three separate panels. */
.settings__row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--s-3); margin-top: var(--s-3);
}
.settings__row .field { margin-bottom: 0; }
.settings__row + .note { margin-top: var(--s-3); }
.settings__row + .note + .note { margin-top: var(--s-2); }

/* Each control with its own help text directly beneath it — one field per
   grid cell — instead of a row of controls and a clump of notes under them. */
.settings__fields {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--s-4) var(--s-5); align-items: start; margin-top: var(--s-3);
}
.settings__fields .field { margin-bottom: 0; }
.panel > .note + .settings__fields { margin-top: var(--s-3); }
.field__note { margin-top: var(--s-2); }

/* Offline-library download progress in Settings. */
.offline-bar { height: 8px; border-radius: var(--r-full); background: var(--surface-sunk); overflow: hidden; margin-bottom: var(--s-3); }
.offline-bar i { display: block; height: 100%; width: 0; background: var(--brand); border-radius: inherit; transition: width var(--dur-mid) var(--ease-out); }

/* Sub-heading inside a merged panel: a hairline rule carries the grouping so
   the panel does not need to become two panels again. */
.settings__sub {
  font-family: var(--font-display); font-size: var(--fs-md); font-weight: 700;
  margin-top: var(--s-5); padding-top: var(--s-4); border-top: 1px solid var(--line);
}
.panel > .settings__sub:first-of-type { margin-top: var(--s-4); padding-top: 0; border-top: none; }

/* Not a panel — the roadmap is information, not something you can change. */
.roadmapbox > h3 { font-size: var(--fs-md); color: var(--ink-soft); margin-bottom: var(--s-3); }
.settings { display: grid; gap: var(--s-5); max-width: 620px; }
.keyrow { display: flex; gap: var(--s-2); }
.note { font-size: var(--fs-sm); color: var(--ink-soft); }
.note--warn { background: var(--retry-tint); color: var(--retry-ink); padding: var(--s-3) var(--s-4); border-radius: var(--r-md); }
.preset-table { width: 100%; border-collapse: collapse; margin-top: var(--s-3); font-size: var(--fs-sm); }
.preset-table th, .preset-table td { text-align: left; padding: 6px 8px; border-top: 1px solid var(--line); }
.preset-table th { font-weight: 600; color: var(--ink-soft); width: 40%; }
.preset-table td:nth-child(2) { font-weight: 700; }

.roadmap { list-style: none; display: grid; gap: var(--s-2); }
.roadmap li { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-3) var(--s-4); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); color: var(--ink-soft); }
.roadmap li::before { content: "🔜"; }

.toast {
  position: fixed; left: 50%; bottom: var(--s-5); transform: translateX(-50%) translateY(20px);
  /* Fixed dark pill regardless of theme — var(--ink) flips to near-white in
     dark mode, which left the hardcoded white text unreadable against it. */
  background: #2B2B3A; color: #fff; padding: var(--s-3) var(--s-5); border-radius: var(--r-full);
  font-weight: 600; font-size: var(--fs-sm); box-shadow: var(--shadow-2);
  opacity: 0; pointer-events: none; transition: opacity var(--dur-mid), transform var(--dur-mid) var(--ease-spring);
  z-index: 50;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast:has(.toast__action) { display: flex; align-items: center; gap: var(--s-3); }
.toast:has(.toast__action).show { pointer-events: auto; }
.toast__action {
  font: inherit; font-weight: 700; cursor: pointer;
  background: none; border: none; color: #9FBCFF;
  text-decoration: underline; text-underline-offset: 3px; padding: 0;
}
.toast__action:hover { color: #fff; }

/* Persistent top banner (js/lib/dom.js showBanner) — unlike .toast, never
   auto-dismisses. Reserved for things the student must actually see, like a
   failed save. */
.savebar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 110;
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: var(--retry-tint); color: var(--retry-ink);
  font-weight: 600; font-size: var(--fs-sm);
  transform: translateY(-100%); transition: transform var(--dur-mid) var(--ease-out);
}
.savebar.show { transform: translateY(0); }
.savebar__action {
  margin-left: auto; font: inherit; font-weight: 700; cursor: pointer;
  background: none; border: none; color: inherit;
  text-decoration: underline; text-underline-offset: 3px; padding: 0;
}
.savebar__close {
  font: inherit; cursor: pointer; background: none; border: none; color: inherit;
  font-size: 18px; line-height: 1; padding: 0 2px; flex: none;
}

/* ---------- animations ---------- */
@keyframes pop-in { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
@keyframes pop { 0% { transform: scale(1); } 40% { transform: scale(1.04); } 100% { transform: scale(1); } }
@keyframes nudge { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes blink { 0%,80%,100% { opacity: .2; } 40% { opacity: 1; } }

/* ---------- shortcuts modal ---------- */
.modal {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(20, 18, 28, .5); backdrop-filter: blur(3px);
  display: grid; place-items: center; padding: var(--s-4);
}
.modal__card {
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--r-lg); box-shadow: var(--shadow-2);
  padding: var(--s-5); max-width: 420px; width: 100%;
}

/* Centred yes/no dialog — replaces window.confirm. */
.confirmdlg__card { max-width: 400px; }
.confirmdlg__body {
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-lg);
  line-height: 1.3; color: var(--ink);
}
.confirmdlg__note {
  margin-top: var(--s-3); padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md); background: var(--ok-tint); color: var(--ok-ink);
  font-size: var(--fs-sm); line-height: 1.4;
}
.confirmdlg--danger .confirmdlg__note { background: var(--retry-tint); color: var(--retry-ink); }
.confirmdlg__actions {
  display: flex; justify-content: flex-end; gap: var(--s-3);
  margin-top: var(--s-5); flex-wrap: wrap;
}
.confirmdlg__actions .btn { flex: 1 1 auto; justify-content: center; min-width: 120px; }
kbd {
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace; font-size: 12px;
  background: color-mix(in srgb, var(--ink) 20%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--ink) 52%, var(--surface));
  border-bottom-width: 2px; border-radius: 6px; padding: 2px 6px; color: var(--ink);
  white-space: nowrap;
}
/* .kbdhint removed — the shortcuts button in the session header replaced it. */

/* The floating hint button only exists on narrow screens. */
.hintfab { display: none; }

/* ---------- responsive ---------- */
@media (max-width: 860px) {
  .session { grid-template-columns: 1fr; }

  /* Tutor becomes a slide-up sheet so a stuck student never has to scroll
     away from the question to reach help. */
  .tutor {
    /* top: auto matters — the desktop rule sets top for sticky, and a fixed
       box with both top and bottom set ignores bottom. */
    position: fixed; top: auto; left: 0; right: 0; bottom: 0; z-index: 70;
    max-height: min(70vh, 520px);
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    border-bottom: none;
    box-shadow: var(--shadow-2);
    transform: translateY(101%);
    transition: transform var(--dur-mid) var(--ease-out);
  }
  .tutor.is-open { transform: translateY(0); }

  /* In normal document flow, right above .nav-row — not fixed, so it can
     never land on top of the Skip/Next buttons regardless of how tall the
     question above it is. Closing the open sheet is the tutor panel's own
     job (.tutor__close), since this button scrolls away with the question. */
  .hintfab {
    display: block; margin: 0 auto var(--s-4); width: max-content;
    font-family: var(--font-display); font-weight: 600; font-size: var(--fs-sm);
    padding: var(--s-3) var(--s-5); border-radius: var(--r-full);
    border: none; background: var(--brand); color: #fff;
    box-shadow: var(--shadow-1); cursor: pointer;
  }

  .tutor__close { display: inline-flex; margin-left: auto; }
}
@media (min-width: 861px) {
  .tutor__close { display: none; }
}
@media (max-width: 540px) {
  .content { padding: var(--s-5) var(--s-3) var(--s-7); }
  h1 { font-size: 1.6rem; }
  .grid { grid-template-columns: 1fr 1fr; }
  .meter { grid-template-columns: 88px 1fr 40px 26px; gap: var(--s-2); }
}
@media (max-width: 380px) {
  .grid { grid-template-columns: 1fr; }
}

/* ---------- print worksheet ---------- */
.psheet__bar { display: flex; gap: 10px; margin-bottom: var(--s-5); }
.psheet__title { font-size: var(--fs-xl); margin-bottom: 4px; }
.psheet__meta { color: var(--ink-soft); font-size: var(--fs-sm); margin-bottom: var(--s-5); }
.psheet__item { margin-bottom: var(--s-5); break-inside: avoid; }
.psheet__q { margin-bottom: 8px; }
.psheet__choices { margin: 4px 0 0 22px; }
.psheet__choices li { list-style: upper-alpha; margin: 2px 0; }
.psheet__lines { height: 64px; border-bottom: 1px solid var(--line-strong);
  background: repeating-linear-gradient(var(--surface), var(--surface) 27px, var(--line) 28px); }
.psheet__break { break-before: page; margin-top: var(--s-8); }
.psheet__akey { margin: 3px 0; font-size: var(--fs-sm); }

/* ---------- shell: leaderboard + bell + account actions ---------- */
.topbar__actions { display: flex; align-items: center; gap: var(--s-2); }
.topbar__leaderboard.is-active { color: var(--brand-ink); border-color: var(--brand-ink); }
.topbar__bell { position: relative; }
.topbar__dot {
  position: absolute; top: 5px; right: 5px; width: 9px; height: 9px;
  border-radius: var(--r-full); background: var(--retry); border: 2px solid var(--surface);
}

.popover {
  position: absolute; z-index: 60; max-width: calc(100vw - 16px);
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--r-md); box-shadow: var(--shadow-2);
  padding: 6px; display: flex; flex-direction: column; gap: 2px;
}
.popover .note { margin: 0; }

/* ---------- notification panel ---------- */
.notifpanel__head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); padding: var(--s-2) var(--s-2) var(--s-3); }
.notifpanel__head h3 { font-size: var(--fs-md); }
.notiftabs { display: flex; gap: 4px; padding: 0 var(--s-1) var(--s-2); border-bottom: 1px solid var(--line); margin-bottom: var(--s-2); }
.notiftab {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px;
  font: inherit; font-size: var(--fs-sm); font-weight: 600;
  padding: var(--s-2) var(--s-3); border: none; border-radius: var(--r-full);
  background: transparent; color: var(--ink-soft); cursor: pointer;
}
.notiftab[aria-selected="true"] { background: var(--surface-sunk); color: var(--ink); }
.notiftab__count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--r-full);
  background: var(--brand); color: #fff; font-size: 11px; font-weight: 700;
}
.notifpanel__body { max-height: min(420px, 60vh); overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }
.notifcard { display: flex; gap: var(--s-3); padding: var(--s-3); border-radius: var(--r-md); background: transparent; }
.notifcard--unread { background: var(--brand-tint); }
.notifcard__icon {
  flex: none; width: 34px; height: 34px; border-radius: var(--r-full);
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-sunk); color: var(--ink-soft);
}
.notifcard--unread .notifcard__icon { background: var(--brand); color: #fff; }
.notifcard__main { flex: 1; min-width: 0; }
.notifcard__title { font-weight: 700; font-size: var(--fs-sm); margin-bottom: 2px; }
.notifcard__text { font-size: var(--fs-sm); color: var(--ink-soft); margin-bottom: var(--s-2); }
.notifcard__footer { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); font-size: var(--fs-sm); flex-wrap: wrap; }
.notifcard__link { color: var(--brand-ink); font-weight: 600; text-decoration: underline; }
.notifcard__meta { color: var(--ink-faint); white-space: nowrap; }
.notifcard__mark {
  flex: none; align-self: flex-start; width: 30px; height: 30px; border-radius: var(--r-full);
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink-soft);
  cursor: pointer; transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.notifcard__mark:hover { background: var(--ok); color: #fff; border-color: transparent; }

/* ---------- achievements page ---------- */
.achievements-page { display: flex; flex-direction: column; gap: var(--s-5); }
.achievements-head h1 { margin-bottom: 4px; }
.ach-summary__bar { margin-top: var(--s-3); height: 8px; border-radius: var(--r-full); background: var(--surface-sunk); overflow: hidden; max-width: 360px; }
.ach-summary__bar i { display: block; height: 100%; border-radius: inherit; background: var(--brand); transition: width var(--dur-slow) var(--ease-out); }
.achgroup__title { display: flex; align-items: center; gap: var(--s-2); margin-bottom: var(--s-4); color: var(--ink-soft); font-size: var(--fs-md); }
.achrow { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: var(--s-3); }
.achbadge {
  position: relative;
  display: flex; gap: var(--s-3); align-items: flex-start;
  padding: var(--s-4); border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--line);
  animation: pop-in var(--dur-mid) var(--ease-out) both;
}
.achbadge__icon {
  flex: none; width: 44px; height: 44px; border-radius: var(--r-full);
  display: grid; place-items: center;
  background: var(--surface-sunk); color: var(--ink-faint); border: 1px solid var(--line-strong);
}
.achbadge__body { min-width: 0; }
.achbadge:has(.achbadge__share) { padding-bottom: 40px; }
.achbadge__top { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; flex-wrap: wrap; }
.achbadge__tiername { font-weight: 700; font-size: var(--fs-sm); color: var(--ink-faint); text-transform: uppercase; letter-spacing: .03em; }
.achbadge__check { display: grid; place-items: center; flex: none; width: 18px; height: 18px; border-radius: var(--r-full); background: var(--ok); color: #fff; }
.achbadge__desc { font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.4; margin: 0 0 var(--s-2); }
.achbadge__unlockdate { font-size: var(--fs-sm); color: var(--ink-faint); font-weight: 600; margin: 0; }
.achbadge__progress { display: flex; align-items: center; gap: var(--s-2); }
.achbadge__bar { flex: 1; height: 6px; border-radius: var(--r-full); background: var(--surface-sunk); overflow: hidden; }
.achbadge__bar i { display: block; height: 100%; border-radius: inherit; background: var(--ink-faint); transition: width var(--dur-slow) var(--ease-out); }
.achbadge__fraction { font-size: var(--fs-sm); color: var(--ink-faint); font-variant-numeric: tabular-nums; flex: none; }
.achbadge--unlocked { border-color: transparent; }
.achbadge--unlocked.achbadge--bronze { background: var(--ach-bronze-tint); }
.achbadge--unlocked.achbadge--bronze .achbadge__icon { background: var(--ach-bronze); color: #fff; border-color: transparent; }
.achbadge--unlocked.achbadge--bronze .achbadge__tiername { color: var(--ach-bronze-ink); }
.achbadge--unlocked.achbadge--silver { background: var(--ach-silver-tint); }
.achbadge--unlocked.achbadge--silver .achbadge__icon { background: var(--ach-silver); color: #fff; border-color: transparent; }
.achbadge--unlocked.achbadge--silver .achbadge__tiername { color: var(--ach-silver-ink); }
.achbadge--unlocked.achbadge--gold { background: var(--ach-gold-tint); }
.achbadge--unlocked.achbadge--gold .achbadge__icon { background: var(--ach-gold); color: #fff; border-color: transparent; }
.achbadge--unlocked.achbadge--gold .achbadge__tiername { color: var(--ach-gold-ink); }
.achbadge--unlocked.achbadge--platinum { background: linear-gradient(135deg, var(--brand-tint), var(--c-ocean-tint) 60%, var(--c-berry-tint)); }
.achbadge--unlocked.achbadge--platinum .achbadge__icon {
  background: linear-gradient(135deg, var(--brand), var(--c-ocean) 55%, var(--c-berry));
  color: #fff; border-color: transparent;
  box-shadow: 0 0 0 3px var(--surface), 0 0 14px rgba(58, 106, 224, .38);
}
.achbadge--unlocked.achbadge--platinum .achbadge__tiername { color: var(--brand-ink); }

/* Locked tiered badges hint at their eventual colour — full tint waits for
   .achbadge--unlocked above — so brons/silver/guld/platina read as a visible
   ladder of destinations even before the first one's earned, not four
   identical grey circles. Only the icon ring + tier name shift; the card's
   own background stays neutral so an unlocked badge still visibly pops out
   from the row. */
.achbadge--bronze:not(.achbadge--unlocked) .achbadge__icon {
  background: color-mix(in srgb, var(--ach-bronze) 16%, var(--surface-sunk));
  border-color: color-mix(in srgb, var(--ach-bronze) 45%, var(--line-strong));
  color: color-mix(in srgb, var(--ach-bronze-ink) 60%, var(--ink-faint));
}
.achbadge--bronze:not(.achbadge--unlocked) .achbadge__tiername { color: color-mix(in srgb, var(--ach-bronze-ink) 70%, var(--ink-faint)); }
.achbadge--silver:not(.achbadge--unlocked) .achbadge__icon {
  background: color-mix(in srgb, var(--ach-silver) 16%, var(--surface-sunk));
  border-color: color-mix(in srgb, var(--ach-silver) 45%, var(--line-strong));
  color: color-mix(in srgb, var(--ach-silver-ink) 60%, var(--ink-faint));
}
.achbadge--silver:not(.achbadge--unlocked) .achbadge__tiername { color: color-mix(in srgb, var(--ach-silver-ink) 70%, var(--ink-faint)); }
.achbadge--gold:not(.achbadge--unlocked) .achbadge__icon {
  background: color-mix(in srgb, var(--ach-gold) 16%, var(--surface-sunk));
  border-color: color-mix(in srgb, var(--ach-gold) 45%, var(--line-strong));
  color: color-mix(in srgb, var(--ach-gold-ink) 60%, var(--ink-faint));
}
.achbadge--gold:not(.achbadge--unlocked) .achbadge__tiername { color: color-mix(in srgb, var(--ach-gold-ink) 70%, var(--ink-faint)); }
.achbadge--platinum:not(.achbadge--unlocked) .achbadge__icon {
  background: linear-gradient(135deg, color-mix(in srgb, var(--brand) 14%, var(--surface-sunk)), color-mix(in srgb, var(--c-berry) 14%, var(--surface-sunk)));
  border-color: color-mix(in srgb, var(--brand) 40%, var(--line-strong));
  color: color-mix(in srgb, var(--brand-ink) 55%, var(--ink-faint));
}
.achbadge--platinum:not(.achbadge--unlocked) .achbadge__tiername { color: color-mix(in srgb, var(--brand-ink) 65%, var(--ink-faint)); }

/* Milestones — the one-off badges carried over from the old set. Neutral
   brand colour when earned, no tier ladder. */
.achbadge--unlocked.achbadge--milestone { background: var(--brand-tint); }
.achbadge--unlocked.achbadge--milestone .achbadge__icon { background: var(--brand); color: #fff; border-color: transparent; }
.achbadge--unlocked.achbadge--milestone .achbadge__tiername { color: var(--brand-ink); }
.achtoast--milestone .achtoast__icon { background: var(--brand); color: #fff; }

/* Progress-page teaser card linking to the full page. */
.achteaser { display: block; text-decoration: none; color: inherit; transition: transform var(--dur-fast) var(--ease-spring), box-shadow var(--dur-fast); }
.achteaser:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }
.achteaser__top { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); margin-bottom: var(--s-2); }
.achteaser__top h3 { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-faint); margin: 0; }
.achteaser__top .badge { background: var(--brand-tint); color: var(--brand-ink); }

/* Unlock celebration — dropped in from the top, appended to <body> so it
   survives the navigation to the results page. */
.achtoast {
  position: fixed; left: 50%; top: var(--s-5); z-index: 90;
  display: flex; align-items: center; gap: var(--s-3);
  min-width: 280px; max-width: min(400px, calc(100vw - 32px));
  padding: var(--s-4) var(--s-5); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--line-strong); box-shadow: var(--shadow-2);
  transform: translate(-50%, -20px); opacity: 0; pointer-events: none;
  transition: transform var(--dur-mid) var(--ease-spring), opacity var(--dur-mid);
}
.achtoast.show { transform: translate(-50%, 0); opacity: 1; }
.achtoast__icon { flex: none; width: 48px; height: 48px; border-radius: var(--r-full); display: grid; place-items: center; background: var(--surface-sunk); color: var(--ink-soft); }
.achtoast__eyebrow { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-faint); margin: 0; }
.achtoast__name { font-family: var(--font-display); font-weight: 700; margin: 1px 0; }
.achtoast__desc { font-size: var(--fs-sm); color: var(--ink-soft); margin: 0; }
.achtoast--bronze .achtoast__icon { background: var(--ach-bronze); color: #fff; }
.achtoast--silver .achtoast__icon { background: var(--ach-silver); color: #fff; }
.achtoast--gold .achtoast__icon { background: var(--ach-gold); color: #fff; }
.achtoast--platinum .achtoast__icon { background: linear-gradient(135deg, var(--brand), var(--c-ocean) 55%, var(--c-berry)); color: #fff; }
.achtoast--gold { border-color: var(--ach-gold); }
.achtoast--platinum { border-color: var(--brand-bright); }

/* ---------- estimated grade ---------- */
.gradepill {
  display: grid; place-items: center; width: 26px; height: 26px;
  border-radius: var(--r-full); font-family: var(--font-display); font-weight: 700; font-size: 13px;
  background: var(--surface-sunk); color: var(--ink-soft); cursor: default;
}
.gradepill--low { background: var(--retry-tint); color: var(--retry-ink); }
.gradepill--high { background: var(--ok-tint); color: var(--ok-ink); }

.gradereveal {
  display: inline-block; margin: var(--s-2) auto var(--s-5); padding: var(--s-5) var(--s-6);
  min-width: 220px; border-radius: var(--r-lg); border: 1px solid var(--line);
  background: var(--surface-sunk);
  animation: pop-in var(--dur-slow) var(--ease-spring) 650ms both;
}
.gradereveal--low { background: var(--retry-tint); border-color: var(--retry); }
.gradereveal--high { background: var(--ok-tint); border-color: var(--ok); }
.gradereveal__eyebrow { display: block; font-size: 12px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-faint); }
.gradereveal__letter { font-family: var(--font-display); font-weight: 700; font-size: 4rem; line-height: 1.2; color: var(--ink); }
.gradereveal--low .gradereveal__letter { color: var(--retry-ink); }
.gradereveal--high .gradereveal__letter { color: var(--ok-ink); }
.gradereveal__compare { font-weight: 600; margin-top: var(--s-1); }
.gradereveal__compare.up { color: var(--ok-ink); }
.gradereveal__compare.down { color: var(--ink-soft); }
.gradereveal__caption { font-size: var(--fs-sm); color: var(--ink-faint); margin-top: 2px; }

/* the normed-score reveal, sibling of .gradereveal */
.gradereveal--hp .gradereveal__letter { font-variant-numeric: tabular-nums; }
.gradereveal--hp:not(.gradereveal--low):not(.gradereveal--high) {
  background: var(--brand-tint); border-color: var(--brand);
}

/* ---------- Högskoleprovet: figures, reading stimulus, KVA/NOG frames ---------- */
.question__figure {
  margin: 0 0 var(--s-4); text-align: center;
}
.question__figure img { max-width: 100%; border-radius: var(--r-sm); }
.question__figure figcaption { font-size: var(--fs-sm); color: var(--ink-faint); margin-top: var(--s-1); }
.question__figure--missing {
  display: flex; flex-direction: column; gap: 4px;
  border: 1px dashed var(--line-strong); border-radius: var(--r-md);
  padding: var(--s-3) var(--s-4); background: var(--surface-sunk); color: var(--ink-soft);
  font-size: var(--fs-sm);
}
.question__figure--missing b {
  display: block; text-transform: uppercase; letter-spacing: .05em; font-size: 11px;
  color: var(--ink-faint); margin-bottom: var(--s-1);
}
.question__stimulus {
  margin: 0 0 var(--s-4); padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line); border-left: 3px solid var(--brand);
  border-radius: var(--r-sm); background: var(--surface-sunk);
  max-height: 42vh; overflow: auto;
}
.question__stimulus-label {
  margin: 0 0 var(--s-2); font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--brand-ink); font-weight: 700;
}
.question__stimulus-body { font-size: var(--fs-sm); line-height: 1.6; color: var(--ink-soft); }
.question__stimulus-body br { content: ""; display: block; margin-bottom: .5em; }

.hp-kva {
  display: grid; grid-template-columns: 1fr auto 1fr; gap: 0;
  border: 1px solid var(--line-strong); border-radius: var(--r-md); overflow: hidden;
  margin: 0 0 var(--s-4);
}
.hp-kva__col { padding: var(--s-3) var(--s-4); background: var(--surface-sunk); }
.hp-kva__col h4 {
  margin: 0 0 var(--s-1); font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-faint); font-weight: 700;
}
.hp-kva__q { font-size: var(--fs-lg); color: var(--ink); }
.hp-kva__div { width: 1px; background: var(--line-strong); }
.hp-kva__given {
  grid-column: 1 / -1; border-top: 1px dashed var(--line-strong);
  padding: var(--s-2) var(--s-4); font-size: var(--fs-sm); color: var(--ink-soft); background: var(--surface);
}
@media (max-width: 480px) {
  .hp-kva { grid-template-columns: 1fr; }
  .hp-kva__div { width: auto; height: 1px; }
}

.hp-nog__stmts { display: flex; flex-direction: column; gap: var(--s-2); margin: 0 0 var(--s-4); }
.hp-nog__stmt {
  display: flex; gap: var(--s-3); padding: var(--s-2) var(--s-3);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm); background: var(--surface-sunk);
  font-size: var(--fs-sm); color: var(--ink-soft);
}
.hp-nog__stmt b { flex: none; color: var(--ink); }

/* #/hp dashboard */
.hp-dash { display: grid; gap: var(--s-4); }
.hp-dash > h1 { margin-bottom: 0; }
.hp-dash__when { display: flex; align-items: center; gap: 6px; font-weight: 600; flex-wrap: wrap; }
.hp-dash__prognosis { display: flex; align-items: baseline; gap: var(--s-5); flex-wrap: wrap; }
.hp-dash__big { font-family: var(--font-display); font-weight: 700; font-size: 3rem; color: var(--brand-ink); font-variant-numeric: tabular-nums; }
.hp-dash__split { font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.7; }
.hp-dash__split b { color: var(--ink); font-variant-numeric: tabular-nums; }

.hp-readiness { display: flex; flex-direction: column; gap: var(--s-2); }
.hp-readiness__row {
  display: grid; grid-template-columns: 48px 1fr 42px; gap: var(--s-3); align-items: center;
  text-decoration: none; color: inherit; padding: 4px 0;
}
.hp-readiness__row:hover .hp-readiness__k { color: var(--brand); }
.hp-readiness__k { font-weight: 700; font-size: var(--fs-sm); }
.hp-readiness__n { text-align: right; font-size: var(--fs-sm); color: var(--ink-faint); font-variant-numeric: tabular-nums; }

/* ---------- instant solve ---------- */
.solve-dropzone {
  display: flex; align-items: center; justify-content: center;
  min-height: 180px; border: 2px dashed var(--line-strong); border-radius: var(--r-lg);
  background: var(--surface-sunk); cursor: pointer; overflow: hidden;
  transition: transform var(--dur-fast) var(--ease-spring), border-color var(--dur-fast), background var(--dur-fast);
}
.solve-dropzone:hover { transform: translateY(-2px); border-color: var(--brand); background: var(--brand-tint); }
.solve-dropzone.has-image { border-style: solid; border-color: var(--line); background: var(--surface); padding: var(--s-3); }
.solve-dropzone__inner { display: flex; flex-direction: column; align-items: center; gap: var(--s-2); color: var(--ink-soft); text-align: center; padding: var(--s-5); }
.solve-dropzone__cta { font-family: var(--font-display); font-weight: 700; color: var(--ink); }
.solve-dropzone svg { color: var(--brand); }
.solve-dropzone img { max-width: 100%; max-height: 320px; display: block; border-radius: var(--r-md); object-fit: contain; }
.solve-result { display: flex; gap: var(--s-5); align-items: flex-start; flex-wrap: wrap; text-align: left; }
.solve-result__thumb { width: 120px; height: 120px; object-fit: cover; border-radius: var(--r-md); border: 1px solid var(--line); flex: none; }
.solve-restated { font-style: italic; color: var(--ink-soft); font-size: var(--fs-sm); margin: 0 0 var(--s-3); }
.solve-answer { padding: var(--s-4) var(--s-5); border-radius: var(--r-lg); border: 1px solid var(--ok); background: var(--ok-tint); }
.solve-answer__label { display: block; font-size: 12px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ok-ink); margin-bottom: 4px; }
.solve-answer__value { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-xl); color: var(--ink); }
.solve-steps { margin: 12px 0 0; padding-left: 22px; display: flex; flex-direction: column; gap: var(--s-2); }
.solve-steps li { padding-left: 4px; }
/* The method is collapsible — the answer is already shown, so seeing the
   working is opt-in (hide it and try to reconstruct it). */
.solve-method { margin-top: 20px; text-align: left; border-top: 1px solid var(--line); padding-top: var(--s-4); }
.solve-method > summary {
  cursor: pointer; list-style: none; font-family: var(--font-display); font-weight: 700;
  font-size: var(--fs-md); color: var(--ink); display: inline-flex; align-items: center; gap: 8px;
}
.solve-method > summary::-webkit-details-marker { display: none; }
.solve-method > summary::before { content: "▸"; font-size: 11px; color: var(--ink-faint); transition: transform var(--dur-fast); }
.solve-method[open] > summary::before { transform: rotate(90deg); }
/* Push toward practising, not just reading the answer. */
.solve-next { margin-top: 20px; padding: var(--s-4); border-radius: var(--r-md); background: var(--brand-tint); border: 1px solid color-mix(in srgb, var(--brand) 24%, transparent); text-align: left; }
.solve-next__lead { margin: 0 0 var(--s-3); font-weight: 600; color: var(--ink); }

/* ---------- calendar quick-add dialog ---------- */
.quickadd { max-width: 380px; }
.quickadd__types { display: flex; gap: var(--s-2); }
.quickadd__type {
  flex: 1; font: inherit; font-weight: 600; font-size: var(--fs-sm);
  padding: var(--s-3); border-radius: var(--r-md);
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink-soft);
  cursor: pointer; transition: background var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast);
}
.quickadd__type:hover { background: var(--surface-sunk); }
.quickadd__type[aria-pressed="true"] { background: var(--brand-tint); border-color: var(--brand); color: var(--brand-ink); }

/* ---------- friend leaderboard ---------- */
.lbrows { display: flex; flex-direction: column; gap: var(--s-2); }
.lbrow {
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
  padding: var(--s-3) var(--s-4); border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--line);
}
.lbrow--me { border-color: var(--brand); background: var(--brand-tint); }
/* Same gold/silver/bronze as the achievement badges — one ranked-tier
   visual language for the whole app. */
.lbrank {
  flex: none; width: 28px; height: 28px; border-radius: var(--r-full);
  display: grid; place-items: center; font-weight: 700; font-family: var(--font-display);
  background: var(--surface-sunk); color: var(--ink-soft); font-size: var(--fs-sm);
}
.lbrank--gold { background: var(--ach-gold); color: #fff; }
.lbrank--silver { background: var(--ach-silver); color: #fff; }
.lbrank--bronze { background: var(--ach-bronze); color: #fff; }
.lbrow__who { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.lbrow__handle { font-weight: 700; font-family: var(--font-display); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lbrow__stats { display: flex; align-items: center; gap: var(--s-4); flex: none; }
.lbrow__streak { display: inline-flex; align-items: center; gap: 4px; color: var(--retry-ink); font-weight: 700; font-size: var(--fs-sm); }
.lbrow__questions { font-weight: 700; font-size: var(--fs-sm); color: var(--ink-soft); white-space: nowrap; }
.lbcode {
  font-size: 22px; font-weight: 700; letter-spacing: .12em; font-family: ui-monospace, "SF Mono", Menlo, monospace;
  background: var(--surface-sunk); border: 1px dashed var(--line-strong); border-radius: var(--r-md);
  padding: var(--s-3); text-align: center; margin: var(--s-2) 0 var(--s-3);
}

/* ---------- share card ---------- */
.sharecard { text-align: center; position: relative; max-width: 380px; }
.sharecard__close { position: absolute; top: var(--s-2); right: var(--s-2); }
.sharecard__preview { width: 100%; border-radius: var(--r-md); margin: var(--s-3) 0; display: block; }
.sharecard__actions { display: flex; gap: var(--s-3); justify-content: center; flex-wrap: wrap; }
/* A fixed-dark pill regardless of theme, like .toast — a small "chip" of
   chrome rather than a themed control, so it reads the same on every badge. */
.achbadge__share {
  position: absolute; right: var(--s-3); bottom: var(--s-3);
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; border: none; border-radius: var(--r-full);
  background: #232330; color: #fff;
  font-family: var(--font-display); font-weight: 600; font-size: 12px;
  cursor: pointer; box-shadow: var(--shadow-1);
  transition: transform var(--dur-fast) var(--ease-spring), background var(--dur-fast);
}
.achbadge__share svg { flex: none; }
.achbadge__share:hover { transform: translateY(-1px); background: #000; }

@media print {
  .topbar, .hintfab, [data-noprint], .toast, .savebar, .achtoast, .popover, .sharecard-backdrop { display: none !important; }
  body { background: #fff; color: #000; }
  .content { max-width: none; padding: 0; }
  .psheet__lines { background: none; height: 60px; border-bottom: 1px solid #999; }
  a[href]::after { content: ""; }
}
