/* ============================================================
   A-Level Study Help — the whole site's look, in one file.

   Direction "Marker": white paper, black ink, one highlighter.
   Ticking something off is a marker sweep, and it's the same
   gesture whether it's a past paper, a question or a card.

   Replaces the old assets/style.css and flashcards' app.css.
   Both of those defined header.site, nav.site, .chips, .btn,
   .search, .status and .header-tools differently — everything
   here is one definition shared by every page.
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Familjen+Grotesk:wght@500;600;700&family=Public+Sans:wght@400;500;600;700&display=swap');

/* ---------- tokens ---------- */
:root {
  --paper: #FFFFFF;
  --paper-2: #F7F8FA;
  --ink: #14171A;
  --soft: #5F6670;
  --faint: #9AA1AB;
  --rule: #E4E7EB;
  --rule-strong: #C6CBD2;

  --mark: #D8F34E;          /* the highlighter */
  --mark-deep: #A9C400;     /* its edge, for contrast on light */
  --mark-ink: #3D4A00;      /* text sitting on the highlighter */

  --yes: #0E8C6B;
  --yes-soft: #E4F5EE;
  --no: #C93A3F;
  --no-soft: #FBE7E8;

  --econ: #0F8A7E;
  --fren: #E5624A;
  --geog: #4457C7;

  --shadow-1: 0 1px 2px rgba(20, 23, 26, .05);
  --shadow-2: 0 2px 8px rgba(20, 23, 26, .06), 0 18px 34px -22px rgba(20, 23, 26, .45);

  --display: "Familjen Grotesk", system-ui, sans-serif;
  --body: "Public Sans", system-ui, -apple-system, "Segoe UI", sans-serif;

  --header-h: 56px;
  --tabs-h: 54px;   /* two lines: group label above the links */
  --wrap: 940px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #14161A;
    --paper-2: #1C1F25;
    --ink: #ECEEF2;
    --soft: #A4ACB8;
    --faint: #79808C;
    --rule: #292D34;
    --rule-strong: #3A3F48;

    --mark: #C7E635;
    --mark-deep: #C7E635;
    --mark-ink: #1A2000;

    --yes: #3FCB9E;
    --yes-soft: #102E26;
    --no: #FF7A7F;
    --no-soft: #33191B;

    --econ: #35C2B1;
    --fren: #FF8A73;
    --geog: #8296FF;

    --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-2: 0 2px 8px rgba(0, 0, 0, .35), 0 18px 34px -22px rgba(0, 0, 0, .8);
  }
}

/* the manual switch (theme.js) — same values, forced on */
:root[data-theme="dark"] {
  --paper: #14161A;
  --paper-2: #1C1F25;
  --ink: #ECEEF2;
  --soft: #A4ACB8;
  --faint: #79808C;
  --rule: #292D34;
  --rule-strong: #3A3F48;
  --mark: #C7E635;
  --mark-deep: #C7E635;
  --mark-ink: #1A2000;
  --yes: #3FCB9E;
  --yes-soft: #102E26;
  --no: #FF7A7F;
  --no-soft: #33191B;
  --econ: #35C2B1;
  --fren: #FF8A73;
  --geog: #8296FF;
  --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-2: 0 2px 8px rgba(0, 0, 0, .35), 0 18px 34px -22px rgba(0, 0, 0, .8);
}

*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-padding-top: calc(var(--header-h) + var(--tabs-h) + 12px);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.5;
}

/* Everything a page renders lives inside this, so the phone gets sane
   gutters and the desktop gets a measure that doesn't run away. */
main {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 20px 18px 64px;
}

a { color: inherit; }

:focus-visible {
  outline: 2.5px solid var(--mark-deep);
  outline-offset: 2px;
  border-radius: 3px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}

/* ---------- header ---------- */
header.site {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 12px;
  height: var(--header-h);
  padding: 0 18px;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}

.wordmark {
  font-family: var(--display);
  font-weight: 700;
  font-size: 16.5px;
  letter-spacing: -0.025em;
  line-height: 1;
  text-decoration: none;
  color: var(--ink);
  margin-right: auto;
  white-space: nowrap;
}
/* The highlighter sweep. box-shadow rather than padding so the sweep
   hugs the text without shifting the baseline or the layout. */
.wordmark i {
  font-style: normal;
  background: var(--mark);
  box-shadow: 0 0 0 2.5px var(--mark);
  border-radius: 2px;
  color: var(--mark-ink);
}

.header-tools {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: none;
}

.tool-btn {
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--soft);
  white-space: nowrap;
}
.tool-btn:hover { background: var(--paper-2); color: var(--ink); }

.avatar {
  width: 31px;
  height: 31px;
  border-radius: 999px;
  flex: none;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--display);
  font-weight: 700;
  font-size: 12px;
  display: grid;
  place-items: center;
  text-decoration: none;
}
.avatar.out {
  background: transparent;
  color: var(--soft);
  border: 1.5px solid var(--rule-strong);
}
.avatar svg { display: block; }
.avatar.out:hover { color: var(--ink); border-color: var(--ink); }

/* ---------- nav ---------- */
/* Ten destinations won't fit a row on a phone, so it scrolls sideways
   rather than wrapping to two lines or hiding behind a hamburger —
   the current section is always visible, and the rest are one swipe. */
nav.site {
  position: sticky;
  top: var(--header-h);
  z-index: 39;
  display: flex;
  align-items: stretch;
  gap: 0;
  padding: 6px 18px 0;
  height: var(--tabs-h);
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
nav.site::-webkit-scrollbar { display: none; }

/* Two groups in one scrolling bar. The label above each set does the
   separating, so the flashcards read as a section of this site rather than
   a separate thing bolted onto the end of a long row. */
.nav-group {
  flex: none;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 1px;
  padding-bottom: 2px;
}
.nav-group + .nav-group {
  margin-left: 18px;
  padding-left: 18px;
  border-left: 1px solid var(--rule);
}
.nav-group-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
  line-height: 1;
  padding-left: 1px;
}
.nav-list {
  display: flex;
  gap: 16px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav-list li { display: flex; }

nav.site a {
  flex: none;
  display: flex;
  align-items: flex-end;
  padding: 2px 0 4px;
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
  color: var(--faint);
  border-bottom: 2.5px solid transparent;
  margin-bottom: -3px;
}
nav.site a:hover { color: var(--ink); }
nav.site a[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
  border-bottom-color: var(--ink);
}
/* the group holding the current page gets its label picked out too */
.nav-group.on .nav-group-label { color: var(--ink); }

@media (min-width: 720px) {
  header.site, nav.site { padding-left: max(18px, calc((100vw - var(--wrap)) / 2)); }
  header.site { padding-right: max(18px, calc((100vw - var(--wrap)) / 2)); }
}

/* ---------- countdown banner ---------- */
.announce {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;   /* centred across the full width of the bar */
  gap: 10px;
  padding: 11px 18px;
  background: var(--mark);
  color: var(--mark-ink);
  font-size: 13px;
  font-weight: 500;
  text-align: center;
}
.announce b {
  font-family: var(--display);
  font-size: 22px;
  letter-spacing: -0.03em;
  line-height: 1;
  flex: none;
}
.announce-text { line-height: 1.35; }
.announce-close {
  position: absolute;
  right: 10px;
  font: inherit;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 6px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--mark-ink);
  opacity: .6;
  flex: none;
}
.announce-close:hover { opacity: 1; background: rgba(0, 0, 0, .07); }

/* ---------- headings and text ---------- */
h1 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(26px, 6vw, 34px);
  letter-spacing: -0.03em;
  line-height: 1.1;
  margin: 0 0 6px;
}
h2 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 19px;
  letter-spacing: -0.02em;
  margin: 30px 0 10px;
}
h3 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 15.5px;
  letter-spacing: -0.015em;
  margin: 0 0 4px;
}

.lede, .sub {
  margin: 0 0 18px;
  font-size: 14.5px;
  color: var(--soft);
  line-height: 1.55;
}
.lede b, .sub b { color: var(--ink); font-weight: 600; }

.eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 9px;
}

.status, .note, .more-note {
  font-size: 13px;
  color: var(--soft);
  line-height: 1.55;
  margin: 10px 0;
}

/* ---------- chips ---------- */
.chips {
  display: flex;
  gap: 7px;
  flex-wrap: wrap;
  margin: 0 0 22px;
}
.chip {
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  padding: 8px 13px;
  border-radius: 999px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  color: var(--soft);
  white-space: nowrap;
}
.chip:hover { border-color: var(--ink); color: var(--ink); }
.chip.on {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
  font-weight: 600;
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  padding: 11px 16px;
  border-radius: 10px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.btn:hover { border-color: var(--ink); }
.btn.primary {
  background: var(--mark);
  border-color: var(--mark);
  color: var(--mark-ink);
}
.btn.primary:hover { background: var(--mark-deep); border-color: var(--mark-deep); }
.btn.solid {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}
.btn[disabled] { opacity: .45; cursor: not-allowed; }

/* ---------- the tick ---------- */
/* One control, used for papers, questions and anything else that can be
   marked off. The sweep of highlighter is the whole point. */
.tick {
  width: 23px;
  height: 23px;
  flex: none;
  border-radius: 6px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  display: grid;
  place-items: center;
  cursor: pointer;
  padding: 0;
  transition: background .12s ease, border-color .12s ease;
}
.tick svg { display: block; opacity: 0; transition: opacity .12s ease; }
.tick .tick-mark { stroke: var(--mark-ink); }
.tick.on { background: var(--mark); border-color: var(--mark-deep); }
.tick.on svg { opacity: 1; }
.tick:hover { border-color: var(--ink); }

/* ---------- rows ---------- */
.row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 0;
  border-bottom: 1px solid var(--rule);
}
.row .what { flex: 1; min-width: 0; }
.row .what b {
  display: block;
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.3;
}
.row .what small {
  display: block;
  font-size: 12px;
  color: var(--faint);
  line-height: 1.4;
}
.row.done .what b { color: var(--soft); }
.row .go { font-size: 18px; color: var(--rule-strong); flex: none; }

/* ---------- progress bar ---------- */
.bar {
  height: 9px;
  border-radius: 999px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  overflow: hidden;
}
.bar i {
  display: block;
  height: 100%;
  background: var(--mark);
  border-radius: 999px;
}
.bar-note {
  display: flex;
  justify-content: space-between;
  margin-top: 7px;
  font-size: 11.5px;
  color: var(--faint);
  font-weight: 500;
}

/* ---------- panels ---------- */
.panel {
  border: 1.5px solid var(--rule);
  border-radius: 14px;
  padding: 15px;
  background: var(--paper);
}
.panel + .panel { margin-top: 10px; }

/* ============================================================
   Past-paper matrix — the classes app.js emits
   ============================================================ */
.level-head {
  font-family: var(--display);
  font-weight: 700;
  font-size: 20px;
  letter-spacing: -0.02em;
  margin: 30px 0 4px;
}
.level-head:first-child { margin-top: 6px; }

.pp-years { display: grid; gap: 12px; margin-top: 14px; }

.pp-year {
  border: 1.5px solid var(--rule);
  border-radius: 14px;
  overflow: hidden;
}
.pp-year-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  padding: 11px 14px;
  background: var(--paper-2);
  border-bottom: 1px solid var(--rule);
  font-family: var(--display);
  font-weight: 600;
  font-size: 14.5px;
  letter-spacing: -0.01em;
}

.pp-gb, .pp-gb-none {
  font-family: var(--body);
  font-size: 12px;
  font-weight: 500;
  text-decoration: none;
  color: var(--soft);
  white-space: nowrap;
}
.pp-gb:hover { color: var(--ink); }
.pp-gb-calc {
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 5px 9px;
  border-radius: 999px;
  border: 1.5px solid var(--mark-deep);
  background: var(--mark);
  color: var(--mark-ink);
}
.pp-gb-none { color: var(--faint); }

.pp-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--rule);
}
.pp-row:last-child { border-bottom: 0; }

.pp-name {
  flex: none;
  width: 84px;
  font-size: 13.5px;
  font-weight: 600;
  padding-top: 7px;
  line-height: 1.3;
}
.pp-btns { display: flex; flex-wrap: wrap; gap: 6px; flex: 1; min-width: 0; }

.pp-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  padding: 8px 11px;
  border-radius: 8px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  color: var(--soft);
  text-decoration: none;
  white-space: nowrap;
}
.pp-btn:hover { border-color: var(--ink); color: var(--ink); }
/* The question paper is the thing you actually came for. */
.pp-btn.qp {
  background: var(--mark);
  border-color: var(--mark);
  color: var(--mark-ink);
  font-weight: 600;
}
.pp-btn.qp:hover { background: var(--mark-deep); border-color: var(--mark-deep); }
.pp-btn.extra { font-size: 12px; color: var(--faint); border-style: dashed; }

.pp-menu { position: relative; display: inline-flex; }
.pp-menu-btn .caret { color: var(--faint); font-weight: 600; }
.pp-menu-list {
  position: absolute;
  top: calc(100% + 5px);
  left: 0;
  z-index: 30;
  min-width: 190px;
  display: flex;
  flex-direction: column;
  padding: 5px;
  border-radius: 10px;
  border: 1.5px solid var(--rule);
  background: var(--paper);
  box-shadow: var(--shadow-2);
}
.pp-menu-list[hidden] { display: none; }
.pp-menu-list a {
  padding: 8px 10px;
  border-radius: 7px;
  font-size: 13px;
  text-decoration: none;
  color: var(--ink);
}
.pp-menu-list a:hover { background: var(--paper-2); }

@media (max-width: 560px) {
  .pp-row { flex-direction: column; gap: 7px; }
  .pp-name { width: auto; padding-top: 0; font-size: 12.5px; color: var(--soft); }
}

/* ---------- footer ---------- */
footer.site {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 26px 18px 44px;
  border-top: 1px solid var(--rule);
  font-size: 12.5px;
  color: var(--faint);
  line-height: 1.9;
}
footer.site a, .link-btn {
  color: var(--soft);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--rule-strong);
}
footer.site a:hover, .link-btn:hover { color: var(--ink); }
.link-btn {
  font: inherit;
  cursor: pointer;
  padding: 0;
  border: 0;
  background: none;
}

/* ---------- modal shell (search, grade calculator, sync) ---------- */
.modal-back {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: start center;
  padding: 8vh 16px 16px;
  background: rgba(20, 23, 26, .45);
  backdrop-filter: blur(2px);
}
.modal-back[hidden] { display: none; }
.modal {
  width: 100%;
  max-width: 560px;
  max-height: 82vh;
  overflow-y: auto;
  border-radius: 16px;
  border: 1.5px solid var(--rule);
  background: var(--paper);
  box-shadow: var(--shadow-2);
  padding: 18px;
}
.modal h2 { margin-top: 0; }

.search {
  width: 100%;
  font: inherit;
  font-size: 15px;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1.5px solid var(--rule-strong);
  background: var(--paper);
  color: var(--ink);
}
.search::placeholder { color: var(--faint); }
.search:focus { border-color: var(--ink); outline: none; }

/* ---------- the stale-file bar (from flashcards' build guard) ---------- */
.stale-bar {
  padding: 10px 18px;
  background: var(--no-soft);
  color: var(--no);
  font-size: 13px;
  font-weight: 600;
  text-align: center;
}

/* ---------- skip link ---------- */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 10px 14px;
  background: var(--mark);
  color: var(--mark-ink);
  font-weight: 600;
  border-radius: 0 0 8px 0;
}
.skip:focus { left: 0; }

/* ============================================================
   Search overlay — the classes search.js emits
   ============================================================ */
body.search-open, body.gb-lock { overflow: hidden; }

.icon-btn {
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 11px;
  border-radius: 8px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  color: var(--soft);
  white-space: nowrap;
}
.icon-btn:hover { border-color: var(--ink); color: var(--ink); }
.icon-btn .icon-label { display: none; }
@media (min-width: 560px) { .icon-btn .icon-label { display: inline; } }

.search-overlay {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 7vh 14px 14px;
  background: rgba(20, 23, 26, .45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.search-overlay[hidden] { display: none; }

.search-modal {
  width: 100%;
  max-width: 620px;
  max-height: 84vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 16px;
  border: 1.5px solid var(--rule);
  background: var(--paper);
  box-shadow: var(--shadow-2);
}

.search-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 10px 10px 14px;
  border-bottom: 1.5px solid var(--rule);
  flex: none;
}
.search-input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 16px;               /* 16px or iOS zooms the page on focus */
  padding: 9px 2px;
  border: 0;
  background: transparent;
  color: var(--ink);
  -webkit-appearance: none;
  appearance: none;
}
.search-input:focus { outline: none; }
.search-input::placeholder { color: var(--faint); }
.search-input::-webkit-search-cancel-button { -webkit-appearance: none; }

.search-close {
  font: inherit;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  flex: none;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  border: 0;
  background: transparent;
  color: var(--faint);
}
.search-close:hover { background: var(--paper-2); color: var(--ink); }

.search-body {
  overflow-y: auto;
  padding: 6px;
  -webkit-overflow-scrolling: touch;
}
.search-hint, .search-empty {
  margin: 0;
  padding: 22px 14px;
  text-align: center;
  font-size: 13.5px;
  color: var(--faint);
  line-height: 1.6;
}

.hit {
  display: block;
  padding: 10px 12px;
  border-radius: 10px;
  text-decoration: none;
  color: var(--ink);
}
.hit:hover, .hit:focus-visible { background: var(--paper-2); }
.hit .meta {
  display: block;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 2px;
}
/* the two hits people are usually hunting for get a colour */
.hit .meta.kind-qp { color: var(--mark-deep); }
.hit .meta.kind-ms { color: var(--geog); }
.hit .text {
  display: block;
  font-size: 14px;
  line-height: 1.4;
}
/* search.js wraps matched terms in <mark> — same highlighter as everywhere */
.hit mark, main mark {
  background: var(--mark);
  color: var(--mark-ink);
  border-radius: 2px;
  padding: 0 1px;
}

/* ============================================================
   Grade calculator — the classes grade-calc.js emits
   ============================================================ */
.gb-overlay {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 6vh 14px 14px;
  background: rgba(20, 23, 26, .45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.gb-overlay[hidden] { display: none; }

.gb-modal {
  position: relative;
  width: 100%;
  max-width: 460px;
  max-height: 86vh;
  overflow-y: auto;
  padding: 20px 18px 18px;
  border-radius: 16px;
  border: 1.5px solid var(--rule);
  background: var(--paper);
  box-shadow: var(--shadow-2);
  -webkit-overflow-scrolling: touch;
}
.gb-modal:focus { outline: none; }

.gb-close {
  position: absolute;
  top: 11px;
  right: 11px;
  font: inherit;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  border: 0;
  background: transparent;
  color: var(--faint);
}
.gb-close:hover { background: var(--paper-2); color: var(--ink); }

.gb-modal h3 {
  font-family: var(--display);
  font-size: 18px;
  letter-spacing: -0.02em;
  margin: 0 34px 3px 0;
}
.gb-sub {
  margin: 0 0 16px;
  font-size: 13px;
  color: var(--soft);
  line-height: 1.5;
}

.gb-papers { display: grid; gap: 8px; }
.gb-paper-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 10px;
  border: 1.5px solid var(--rule);
  cursor: pointer;
}
.gb-paper-row:focus-within { border-color: var(--ink); }
.gb-paper-name {
  flex: 1;
  min-width: 0;
  font-size: 14px;
  font-weight: 500;
}
.gb-input {
  flex: none;
  width: 84px;
  font: inherit;
  font-size: 16px;               /* 16px, again, to stop iOS zooming */
  font-weight: 600;
  text-align: center;
  padding: 8px 6px;
  border-radius: 8px;
  border: 1.5px solid var(--rule-strong);
  background: var(--paper);
  color: var(--ink);
  -webkit-appearance: none;
  appearance: none;
}
.gb-input::-webkit-outer-spin-button,
.gb-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.gb-input { -moz-appearance: textfield; }
.gb-input:focus { border-color: var(--ink); outline: none; }

.gb-result {
  margin-top: 16px;
  padding: 14px;
  border-radius: 12px;
  background: var(--paper-2);
  border: 1.5px solid var(--rule);
}
.gb-total-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 13px;
  color: var(--soft);
  padding-bottom: 11px;
  margin-bottom: 11px;
  border-bottom: 1px solid var(--rule);
}
.gb-total-val {
  font-family: var(--display);
  font-size: 19px;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.gb-grade-row { display: flex; align-items: center; gap: 12px; }

/* The grade is the answer to the question — everything else on the panel
   is working out, so this is the one thing that gets the highlighter. */
.gb-grade-badge {
  flex: none;
  min-width: 52px;
  height: 52px;
  padding: 0 12px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  background: var(--mark);
  color: var(--mark-ink);
  font-family: var(--display);
  font-weight: 700;
  font-size: 26px;
  letter-spacing: -0.03em;
}
.gb-grade-badge.gb-u {
  background: var(--no-soft);
  color: var(--no);
}
.gb-next {
  font-size: 13px;
  color: var(--soft);
  line-height: 1.45;
}
.gb-next b { color: var(--ink); font-weight: 600; }

.gb-excluded, .gb-source {
  margin: 12px 0 0;
  font-size: 12px;
  color: var(--faint);
  line-height: 1.5;
}
.gb-excluded[hidden] { display: none; }
.gb-source a { color: var(--soft); }

@media (max-width: 420px) {
  .gb-paper-row { gap: 8px; padding: 8px 10px; }
  .gb-input { width: 72px; }
}

/* ============================================================
   Question bank and glossary
   The densest pages on the site, so this is where the design
   has to stay out of the way: quiet cards, one accent, and the
   tick doing the talking.
   ============================================================ */
/* questions.js drops a search box, several selects and a few buttons into
   #filters as bare siblings, with no wrapper to lay them out — so without
   this they sit flush against each other with no gap at all. */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  align-items: center;
  margin-bottom: 18px;
}
.filters .qb-search { flex: 1 1 200px; }
.filters .qb-pills { display: flex; gap: 6px; }
/* the extra selects live in a panel that spans the whole row when opened */
.filters .qb-tools { flex-basis: 100%; margin: 0; }

.qb-tools {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  align-items: center;
  margin-bottom: 12px;
}
.qb-search {
  flex: 1 1 220px;
  min-width: 0;
  font: inherit;
  font-size: 16px;                 /* 16px stops iOS zooming on focus */
  padding: 10px 13px;
  border-radius: 10px;
  border: 1.5px solid var(--rule-strong);
  background: var(--paper);
  color: var(--ink);
  -webkit-appearance: none;
  appearance: none;
}
.qb-search::-webkit-search-cancel-button { -webkit-appearance: none; }
.qb-search:focus { border-color: var(--ink); outline: none; }
.qb-search::placeholder { color: var(--faint); }

.qb-select {
  font: inherit;
  font-size: 14px;
  padding: 9px 30px 9px 11px;
  border-radius: 9px;
  border: 1.5px solid var(--rule-strong);
  background-color: var(--paper);
  color: var(--ink);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%239AA1AB' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
}
.qb-select:focus { border-color: var(--ink); outline: none; }

.qb-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.qb-count { cursor: default; border-style: dashed; }
.qb-count:hover { border-color: var(--rule-strong); color: var(--soft); }

/* The panel collapses by animating grid-template-rows from 0fr to 1fr — the
   trick that lets an auto-height element slide open. I'd previously only
   styled .qb-more-inner[hidden], which nothing ever sets, so every filter
   was on screen all the time and the toggle appeared dead. */
.qb-more {
  flex-basis: 100%;
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .25s ease;
  margin-bottom: 0;
}
.qb-more.open { grid-template-rows: 1fr; }
.qb-more-inner {
  overflow: hidden;
  min-height: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}
/* padding only once open, or the collapsed panel keeps its own height */
.qb-more.open .qb-more-inner {
  padding: 13px;
  margin-top: 8px;
  border-radius: 12px;
  border: 1.5px solid var(--rule);
  background: var(--paper-2);
}
.qb-more-toggle { border-style: dashed; }
.qb-more-toggle .qb-more-caret {
  display: inline-block;
  font-weight: 700;
  transition: transform .25s ease;
}
@media (prefers-reduced-motion: reduce) {
  .qb-more, .qb-more-caret { transition: none; }
}

/* ---------- a question card ---------- */
.qcard {
  border: 1.5px solid var(--rule);
  border-radius: 14px;
  padding: 14px;
  margin-bottom: 10px;
  background: var(--paper);
}
/* Done fades rather than hides: you still want to find it again, but it
   should stop competing for attention with what's left. */
.qcard.is-done { opacity: .58; }
.qcard.is-done:hover, .qcard.is-done:focus-within { opacity: 1; }

.qcard-head {
  display: flex;
  align-items: baseline;
  gap: 9px;
  flex-wrap: wrap;
  margin-bottom: 7px;
}
.qnum {
  font-family: var(--display);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.02em;
  flex: none;
}
.qmeta { font-size: 11.5px; color: var(--faint); font-weight: 500; }
.qmarks {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--soft);
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  flex: none;
}
.subtopic {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
}

.qtext { font-size: 14.5px; line-height: 1.55; margin: 0 0 8px; }
.qtext-fr { font-style: italic; }
.q-bullets { margin: 6px 0 8px; padding-left: 20px; font-size: 14px; line-height: 1.55; }
.q-bullets li { margin-bottom: 3px; }
.qnote { font-size: 12.5px; color: var(--soft); margin: 6px 0 0; line-height: 1.5; }
.q-heading {
  font-family: var(--display);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.015em;
  margin: 16px 0 8px;
}
.q-questions { margin-top: 10px; }
.q-cap { font-size: 11.5px; color: var(--faint); margin: 5px 0 0; }
/* .q-img is a <figure> wrapping the image, not the image itself, and
   .q-img-off is the "Load this image" button that stands in for it —
   styling either as the other left speaking-card images unbounded. */
.q-img {
  margin: 11px 0 0;
  padding: 0;
}
.q-img img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 62vh;
  object-fit: contain;
  border-radius: 10px;
  border: 1px solid var(--rule);
  background: var(--paper-2);
}
.q-img figcaption {
  margin-top: 6px;
  font-size: 12px;
  color: var(--faint);
  line-height: 1.45;
}
.q-img-off {
  display: block;
  width: 100%;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  margin-top: 11px;
  padding: 22px 14px;
  border-radius: 10px;
  border: 1.5px dashed var(--rule-strong);
  background: var(--paper-2);
  color: var(--soft);
}
.q-img-off:hover { border-color: var(--ink); color: var(--ink); }

.qlinks { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }

/* ---------- the tick on a question card ---------- */
/* Same marker sweep as the past-paper rows. It's a real checkbox for
   keyboard and screen-reader users; the box is drawn on the label. */
.qtools {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 11px;
  padding-top: 11px;
  border-top: 1px solid var(--rule);
}
.q-done {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  color: var(--soft);
  user-select: none;
}
.q-done input {
  appearance: none;
  -webkit-appearance: none;
  width: 22px;
  height: 22px;
  margin: 0;
  flex: none;
  border-radius: 6px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  cursor: pointer;
  position: relative;
  transition: background .12s ease, border-color .12s ease;
}
.q-done input::after {
  content: "";
  position: absolute;
  left: 6px;
  top: 2px;
  width: 6px;
  height: 11px;
  border: solid var(--mark-ink);
  border-width: 0 2.2px 2.2px 0;
  transform: rotate(45deg) scale(0);
  transition: transform .12s ease;
}
.q-done input:checked { background: var(--mark); border-color: var(--mark-deep); }
.q-done input:checked::after { transform: rotate(45deg) scale(1); }
.q-done input:focus-visible { outline: 2.5px solid var(--mark-deep); outline-offset: 2px; }
.q-done input:checked + span { color: var(--ink); }

.q-copy {
  font: inherit;
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  color: var(--soft);
  margin-left: auto;
}
.q-copy:hover { border-color: var(--ink); color: var(--ink); }
.q-copy.ok { background: var(--mark); border-color: var(--mark); color: var(--mark-ink); }

.pp-menu-note {
  display: block;
  padding: 7px 10px 3px;
  font-size: 11px;
  color: var(--faint);
}
.cmd {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  padding: 1px 5px;
  border-radius: 5px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
}
.stamp {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ============================================================
   Timed practice
   Two states with opposite jobs: the setup wants to be calm and
   readable, the running clock wants to be unmissable and then
   get out of the way so the paper has the screen.
   ============================================================ */
.pr-card {
  border: 1.5px solid var(--rule);
  border-radius: 16px;
  padding: 18px;
  background: var(--paper);
}
.pr-card-done { text-align: left; }

.pr-step {
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: var(--display);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.015em;
  margin: 22px 0 10px;
}
.pr-step:first-child { margin-top: 0; }
/* Numbered because sitting a paper genuinely is a sequence — pick, time,
   start — not because numbers look tidy. */
.pr-num {
  width: 23px;
  height: 23px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  font-size: 12px;
  font-weight: 700;
}

.pr-fields {
  display: grid;
  gap: 9px;
  grid-template-columns: 1fr;
  margin-bottom: 12px;
}
@media (min-width: 560px) { .pr-fields { grid-template-columns: repeat(3, 1fr); } }
.pr-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.pr-field > span {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
}
.pr-field .qb-select { width: 100%; }

.pr-extras, .pr-history, .pr-stat {
  margin: 8px 0 0;
  font-size: 12.5px;
  color: var(--soft);
  line-height: 1.5;
}
.pr-history:empty, .pr-extras:empty, .pr-stat:empty { display: none; }

.pr-custom {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--soft);
}
.pr-custom input {
  width: 62px;
  font: inherit;
  font-size: 16px;
  text-align: center;
  padding: 7px 4px;
  border-radius: 8px;
  border: 1.5px solid var(--rule-strong);
  background: var(--paper);
  color: var(--ink);
  -webkit-appearance: none;
  appearance: none;
}
.pr-custom input::-webkit-outer-spin-button,
.pr-custom input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pr-custom input { -moz-appearance: textfield; }

.pr-start { margin-top: 14px; font-size: 15px; padding: 12px 18px; }

/* ---------- the running clock ---------- */
.pr-bar {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 14px 12px;
  background: var(--paper);
  border-bottom: 1.5px solid var(--rule);
}
.pr-clock {
  font-family: var(--display);
  font-weight: 700;
  font-size: 27px;
  letter-spacing: -0.03em;
  line-height: 1;
  flex: none;
  font-variant-numeric: tabular-nums;
}
/* under five minutes */
.pr-clock.low { color: var(--no); }
.pr-what {
  font-size: 12.5px;
  color: var(--soft);
  flex: 1 1 auto;
  min-width: 0;
  line-height: 1.35;
}
.pr-controls { display: flex; gap: 6px; flex-wrap: wrap; flex: none; }
.pr-controls .chip { text-decoration: none; }

.pr-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: var(--rule);
}
.pr-progress-fill {
  display: block;
  height: 100%;
  width: 0;
  background: var(--mark-deep);
  transition: width 1s linear;
}

.pr-frame-wrap {
  display: grid;
  gap: 10px;
  grid-template-columns: 1fr;
  position: relative;
  margin-top: 12px;
}
.pr-frame-wrap.split { grid-template-columns: 1fr; }
@media (min-width: 900px) {
  .pr-frame-wrap.split { grid-template-columns: 1fr 1fr; }
}
.pr-pane {
  position: relative;
  border: 1.5px solid var(--rule);
  border-radius: 12px;
  overflow: hidden;
  background: var(--paper-2);
}
.pr-pane-tag {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 2;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: 4px 8px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
}
.pr-pane iframe {
  display: block;
  width: 100%;
  height: 72vh;
  border: 0;
  background: #fff;
}

.pr-cover {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: grid;
  place-items: center;
  text-align: center;
  padding: 20px;
  border-radius: 12px;
  background: var(--paper);
}
.pr-cover[hidden] { display: none; }
.pr-cover-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 25px;
  letter-spacing: -0.03em;
  margin: 0 0 5px;
}
.pr-cover-sub { margin: 0 0 16px; font-size: 13.5px; color: var(--soft); }

.pr-review {
  margin-top: 14px;
  padding: 12px 13px;
  border-radius: 11px;
  border: 1.5px solid var(--rule);
  background: var(--paper-2);
}
.pr-review label {
  display: flex;
  align-items: center;
  gap: 9px;
  cursor: pointer;
  font-size: 13.5px;
  font-weight: 500;
}
.pr-review input {
  appearance: none;
  -webkit-appearance: none;
  width: 21px;
  height: 21px;
  margin: 0;
  flex: none;
  border-radius: 6px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  cursor: pointer;
  position: relative;
}
.pr-review input::after {
  content: "";
  position: absolute;
  left: 6px;
  top: 2px;
  width: 5px;
  height: 10px;
  border: solid var(--mark-ink);
  border-width: 0 2.2px 2.2px 0;
  transform: rotate(45deg) scale(0);
  transition: transform .12s ease;
}
.pr-review input:checked { background: var(--mark); border-color: var(--mark-deep); }
.pr-review input:checked::after { transform: rotate(45deg) scale(1); }

@media (max-width: 560px) {
  .pr-bar { gap: 8px; padding: 9px 12px 11px; }
  .pr-clock { font-size: 23px; }
  .pr-what { flex-basis: 100%; order: 3; }
  .pr-pane iframe { height: 64vh; }
}

/* ============================================================
   Grade boundaries page
   ============================================================ */
.chip-group { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 10px; }
.gbp-year-wrap { margin-top: 18px; }
.gbp-help { font-size: 13px; color: var(--soft); line-height: 1.55; margin: 0 0 16px; }

.gbp-cards { display: grid; gap: 12px; }
.gbp-card {
  border: 1.5px solid var(--rule);
  border-radius: 14px;
  overflow: hidden;
}
.gbp-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  padding: 11px 14px;
  background: var(--paper-2);
  border-bottom: 1px solid var(--rule);
  font-family: var(--display);
  font-weight: 600;
  font-size: 14.5px;
  letter-spacing: -0.01em;
}
.gbp-card-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.gbp-overall {
  padding: 11px 14px;
  font-size: 13px;
  color: var(--soft);
  border-bottom: 1px solid var(--rule);
}
.gbp-overall b { color: var(--ink); font-weight: 600; }

.gbp-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.gbp-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.gbp-table th, .gbp-table td {
  padding: 8px 11px;
  text-align: right;
  border-bottom: 1px solid var(--rule);
  white-space: nowrap;
}
.gbp-table th:first-child, .gbp-table td:first-child {
  text-align: left;
  font-weight: 600;
  position: sticky;
  left: 0;
  background: var(--paper);
}
.gbp-table thead th {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
  background: var(--paper);
}
.gbp-table tbody tr:last-child td { border-bottom: 0; }

.gbp-trend { font-size: 12px; color: var(--faint); padding: 10px 14px; line-height: 1.5; }
.gbp-excluded { font-size: 12px; color: var(--faint); padding: 0 14px 11px; line-height: 1.5; }

.q { font-weight: 600; font-size: 14.5px; margin: 16px 0 4px; }
.q-text { font-size: 14px; color: var(--soft); line-height: 1.6; margin: 0 0 12px; }

/* ============================================================
   Resources page — the book grid
   ============================================================ */
.book .cover {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 10px;
  border: 1.5px solid var(--rule);
  background: var(--paper-2);
}
.book .by { font-size: 11.5px; color: var(--faint); line-height: 1.4; }
.book .links { display: flex; flex-wrap: wrap; gap: 5px; }
.book .link {
  font-size: 11.5px;
  font-weight: 500;
  text-decoration: none;
  padding: 4px 8px;
  border-radius: 7px;
  border: 1.5px solid var(--rule-strong);
  color: var(--soft);
}
.book .link:hover { border-color: var(--ink); color: var(--ink); }

/* The set textbook for each subject, marked class="book main". It's the one
   most people came for, so it gets the highlighter and a bit more room. */
.book > b {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.35;
}
.book.main { grid-column: span 2; }
.book.main .cover { border-color: var(--mark-deep); border-width: 2px; }
.book.main > b { font-size: 15px; }
.book.main > b::after {
  content: "Set text";
  display: inline-block;
  margin-left: 7px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--mark);
  color: var(--mark-ink);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  vertical-align: middle;
}
.book .by b { display: block; color: var(--soft); font-weight: 600; }

@media (max-width: 420px) {
  .book-grid { grid-template-columns: repeat(2, 1fr); }
  .book.main { grid-column: span 2; }
}

/* ============================================================
   FLASHCARDS
   ============================================================ */

.toolbox { display: flex; flex-wrap: wrap; gap: 7px; margin: 22px 0 14px; }
.toolbar { display: grid; gap: 12px; margin: 16px 0 20px; }
/* Scoped: .chip-group is also used on the grade-boundaries page as a plain
   wrapping row. An unscoped column here stacked those chips vertically. */
.toolbar .chip-group { display: flex; flex-direction: column; gap: 6px; }
.chip-group-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--faint);
}
.toolbar .chip-group .chips { margin: 0; }

.chip-select { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.chip-select select, .chip-select input {
  font: inherit;
  font-size: 13px;
  padding: 2px 4px;
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: inherit;
  cursor: pointer;
}
.chip-select input { width: 52px; text-align: center; }
.chip-select.on select, .chip-select.on input { color: var(--paper); }

.shared-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 13px 14px;
  margin-bottom: 18px;
  border-radius: 12px;
  background: var(--mark);
  color: var(--mark-ink);
}
.shared-text { flex: 1 1 200px; font-size: 13.5px; line-height: 1.4; }
.shared-text b { display: block; font-weight: 700; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- deck tiles ---------- */
.tiles { display: grid; gap: 9px; margin: 12px 0; }
.cat-head {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  font: inherit;
  font-family: var(--display);
  font-weight: 600;
  font-size: 16px;
  letter-spacing: -0.02em;
  text-align: left;
  cursor: pointer;
  padding: 12px 2px;
  margin-top: 6px;
  border: 0;
  border-bottom: 1.5px solid var(--rule);
  background: transparent;
  color: var(--ink);
}
/* app.js sets this element's background inline to the subject's colour —
   it's a swatch, not a caret, so it needs a size rather than a font size. */
.cat-mark {
  width: 13px;
  height: 13px;
  flex: none;
  border-radius: 4px;
  background: var(--tab, var(--mark));
}
.cat-count { margin-left: auto; font-family: var(--body); font-size: 12px; font-weight: 500; color: var(--faint); }
/* "Share subject" / "Share these", sat inside the category heading */
.cat-share {
  flex: none;
  font-family: var(--body);
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  color: var(--soft);
  white-space: nowrap;
}
.cat-share:hover { border-color: var(--ink); color: var(--ink); }
/* the count sits between the name and the button, so only it should push */
.cat-head .cat-count + .cat-share { margin-left: 0; }
.cat-head .cat-share { margin-left: 8px; }

.sub-head .cat-share { margin-left: auto; }
.sub-head {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 16px 0 7px;
}

.tile {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 13px;
  border: 1.5px solid var(--rule);
  border-radius: 12px;
  background: var(--paper);
  position: relative;
}
.tile-open {
  flex: 1;
  min-width: 0;
  text-align: left;
  font: inherit;
  cursor: pointer;
  border: 0;
  background: transparent;
  color: var(--ink);
  padding: 0;
}
.tile-name { display: block; font-size: 14.5px; font-weight: 600; line-height: 1.3; }
.tile-meta { display: block; font-size: 11.5px; color: var(--faint); margin-top: 2px; }
.tile-bar {
  display: block;
  height: 6px;
  margin-top: 8px;
  border-radius: 999px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  overflow: hidden;
}
.tile-bar > span { display: block; height: 100%; background: var(--mark); }
.tile-tools { display: flex; gap: 4px; flex: none; }
.tile-tool {
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  padding: 6px 8px;
  border-radius: 7px;
  border: 1.5px solid transparent;
  background: transparent;
  color: var(--faint);
}
.tile-tool:hover { border-color: var(--rule-strong); color: var(--ink); }
.tile-tool-danger:hover { border-color: var(--no); color: var(--no); }

/* ---------- search hits ---------- */
.hits { display: grid; gap: 7px; margin-bottom: 16px; }
.hit-deck { font-size: 11px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--faint); }
.hit-front { font-size: 14px; font-weight: 600; line-height: 1.35; }
.hit-back { font-size: 13px; color: var(--soft); line-height: 1.4; }
.empty { padding: 26px 14px; text-align: center; font-size: 13.5px; color: var(--faint); }

/* ---------- the card itself ---------- */
/* The one place on the site that gets real depth: it's meant to read as a
   physical card on a table, and the stack behind it shows how many are
   left without needing a number. */
.stack {
  position: relative;
  margin: 8px 0 14px;
  perspective: 1400px;   /* without this the flip is a flat wipe, not a turn */
}
.ghost {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  border-radius: 16px;
  border: 1.5px solid var(--rule);
  background: var(--paper);
  pointer-events: none;
}
.ghost.g1 { transform: translateY(6px) scale(.985); opacity: .9; }
.ghost.g2 { transform: translateY(12px) scale(.97); opacity: .6; }
.ghost.g3 { transform: translateY(18px) scale(.955); opacity: .35; }
.ghost[hidden] { display: none; }

/* Both faces share one grid cell, so the card is as tall as its longest
   side and a wordy answer can't spill out the bottom.

   The turn is rotateY and the class is .on — that's what app.js toggles.
   Getting either wrong means the card simply never flips. */
.flip {
  position: relative;
  z-index: 2;
  display: grid;
  cursor: pointer;
  transform-style: preserve-3d;
  transition: transform .5s cubic-bezier(.2, .75, .3, 1);
}
.flip.on { transform: rotateY(180deg); }

.face {
  grid-area: 1 / 1;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: min(44vh, 290px);
  padding: 34px 24px 26px;
  border-radius: 16px;
  border: 1.5px solid var(--rule);
  background: var(--paper);
  box-shadow: var(--shadow-2);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  text-align: center;
  overflow: hidden;
}
/* the subject's colour, carried through from the deck tile */
.face::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 5px;
  background: var(--tab, var(--mark));
}
.face.back { transform: rotateY(180deg); background: var(--paper-2); }

.tag {
  position: absolute;
  top: 12px;
  left: 14px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
}
.star {
  position: absolute;
  top: 8px;
  right: 10px;
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
  padding: 5px 7px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--rule-strong);
}
.star:hover { color: var(--faint); }
.star[aria-pressed="true"] { color: var(--mark-deep); }

.face .q, .face .a {
  margin: 0;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(19px, 5vw, 25px);
  letter-spacing: -0.02em;
  line-height: 1.25;
}
.face .a-q { margin: 0; font-size: 13px; color: var(--faint); line-height: 1.35; }
.face .hint { margin: 0; font-size: 13px; color: var(--soft); font-style: italic; }

.prompt { text-align: center; font-size: 12.5px; color: var(--faint); margin: 0 0 14px; }

/* ---------- answering ---------- */
.typing { margin-bottom: 14px; }
.answer-input {
  width: 100%;
  font: inherit;
  font-size: 16px;
  text-align: center;
  padding: 12px 14px;
  border-radius: 11px;
  border: 1.5px solid var(--rule-strong);
  background: var(--paper);
  color: var(--ink);
  -webkit-appearance: none;
  appearance: none;
}
.answer-input:focus { border-color: var(--ink); outline: none; }
.accents { display: flex; flex-wrap: wrap; gap: 5px; justify-content: center; margin-top: 8px; }
.accent {
  font: inherit;
  font-size: 15px;
  cursor: pointer;
  min-width: 36px;
  padding: 7px 9px;
  border-radius: 8px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  color: var(--ink);
}
.accent:hover { border-color: var(--ink); }

.verdict {
  margin: 10px 0 0;
  text-align: center;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
}
.verdict.ok { color: var(--yes); }
.verdict.no { color: var(--no); }

.choices { display: grid; gap: 7px; margin-bottom: 14px; }
.choice {
  display: flex;
  align-items: center;
  gap: 11px;
  font: inherit;
  font-size: 14.5px;
  text-align: left;
  cursor: pointer;
  padding: 13px 14px;
  border-radius: 11px;
  border: 1.5px solid var(--rule-strong);
  background: var(--paper);
  color: var(--ink);
  line-height: 1.35;
}
.choice:hover { border-color: var(--ink); }
.choice-n {
  flex: none;
  width: 23px;
  height: 23px;
  display: grid;
  place-items: center;
  border-radius: 7px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  font-family: var(--display);
  font-size: 12px;
  font-weight: 700;
  color: var(--faint);
}
.choice-text { flex: 1; min-width: 0; }
.choice:hover .choice-n { color: var(--ink); border-color: var(--rule-strong); }
/* on a phone there is no keyboard, so the number is just a bullet */
@media (hover: none) { .choice-n { color: var(--faint); } }


.judge { display: flex; gap: 8px; margin-bottom: 16px; }
.btn-no, .btn-yes {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  padding: 14px 0;
  border-radius: 12px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  color: var(--ink);
}
.btn-no:hover { border-color: var(--no); color: var(--no); }
/* "Got it" is the one you press most, so it's the one that's easy to hit
   without looking. */
.btn-yes { background: var(--mark); border-color: var(--mark); color: var(--mark-ink); }
.btn-yes:hover { background: var(--mark-deep); border-color: var(--mark-deep); }
kbd {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  padding: 2px 5px;
  border-radius: 4px;
  border: 1px solid currentColor;
  opacity: .5;
}
@media (max-width: 480px) { kbd { display: none; } }

.meter {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 11.5px;
  color: var(--faint);
  font-weight: 500;
}
.meter .bar { flex: 1; height: 8px; }
.meter .bar > span { display: block; height: 100%; background: var(--mark); border-radius: 999px; }

/* .score-row is the ROW; .score is the badge sitting in it. Having these
   the wrong way round is what made the number overlap the text beside it. */
.score-row {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}
.score {
  flex: none;
  font-family: var(--display);
  font-weight: 700;
  font-size: 34px;
  letter-spacing: -0.04em;
  line-height: 1;
  padding: 12px 18px;
  border-radius: 16px;
  background: var(--mark);
  color: var(--mark-ink);
}
.score-sub { font-size: 14px; color: var(--soft); line-height: 1.5; min-width: 0; }
.results-head {
  font-family: var(--display);
  font-weight: 600;
  font-size: 16px;
  margin: 22px 0 9px;
}
.missed { display: grid; gap: 7px; }
.missed-head { font-size: 12.5px; color: var(--soft); margin-bottom: 7px; }

.card-list { display: grid; gap: 6px; }
.card-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1.5px solid var(--rule);
  border-radius: 10px;
}
.card-row-n { font-size: 11.5px; color: var(--faint); flex: none; min-width: 22px; font-variant-numeric: tabular-nums; }
.card-row-text { flex: 1; min-width: 0; font-size: 13.5px; line-height: 1.4; }
.card-row-text b { display: block; font-weight: 600; }
.card-row-text span { color: var(--soft); }
.card-row-dot { width: 9px; height: 9px; border-radius: 999px; flex: none; background: var(--rule-strong); }
.card-row-dot.ok { background: var(--yes); }
.card-row-dot.no { background: var(--no); }
/* A button, with an .on state. Styling it as bare text left every star as a
   default white browser button — so an unstarred card looked starred. */
.card-row-star {
  flex: none;
  font-size: 15px;
  line-height: 1;
  padding: 5px 7px;
  border: 1.5px solid transparent;
  border-radius: 9px;
  background: none;
  color: var(--rule-strong);
  cursor: pointer;
}
.card-row-star:hover { color: var(--mark-deep); border-color: var(--rule); }
.card-row-star.on { color: var(--mark-deep); }

.chunk-note { font-size: 12px; color: var(--faint); margin: 8px 0 0; }

/* ---------- shared form bits (editor, account, list search) ---------- */
.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field > span {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
}
.field input, .field textarea, .field select {
  font: inherit;
  font-size: 16px;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1.5px solid var(--rule-strong);
  background: var(--paper);
  color: var(--ink);
  width: 100%;
  -webkit-appearance: none;
  appearance: none;
}
.field textarea { min-height: 110px; resize: vertical; line-height: 1.5; }
.field input:focus, .field textarea:focus, .field select:focus { border-color: var(--ink); outline: none; }
.field.grow { flex: 1; min-width: 220px; }
.list-search { margin-bottom: 12px; }
.actions { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 14px; }
.danger, .ac-danger { color: var(--no); border-color: var(--no); }
.danger:hover, .ac-danger:hover { background: var(--no-soft); }

/* ---------- deck editor ---------- */
.ed-top { display: flex; gap: 14px; flex-wrap: wrap; margin: 22px 0 18px; }
.ed-grid { display: grid; gap: 12px; grid-template-columns: 1fr; }
@media (min-width: 820px) { .ed-grid { grid-template-columns: 1fr 1fr; align-items: start; } }
.ed-fields { display: grid; gap: 11px; }
.ed-preview {
  border: 1.5px solid var(--rule);
  border-radius: 14px;
  padding: 14px;
  background: var(--paper);
}
/* A card row is a button showing two pieces of text, with tools beside it —
   NOT a pair of input fields. Styling them as inputs put a bordered box
   round each word and left the row looking like a form. */
.ed-list { list-style: none; padding: 0; margin: 10px 0 0; }
.ed-row {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1.5px solid var(--rule);
  border-radius: 12px;
  background: var(--paper);
  margin-bottom: 7px;
  padding-right: 8px;
}
.ed-row.on { border-color: var(--mark-deep); box-shadow: 0 0 0 3px var(--mark); }
.ed-row.incomplete { border-color: var(--rule); }
.ed-row.incomplete .ed-row-front { color: var(--faint); font-style: italic; }

/* the whole row is the click target for editing that card */
.ed-pick {
  flex: 1;
  min-width: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  text-align: left;
  background: none;
  border: 0;
  padding: 11px 14px;
  cursor: pointer;
  font: inherit;
  color: inherit;
}
@media (max-width: 560px) { .ed-pick { grid-template-columns: 1fr; gap: 2px; } }

.ed-row-front { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ed-row-back { color: var(--soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ed-row-tools { display: flex; gap: 3px; flex: none; }
.ed-mini {
  width: 30px;
  height: 30px;
  flex: none;
  font: inherit;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  border: 1.5px solid transparent;
  border-radius: 9px;
  background: none;
  color: var(--faint);
}
.ed-mini:hover { border-color: var(--rule-strong); color: var(--ink); background: var(--paper-2); }

.ed-actions { display: flex; flex-wrap: wrap; gap: 8px; }

/* The paste box is NOT inside a .field, so .field textarea never reached it
   and it fell back to the browser's default white box. */
.ed-paste { display: grid; gap: 8px; margin: 10px 0 26px; }
.ed-paste textarea {
  width: 100%;
  min-height: 130px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 14px;
  line-height: 1.55;
  padding: 13px 15px;
  border: 1.5px solid var(--rule-strong);
  border-radius: 12px;
  background: var(--paper);
  color: var(--ink);
  resize: vertical;
}
.ed-paste textarea:focus { border-color: var(--ink); outline: none; }
.ed-preview .stack { margin-top: 0; }
.ed-preview .face { min-height: min(38vh, 250px); }

/* ---------- account ---------- */
.ac-head { margin-bottom: 18px; }
.ac-grid { display: grid; gap: 12px; grid-template-columns: 1fr; }
@media (min-width: 760px) { .ac-grid { grid-template-columns: 1fr 1fr; align-items: start; } }
.ac-status {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1.5px solid var(--rule);
  background: var(--paper-2);
  font-size: 13.5px;
  margin-bottom: 16px;
}
.ac-dot {
  width: 9px;
  height: 9px;
  border-radius: 999px;
  flex: none;
  background: var(--rule-strong);
}
/* account.js uses .good / .bad / .busy — not .on / .off */
.ac-dot.good { background: var(--yes); }
.ac-dot.bad  { background: var(--no); }
.ac-dot.busy { background: var(--mark-deep); }
.ac-msg { font-size: 13px; line-height: 1.5; margin: 9px 0 0; }
.ac-msg.ok { color: var(--yes); }
.ac-msg.no { color: var(--no); }
.ac-msg:empty { display: none; }
.ac-note { font-size: 12.5px; color: var(--faint); line-height: 1.55; margin: 9px 0 0; }

.tally { display: grid; gap: 9px; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); }
.tally-box {
  padding: 12px;
  border-radius: 11px;
  border: 1.5px solid var(--rule);
  text-align: center;
}
.tally-box b {
  display: block;
  font-family: var(--display);
  font-weight: 700;
  font-size: 23px;
  letter-spacing: -0.03em;
  line-height: 1;
}
.tally-box span { display: block; font-size: 11px; color: var(--faint); margin-top: 4px; }

/* A week of study at a glance — bars, not a chart library. */
.spark { display: flex; align-items: flex-end; gap: 3px; height: 46px; margin-top: 10px; }
.spark-bar {
  flex: 1;
  min-height: 3px;
  border-radius: 3px 3px 0 0;
  background: var(--mark);
}
.spark-bar.none { background: var(--rule); }

/* ---------- print page ----------
   Deliberately empty. assets/print.css owns this page completely: the
   two-column screen layout, the scaled A4 preview, and the paper itself.
   It was written against this exact markup — duplicating any of it here
   only creates a fight over which rule wins. */

/* The printed sheets are laid out in assets/print.css — millimetre-based
   A4 with fold-over units, card-size variables and its own @page rules.
   Nothing here should touch .sheet, .unit or .single, or it will fight it. */


/* ---------- the dropdown, as a sheet on small screens (menus.js) ---------- */
/* A hover menu is useless on a phone, so below 560px the same links open as
   a bottom sheet instead. */
.pp-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 92;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0;
  background: rgba(20, 23, 26, .45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.pp-modal-overlay[hidden] { display: none; }
.pp-modal {
  width: 100%;
  max-width: 520px;
  max-height: 78vh;
  overflow-y: auto;
  padding: 16px 16px 26px;
  border-radius: 18px 18px 0 0;
  border: 1.5px solid var(--rule);
  border-bottom: 0;
  background: var(--paper);
  box-shadow: var(--shadow-2);
}
@media (min-width: 560px) {
  .pp-modal-overlay { align-items: center; padding: 16px; }
  .pp-modal { border-radius: 16px; border-bottom: 1.5px solid var(--rule); }
}
.pp-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}
.pp-modal-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.02em;
}
.pp-modal-close {
  font: inherit;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  width: 32px;
  height: 32px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 8px;
  border: 0;
  background: transparent;
  color: var(--faint);
}
.pp-modal-close:hover { background: var(--paper-2); color: var(--ink); }
.pp-modal-links { display: grid; gap: 5px; }
.pp-modal-links a {
  padding: 12px 13px;
  border-radius: 10px;
  border: 1.5px solid var(--rule);
  text-decoration: none;
  font-size: 14.5px;
  font-weight: 500;
  color: var(--ink);
}
.pp-modal-links a:hover { border-color: var(--ink); }
.pp-modal-note { font-size: 12px; color: var(--faint); margin: 11px 0 0; line-height: 1.5; }

.pr-right { min-width: 0; }

/* ---------- the share-selection bar and toasts ---------- */
/* Both sit above everything and hug the bottom of the screen, clear of the
   iPhone home indicator. */
.select-bar {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  z-index: 70;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 11px 13px;
  border-radius: 14px;
  border: 1.5px solid var(--rule);
  background: var(--paper);
  box-shadow: var(--shadow-2);
}
.select-bar[hidden] { display: none; }
.select-count { flex: 1 1 auto; font-size: 13.5px; font-weight: 600; }
@media (min-width: 560px) {
  .select-bar { left: 50%; right: auto; transform: translateX(-50%); min-width: 380px; }
}

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 80;
  max-width: calc(100vw - 32px);
  padding: 11px 16px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  font-size: 13.5px;
  font-weight: 500;
  text-align: center;
  box-shadow: var(--shadow-2);
}
.toast[hidden] { display: none; }

.back-link { font-weight: 600; }

/* ============================================================
   hidden must always win
   ------------------------------------------------------------
   Setting display:flex or display:grid on a class silently beats
   the browser's built-in [hidden]{display:none}, so an element
   marked hidden in the HTML renders anyway — which is why an
   empty "someone shared a deck with you" bar could appear when
   nothing had been shared. One rule, applied last, rather than
   remembering a :not([hidden]) on every component.
   ============================================================ */
[hidden] { display: none !important; }

/* ============================================================
   Runtime state classes
   ------------------------------------------------------------
   Every class in here is one the JavaScript adds or removes at
   runtime. If the CSS doesn't define it, the state is invisible
   and the feature looks broken with no error to go on — which is
   exactly what happened to the card flip (.on, not .flipped).
   ============================================================ */

/* ---- answering ---- */
.answer-input.answered {
  opacity: .65;
  background: var(--paper-2);
  cursor: default;
}
/* app.js adds .choice-right / .choice-wrong — not .ok / .no */
.choice-right {
  border-color: var(--yes);
  background: var(--yes-soft);
  color: var(--yes);
  font-weight: 600;
  opacity: 1;
}
.choice-right .choice-n { background: var(--yes); border-color: var(--yes); color: var(--paper); }
.choice-wrong {
  border-color: var(--no);
  background: var(--no-soft);
  color: var(--no);
  opacity: 1;
}
.choice-wrong .choice-n { background: var(--no); border-color: var(--no); color: var(--paper); }
.choice[disabled] { cursor: default; }
.choice[disabled]:not(.choice-right):not(.choice-wrong) { opacity: .55; }

/* ---- picking decks to share ---- */
body.picking .tile { cursor: pointer; }
.tile-pickable { padding-right: 44px; }
.tile-check {
  position: absolute;
  top: 14px;
  right: 13px;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  border: 1.5px solid var(--rule-strong);
  background: transparent;
  color: transparent;
  display: grid;
  place-items: center;
  font-size: 13px;
  font-weight: 700;
}
.tile-picked { border-color: var(--mark-deep); box-shadow: 0 0 0 3px var(--mark); }
.tile-picked .tile-check {
  background: var(--mark);
  border-color: var(--mark-deep);
  color: var(--mark-ink);
}
.tile-broken { opacity: .55; }
.tile-broken .tile-meta { color: var(--no); }

/* ---- end of the pile ---- */
.score.clean { background: var(--yes-soft); color: var(--yes); }

/* ---- the deck editor ---- */
.ed-row.incomplete {
  border-color: var(--no);
  background: var(--no-soft);
}

/* ---- the account marker in the header ---- */
.avatar.nav-signed-in { background: var(--ink); color: var(--paper); }

/* ---- question bank and glossary ---- */
.qb-active { border-color: var(--ink); color: var(--ink); font-weight: 600; }
/* questions.js sets aria-expanded on the toggle button itself — keying the
   caret off a class on the panel meant it never turned. */
.qb-more-caret { display: inline-block; transition: transform .15s ease; }
.qb-more-toggle[aria-expanded="true"] .qb-more-caret { transform: rotate(45deg); }

/* Arriving from a search hit: the card flashes so you can see which one of
   forty you were sent to. */
@keyframes qcard-flash {
  0%   { background: var(--mark); border-color: var(--mark-deep); }
  100% { background: var(--paper); border-color: var(--rule); }
}
.qcard-flash { animation: qcard-flash 1.6s ease-out; }
@media (prefers-reduced-motion: reduce) {
  .qcard-flash { animation: none; border-color: var(--mark-deep); }
}

/* ---- the dropdown-as-sheet ---- */
body.pp-modal-open { overflow: hidden; }

/* ============================================================
   Textbook resources — rebuilt
   ------------------------------------------------------------
   The cover <img> comes LAST in the markup, after the links, so
   anything relying on source order puts it at the bottom of the
   card. Explicit grid placement pins it to the left column
   regardless of where it sits in the HTML.
   ============================================================ */
.book-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
  margin: 14px 0 30px;
  align-items: start;
}

.book {
  display: grid;
  grid-template-columns: 62px 1fr;
  grid-template-rows: auto auto 1fr;
  column-gap: 13px;
  row-gap: 3px;
  padding: 14px;
  border: 1.5px solid var(--rule);
  border-radius: 14px;
  background: var(--paper);
  min-width: 0;
}
.book .cover {
  grid-column: 1;
  grid-row: 1 / span 3;
  width: 62px;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--rule);
  background: var(--paper-2);
  align-self: start;
}
.book > b {
  grid-column: 2;
  grid-row: 1;
  font-family: var(--display);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -0.015em;
  line-height: 1.3;
  min-width: 0;
}
.book .by {
  grid-column: 2;
  grid-row: 2;
  display: block;
  font-size: 11.5px;
  color: var(--faint);
  line-height: 1.4;
  margin-bottom: 8px;
  min-width: 0;
}
.book .by b { display: block; color: var(--soft); font-weight: 600; }
.book .links {
  grid-column: 2;
  grid-row: 3;
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  align-content: start;
  align-items: flex-start;
  min-width: 0;
}

/* The set text for each subject: full width, bigger cover, and the
   highlighter — it's the one most people came for. */
.book.main {
  grid-column: 1 / -1;
  grid-template-columns: 92px 1fr;
  padding: 16px;
  border-color: var(--mark-deep);
  box-shadow: 0 0 0 3px var(--mark);
}
.book.main .cover { width: 92px; }
.book.main > b { font-size: 16px; }
.book.main > b::after {
  content: "Set text";
  display: inline-block;
  margin-left: 8px;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--mark);
  color: var(--mark-ink);
  font-family: var(--body);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  vertical-align: 2px;
}

/* A dropdown rendered as a plain text link (menus.js, class="link").
   It sits in a list beside ordinary <a> links, so it has to be
   indistinguishable from them — same size, same colour, same underline.
   Only the + marks it as the one that expands. */
.linklist a,
.pp-link-menu {
  font: inherit;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.pp-link-menu { cursor: pointer; padding: 0; border: 0; background: none; text-align: left; }
.linklist a:hover,
.pp-link-menu:hover { text-decoration-thickness: 2px; }
/* the + is a marker, not part of the label, so it stays quiet and
   doesn't get underlined with the words */
.pp-link-menu .caret {
  display: inline-block;
  margin-left: 4px;
  color: var(--faint);
  font-weight: 600;
  text-decoration: none;
}

.linklist { list-style: none; padding: 0; margin: 10px 0 26px; }
.linklist li { margin: 0 0 8px; }

@media (max-width: 460px) {
  .book { grid-template-columns: 52px 1fr; column-gap: 11px; }
  .book .cover { width: 52px; }
  .book.main { grid-template-columns: 68px 1fr; }
  .book.main .cover { width: 68px; }
}

/* Only the pieces print.css leaves to the host page. It covers the two-column
   layout, the scaled preview and the paper; the deck-picker list below lived
   in the old app.css, so it has to come across here. */
.pr-decks { margin: 6px 0 0; }
.pr-deck {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 13px;
  border: 1.5px solid var(--rule);
  border-radius: 12px;
  background: var(--paper);
  cursor: pointer;
  font-size: 13.5px;
}
.pr-deck:hover { border-color: var(--mark-deep); }
/* min-width:0 or a long deck title refuses to shrink and widens the row */
.pr-deck-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pr-deck-n {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  color: var(--faint);
  flex: none;
}
.pr-count { font-size: 13px; color: var(--soft); margin: 0 0 10px; }
.pr-help { margin: 8px 0 0; }

.pr-deck-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(250px, 100%), 1fr));
  gap: 5px;
  margin-bottom: 12px;
}
.pr-help-row {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: 14px;
  padding: 11px 0;
  border-top: 1px solid var(--rule);
  font-size: 13.5px;
  line-height: 1.5;
}
.pr-help-row b { font-family: var(--display); font-weight: 600; }
@media (max-width: 560px) { .pr-help-row { grid-template-columns: 1fr; gap: 3px; } }
.pr-deck-empty { opacity: .5; }
.pr-deck input { accent-color: var(--mark-deep); width: 17px; height: 17px; flex: none; }


/* ============================================================
   Printing
   ------------------------------------------------------------
   The shell is injected by shell.js on every page and carries no
   screen-only marker, so without this the header, nav, footer and
   countdown all land on the paper — which is why printing a deck
   produced the whole web page instead of just the cards.
   ============================================================ */
@media print {
  header.site,
  nav.site,
  footer.site,
  .announce,
  .skip,
  .select-bar,
  .toast,
  .stale-bar,
  .screen-only { display: none !important; }

  body { background: #fff; }
  main { max-width: none; margin: 0; padding: 0; }

  /* the preview is a scrolling box on screen; on paper it is the document */
  .pr-preview,
  .pr-preview-body {
    max-height: none !important;
    overflow: visible !important;
    padding: 0 !important;
    margin: 0 !important;
    background: none !important;
  }
  .pr-collapsed { display: block !important; }

  a[href]::after { content: none !important; }
}

/* ============================================================
   Things the original stylesheets styled that I missed
   ------------------------------------------------------------
   Found by diffing every selector in style.css and app.css
   against this file, rather than only comparing class names —
   which is how element and pseudo-element rules slipped past
   several earlier passes.
   ============================================================ */

/* ---- the FAQ accordions on the grade-boundaries page ---- */
/* Nine <details class="q"> live there. Styling .q as a heading left the
   summary with the browser's default disclosure triangle and no box. */
details.q {
  border: 1.5px solid var(--rule);
  border-radius: 12px;
  background: var(--paper);
  padding: 0;
  margin: 0 0 8px;
  font-weight: 400;
  font-size: inherit;
}
details.q summary {
  cursor: pointer;
  list-style: none;
  padding: 12px 14px;
  font-family: var(--display);
  font-weight: 600;
  font-size: 14.5px;
  letter-spacing: -0.01em;
}
details.q summary::-webkit-details-marker { display: none; }
details.q summary::before { content: "\25B8\00a0"; color: var(--mark-deep); font-weight: 700; }
details.q[open] summary::before { content: "\002B\00a0"; }
details.q[open] { border-color: var(--rule-strong); }
details.q .q-text, details.q .q-links { padding: 0 14px 13px; margin: 0; }
details.q .q-links { display: flex; flex-wrap: wrap; gap: 6px; }

/* ---- deck tiles carry their subject colour ---- */
/* app.js sets --tab on each tile and on the card stack. Without this the
   stripe never appears and every subject looks identical. */
.tile { position: relative; overflow: hidden; }
.tile::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 5px;
  background: var(--tab, var(--mark));
}
.tile { padding-top: 15px; }
.tile:hover { border-color: var(--rule-strong); }

/* ---- lists that are really <ul> ---- */
.missed { list-style: none; padding: 0; margin: 0; }
.missed li { padding: 11px 0; border-top: 1px solid var(--rule); font-size: 13.5px; line-height: 1.45; }
.hits { list-style: none; padding: 0; }
.hits li {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  gap: 12px;
  align-items: baseline;
  padding: 11px 13px;
  border: 1.5px solid var(--rule);
  border-radius: 11px;
}
@media (max-width: 560px) { .hits li { grid-template-columns: 1fr; gap: 3px; } }
.card-list:empty { display: none; }

/* ---- the in-deck card search ---- */
/* .list-search is the <label>; the input inside it had nothing at all. */
.list-search input {
  width: 100%;
  font: inherit;
  font-size: 16px;
  padding: 11px 15px;
  border: 1.5px solid var(--rule-strong);
  border-radius: 11px;
  background: var(--paper);
  color: var(--ink);
  -webkit-appearance: none;
  appearance: none;
}
.list-search input:focus { border-color: var(--ink); outline: none; }
.list-search input::placeholder { color: var(--faint); }
.list-search input::-webkit-search-cancel-button { -webkit-appearance: none; }

/* ---- a highlighted row in the grade-boundaries table ---- */
/* This is a <tr>, so it needs a background rather than a box. */
.gbp-table tr.gbp-overall td { background: var(--mark); color: var(--mark-ink); font-weight: 600; }
.gbp-table tr.gbp-overall td:first-child { background: var(--mark); }

/* ---- disabled controls have to look disabled ---- */
.chip[disabled], .cat-share[disabled], .pr-start:disabled, .qb-select:disabled {
  opacity: .4;
  cursor: not-allowed;
}
.chip[disabled]:hover { border-color: var(--rule-strong); color: var(--soft); }

/* ---- a ticked-off question says so in its number ---- */
.qcard.is-done .qnum::after { content: " \2713"; color: var(--mark-deep); }

/* ---- odds and ends the originals had ---- */
.field > span small { text-transform: none; letter-spacing: 0; font-size: .95em; opacity: .85; }
.hint b { color: var(--ink); font-weight: 600; }
.shared-text span { display: block; font-size: 12.5px; }
.q-questions li { margin-bottom: 6px; }
.q-questions li::marker { color: var(--faint); font-weight: 600; }
.pp-modal-note a { color: var(--soft); }
.pp-modal-note a:hover { color: var(--ink); }
.gb-source a:hover { color: var(--ink); }
.hit .meta b { font-weight: 700; }
.card-row-text i { font-style: italic; color: var(--faint); }
.card-row:nth-child(even) { background: var(--paper-2); }
.flip:focus-visible { outline: 2.5px solid var(--mark-deep); outline-offset: 5px; border-radius: 18px; }
.star:active { transform: scale(.9); }
code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .92em;
  padding: 1px 5px;
  border-radius: 5px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
}

/* a disabled choice shouldn't light up under the cursor */
.choice:hover:not([disabled]) { border-color: var(--ink); }
.choice[disabled]:hover { border-color: var(--rule-strong); }
.chip.qb-count:hover, .chip.sort-toggle:hover { border-color: var(--ink); color: var(--ink); }
.chip-select > span { color: inherit; }
.chip-select input[type="number"][hidden] { display: none; }
.btn.danger:hover { background: var(--no-soft); }

/* ============================================================
   Filter row — a labelled row of controls
   ------------------------------------------------------------
   Used on the grade-boundaries page. Each control is a labelled
   field so the row reads left to right at a glance, and it wraps
   to one control per line on a phone rather than shuffling into
   an unpredictable order.
   ============================================================ */
.filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px 14px;
  margin: 0 0 20px;
}
.filter-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}
.filter-field > span {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
}
/* pushed to the far end of the row, away from the filters proper */
.filter-field-end { margin-left: auto; align-self: flex-end; }
.filter-field .qb-select { min-width: 150px; }
.filter-field-end .chip { padding: 10px 14px; }

@media (max-width: 640px) {
  .filter-row { gap: 12px; }
  .filter-field { flex: 1 1 100%; }
  .filter-field .qb-select { width: 100%; }
  .filter-field-end { margin-left: 0; }
}

/* ---------- a two-state switch ---------- */
/* One control with two halves, rather than two buttons that happen to be
   mutually exclusive — the shared track makes the either/or obvious. */
.switch {
  display: inline-flex;
  padding: 3px;
  border-radius: 999px;
  border: 1.5px solid var(--rule-strong);
  background: var(--paper-2);
}
.switch-opt {
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  padding: 8px 15px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--soft);
  white-space: nowrap;
}
.switch-opt:hover { color: var(--ink); }
.switch-opt.on {
  background: var(--ink);
  color: var(--paper);
  font-weight: 600;
}
.switch-opt:focus-visible { outline: 2.5px solid var(--mark-deep); outline-offset: 2px; }

/* optgroup labels in the subject list */
.qb-select optgroup {
  font-style: normal;
  font-weight: 700;
  color: var(--faint);
  background: var(--paper);
}
.qb-select option { font-weight: 400; color: var(--ink); background: var(--paper); }

/* ============================================================
   The randomise button
   ------------------------------------------------------------
   Same chip as its neighbours, so it doesn't shout — but with a
   dotted ring that turns slowly, which reads as "shuffle" without
   needing a second colour. Once the filter row scrolls away it
   shrinks to a dice and follows you down the page.
   ============================================================ */
.qb-random {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  /* the ring is drawn by ::before, so the chip's own border stays off */
  border-color: transparent;
  background: transparent;
  overflow: visible;
}
/* Marching ants: the dashes travel around the outline rather than the whole
   ring turning. A CSS dashed border can't do this — the dashes are fixed to
   the box — so the outline is an SVG rect whose stroke-dashoffset animates.
   rx is clamped by the renderer to half the height, which gives the pill
   shape in the row and a circle when it's floating, with no extra rules. */
.qb-random-ants {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;      /* the stroke straddles the edge */
  pointer-events: none;
}
.qb-random-ants rect {
  fill: none;
  stroke: var(--rule-strong);
  stroke-width: 1.5;
  stroke-dasharray: 6 5;
  animation: qb-ants 1.4s linear infinite;
  /* rx is clamped against the WIDTH, not the height, so rx="999" gives an
     ellipse rather than a pill. It has to be half the button's height. */
  rx: 16.5px;
}
.qb-random:hover { color: var(--ink); }
.qb-random:hover .qb-random-ants rect { stroke: var(--mark-deep); }

/* one full dash + gap, so the loop is seamless */
@keyframes qb-ants { to { stroke-dashoffset: -11; } }

@media (prefers-reduced-motion: reduce) {
  .qb-random-ants rect { animation: none; }
}

.qb-random-face {
  font-size: 15px;
  line-height: 1;
  /* the dice itself tips a little when you press it */
  transition: transform .18s ease;
}
.qb-random:active .qb-random-face { transform: rotate(-18deg) scale(1.1); }

/* ---------- floating ---------- */
/* Below the fold it becomes a circle in the corner, clear of the iPhone
   home indicator and of anything sitting at the bottom of the page. */
.qb-random.floating {
  position: fixed;
  right: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  z-index: 60;
  width: 52px;
  height: 52px;
  padding: 0;
  gap: 0;
  justify-content: center;
  border-radius: 999px;
  background: var(--paper);
  box-shadow: var(--shadow-2);
  animation: qb-random-pop .18s ease-out;
}
.qb-random.floating .qb-random-label {
  /* hidden visually, still read aloud */
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.qb-random.floating .qb-random-face { font-size: 21px; }
.qb-random.floating .qb-random-ants rect {
  stroke: var(--mark-deep);
  stroke-width: 2;
  rx: 26px;               /* half of the 52px circle */
}

@keyframes qb-random-pop {
  from { transform: scale(.6); opacity: 0; }
  to   { transform: scale(1);  opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .qb-random.floating { animation: none; }
}

/* keep it clear of the share bar on pages that have one */
.select-bar:not([hidden]) ~ .qb-random.floating { bottom: 84px; }

/* ============================================================
   Exam mode
   ------------------------------------------------------------
   Once the clock starts the page becomes the paper. Everything
   that isn't the paper or the timer goes, and the page stops
   scrolling so nothing drifts off the top mid-question.
   Set on <html> and <body> by practice.js, cleared on finish
   and on unload so a reload can't strand the site with no nav.
   ============================================================ */
html.exam-mode,
body.exam-mode {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

body.exam-mode header.site,
body.exam-mode nav.site,
body.exam-mode footer.site,
body.exam-mode .announce,
body.exam-mode .skip { display: none !important; }

body.exam-mode main {
  max-width: none;
  height: 100dvh;          /* dvh, so a phone's shrinking address bar doesn't clip it */
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
}

body.exam-mode #pr-run {
  flex: 1;
  min-height: 0;           /* or the flex child refuses to shrink and overflows */
  display: flex;
  flex-direction: column;
}

/* the timer bar stays put at the top */
body.exam-mode .pr-bar {
  flex: none;
  border-radius: 0;
  padding-left: max(14px, env(safe-area-inset-left));
  padding-right: max(14px, env(safe-area-inset-right));
}

body.exam-mode .pr-frame-wrap {
  flex: 1;
  min-height: 0;
  margin: 0;
  gap: 1px;
  background: var(--rule);
}
body.exam-mode .pr-pane {
  min-height: 0;
  border: 0;
  border-radius: 0;
}
/* fill the space rather than a fixed vh, which would leave a gap or overflow */
body.exam-mode .pr-pane iframe { height: 100%; }
body.exam-mode .pr-pane-tag { opacity: .85; }

/* the "ready?" cover sits over the whole paper area */
body.exam-mode .pr-cover { border-radius: 0; }

@media (max-width: 900px) {
  body.exam-mode .pr-frame-wrap.split { grid-template-columns: 1fr; }
}

/* "Clear everything" wipes all three kinds at once, so it reads as the last
   resort rather than a fourth equal option. */
.ac-reset-all { margin-left: auto; }
.ac-reset-all:not([disabled]) { background: var(--no-soft); }
@media (max-width: 560px) { .ac-reset-all { margin-left: 0; width: 100%; } }

/* on the account page, the header marker is the "current page" indicator */
.avatar[aria-current="page"] {
  box-shadow: 0 0 0 2.5px var(--mark);
}

/* ---------- the fullscreen toggle ---------- */
/* Sits at the end of the timer bar, pushed to the corner. The icon is drawn
   in CSS — two brackets that turn inward when you're already fullscreen —
   so there's no icon font or SVG to load for one control. */
.pr-full { margin-left: auto; }
.pr-full-icon {
  position: relative;
  display: inline-block;
  width: 13px;
  height: 13px;
  flex: none;
}
.pr-full-icon::before,
.pr-full-icon::after {
  content: "";
  position: absolute;
  width: 6px;
  height: 6px;
  border: 1.8px solid currentColor;
}
/* top-left and bottom-right corners, pointing out */
.pr-full-icon::before { top: 0; left: 0; border-right: 0; border-bottom: 0; }
.pr-full-icon::after { bottom: 0; right: 0; border-left: 0; border-top: 0; }
/* already fullscreen: same brackets, turned in */
.pr-full.on .pr-full-icon::before { top: 0; left: 0; border: 1.8px solid currentColor; border-left: 0; border-top: 0; }
.pr-full.on .pr-full-icon::after { bottom: 0; right: 0; border: 1.8px solid currentColor; border-right: 0; border-bottom: 0; }

.pr-full { display: inline-flex; align-items: center; gap: 7px; }
.pr-full.on { background: var(--ink); border-color: var(--ink); color: var(--paper); }

/* On a narrow screen the label goes and the icon carries it, so the bar
   doesn't push the clock off the edge. */
@media (max-width: 620px) {
  .pr-full-label {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .pr-full { gap: 0; padding-left: 10px; padding-right: 10px; }
}

/* ============================================================
   Prompts
   ------------------------------------------------------------
   Two of them, both shown once: a heads-up on iPhones and iPads
   that Safari won't show a PDF inside a page, and a first-visit
   offer to make an account.
   ============================================================ */
.prompt-back {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0;
  background: rgba(20, 23, 26, .45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  animation: prompt-fade .18s ease-out;
}
body.prompt-open { overflow: hidden; }

.prompt {
  width: 100%;
  max-width: 460px;
  max-height: 85vh;
  overflow-y: auto;
  /* a sheet on a phone, a card on a desktop */
  padding: 22px 20px calc(22px + env(safe-area-inset-bottom, 0px));
  border-radius: 20px 20px 0 0;
  border: 1.5px solid var(--rule);
  border-bottom: 0;
  background: var(--paper);
  box-shadow: var(--shadow-2);
  animation: prompt-rise .22s cubic-bezier(.2, .7, .3, 1);
}
@media (min-width: 560px) {
  .prompt-back { align-items: center; padding: 20px; }
  .prompt { border-radius: 18px; border-bottom: 1.5px solid var(--rule); animation: prompt-fade .18s ease-out; }
}

.prompt-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 20px;
  letter-spacing: -0.025em;
  line-height: 1.2;
  margin: 0 0 9px;
}
.prompt-text {
  margin: 0 0 18px;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--soft);
}
.prompt-text b { color: var(--ink); font-weight: 600; }

.prompt-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.prompt-actions .btn { flex: 1 1 auto; justify-content: center; }

@keyframes prompt-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes prompt-rise { from { transform: translateY(14px); } to { transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .prompt-back, .prompt { animation: none; }
}

/* On an iPhone or iPad the new-tab link is the way through, not one option
   among several, so it gets the highlighter and the others stay quiet. */
body.is-ios #pr-newtab {
  background: var(--mark);
  border-color: var(--mark);
  color: var(--mark-ink);
  font-weight: 700;
}
body.is-ios #pr-newtab::after {
  content: " \2197";
  font-weight: 700;
}

/* ============================================================
   Media on a flashcard
   ------------------------------------------------------------
   Pictures, video, audio and PDFs. Sized to sit inside the card
   without pushing the text off it — the card grows to fit, but
   the media is capped so a tall image can't take the whole
   screen and hide the answer underneath.
   ============================================================ */
.media {
  width: 100%;
  margin-top: 12px;
  display: flex;
  justify-content: center;
}
.media[hidden] { display: none; }

.media img {
  max-width: 100%;
  max-height: 30vh;
  object-fit: contain;
  border-radius: 10px;
  border: 1px solid var(--rule);
  background: var(--paper-2);
}

/* video and PDFs keep their shape while the card resizes around them */
.media-youtube, .media-pdf { display: block; }
.media-youtube iframe,
.media-pdf iframe {
  display: block;
  width: 100%;
  border: 0;
  border-radius: 10px;
  background: var(--paper-2);
}
.media-youtube iframe { aspect-ratio: 16 / 9; }
.media-pdf iframe { height: 34vh; border: 1px solid var(--rule); }

.media audio { width: 100%; max-width: 320px; }

/* anything not on the embed allowlist is offered as a link instead */
.media-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  padding: 8px 13px;
  border-radius: 9px;
  border: 1.5px solid var(--rule-strong);
  color: var(--soft);
}
.media-link:hover { border-color: var(--ink); color: var(--ink); }

/* The card holds more now, so it may need to scroll on a short screen
   rather than spilling its answer off the bottom. */
.face { overflow-y: auto; }

/* a card carrying media wants a bit more room before it starts scrolling */
.stack.has-media .face { min-height: min(56vh, 420px); }

@media (max-width: 560px) {
  .media img { max-height: 26vh; }
  .media-pdf iframe { height: 30vh; }
}

/* ============================================================
   Deck colours
   ------------------------------------------------------------
   Each deck carries a colour on --tab, used for its tile stripe,
   its category swatch and the band across the top of a card.
   Kept as tokens so they can be tuned once and lifted in dark
   mode, where the light-mode versions go muddy.
   A deck can override this in the third column of
   data/flashcards.csv — a name (green, blue, coral, purple,
   amber, pink) or any CSS colour.
   ============================================================ */
:root {
  --deck-1: #4B3FE4;   /* indigo  — economics */
  --deck-2: #0F8A7E;   /* teal    — geography */
  --deck-3: #C2681B;   /* amber   — psychology */
  --deck-4: #C13A86;   /* pink    — french */
  --deck-5: #2472C8;   /* blue    — your own decks */
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --deck-1: #8E85FF;
    --deck-2: #35C2B1;
    --deck-3: #E8A45C;
    --deck-4: #FF7FC0;
    --deck-5: #7FB0FF;
  }
}
:root[data-theme="dark"] {
  --deck-1: #8E85FF;
  --deck-2: #35C2B1;
  --deck-3: #E8A45C;
  --deck-4: #FF7FC0;
  --deck-5: #7FB0FF;
}

/* the deck's colour, on the card itself */
.face::before { background: var(--tab, var(--mark)); }
.tile::before { background: var(--tab, var(--mark)); }
.cat-mark { background: var(--tab, var(--mark)); }

/* A way out of an embed that won't play or render — some videos have
   embedding switched off, and the frame alone is a dead end. */
.media-out {
  display: inline-block;
  margin-top: 7px;
  font-size: 12px;
  font-weight: 500;
  color: var(--soft);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--rule-strong);
}
.media-out:hover { color: var(--ink); }

/* ---------- video: the still, until you press play ---------- */
/* Nothing from YouTube loads until this button is clicked — no scripts, no
   storage access, no requests for a card you only flipped past. */
.yt-facade {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: 0;
  border-radius: 12px;
  overflow: hidden;
  cursor: pointer;
  background: var(--paper-2);
}
.yt-facade img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.yt-play {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 62px;
  height: 44px;
  border-radius: 11px;
  background: rgba(20, 23, 26, .78);
  transition: background .15s ease, transform .15s ease;
}
/* the triangle, drawn with a border so there's no image to load */
.yt-play::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-42%, -50%);
  border-style: solid;
  border-width: 9px 0 9px 15px;
  border-color: transparent transparent transparent #fff;
}
.yt-facade:hover .yt-play { background: #C4302B; transform: translate(-50%, -50%) scale(1.06); }
.yt-facade:focus-visible { outline: 2.5px solid var(--mark-deep); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .yt-play { transition: none; }
}

/* the editor's preview shows a label for video, PDF and audio rather than
   loading a player on every keystroke */
.ed-pv-media-tag {
  display: inline-block;
  padding: 7px 12px;
  border-radius: 999px;
  border: 1.5px dashed var(--rule-strong);
  font-size: 12px;
  font-weight: 600;
  color: var(--soft);
}
#ed-media-note:empty { display: none; }
#ed-media-note { margin-top: -4px; font-size: 12.5px; }

/* ============================================================
   Study notes
   ------------------------------------------------------------
   Markdown files in data/notes/, listed per subject on the
   resources page and rendered on notes.html. Set for reading:
   a narrower measure, generous line height, and the highlighter
   used for the key terms rather than for decoration.
   ============================================================ */
.notes-head {
  font-family: var(--display);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -0.02em;
  margin: 26px 0 3px;
}
.notes-lede { font-size: 13.5px; color: var(--soft); margin: 0 0 12px; }

.note-list {
  display: grid;
  gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
  margin-bottom: 18px;
}
.note-card {
  display: block;
  padding: 13px 15px;
  border: 1.5px solid var(--rule);
  border-radius: 12px;
  text-decoration: none;
  color: var(--ink);
  background: var(--paper);
}
.note-card:hover { border-color: var(--ink); }
.note-card-title {
  display: block;
  font-family: var(--display);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.015em;
}
.note-card-sum {
  display: block;
  margin-top: 3px;
  font-size: 12.5px;
  color: var(--soft);
  line-height: 1.45;
}

/* ---------- the note itself ---------- */
.note-back {
  display: inline-block;
  font-size: 13px;
  font-weight: 500;
  color: var(--soft);
  text-decoration: none;
  margin-bottom: 14px;
}
.note-back:hover { color: var(--ink); }

.note-layout { display: grid; gap: 26px; grid-template-columns: 1fr; align-items: start; }
@media (min-width: 900px) {
  .note-layout { grid-template-columns: 1fr 190px; }
  .note-toc {
    order: 2;
    position: sticky;
    top: calc(var(--header-h) + var(--tabs-h) + 16px);
    /* Its own scrollbar, so a long contents list doesn't force you to the
       bottom of the article to reach the last heading. dvh because a phone's
       address bar changes the real viewport height as you scroll. */
    max-height: calc(100dvh - var(--header-h) - var(--tabs-h) - 32px);
    overflow-y: auto;
    overscroll-behavior: contain;   /* stop the page scrolling once it bottoms out */
    scrollbar-width: thin;
  }
  .note-body { order: 1; }
}

.note-toc {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* on a phone it sits above the article, so cap it there too rather than
     pushing the note itself off the screen */
  max-height: 42vh;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.note-toc::-webkit-scrollbar { width: 6px; }
.note-toc::-webkit-scrollbar-thumb { background: var(--rule-strong); border-radius: 99px; }
.note-toc::-webkit-scrollbar-track { background: transparent; }
.note-toc-link {
  font-size: 12.5px;
  line-height: 1.4;
  padding: 4px 0 4px 10px;
  border-left: 2px solid var(--rule);
  text-decoration: none;
  color: var(--soft);
}
.note-toc-link:hover { color: var(--ink); border-left-color: var(--ink); }
.note-toc-link.lvl3 { padding-left: 20px; font-size: 12px; }

/* the section you're reading */
.note-toc-link.on {
  color: var(--ink);
  font-weight: 600;
  border-left-color: var(--mark-deep);
  background: linear-gradient(to right, var(--paper-2), transparent);
}

/* a heading jumped to from the contents shouldn't land under the sticky
   header — this is what pushes it clear */
.md h2, .md h3 { scroll-margin-top: calc(var(--header-h) + var(--tabs-h) + 20px); }

/* ---------- rendered markdown ---------- */
.md { max-width: 68ch; font-size: 16px; line-height: 1.7; }
.md > *:first-child { margin-top: 0; }
.md h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.025em;
  margin: 34px 0 10px;
  padding-top: 18px;
  border-top: 1px solid var(--rule);
}
.md h3 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 17px;
  margin: 24px 0 7px;
}
.md p { margin: 0 0 15px; }
.md ul, .md ol { margin: 0 0 15px; padding-left: 22px; }
.md li { margin-bottom: 6px; }
.md li > ul, .md li > ol { margin: 6px 0 0; }
.md a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--rule-strong); }
.md a:hover { text-decoration-color: var(--ink); }
.md strong { font-weight: 700; }
.md mark { background: var(--mark); color: var(--mark-ink); padding: 0 3px; border-radius: 3px; }
.md code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .9em;
  padding: 1px 5px;
  border-radius: 5px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
}
.md pre {
  margin: 0 0 15px;
  padding: 13px 15px;
  border-radius: 11px;
  background: var(--paper-2);
  border: 1.5px solid var(--rule);
  overflow-x: auto;
}
.md pre code { border: 0; background: none; padding: 0; font-size: 13.5px; line-height: 1.55; }
.md blockquote {
  margin: 0 0 15px;
  padding: 2px 0 2px 15px;
  border-left: 3px solid var(--mark);
  color: var(--soft);
}
.md blockquote p:last-child { margin-bottom: 0; }
.md hr { border: 0; border-top: 1px solid var(--rule); margin: 26px 0; }
.md img { max-width: 100%; height: auto; border-radius: 10px; border: 1px solid var(--rule); }

.md-table-wrap { overflow-x: auto; margin: 0 0 15px; }
.md table { width: 100%; border-collapse: collapse; font-size: 14.5px; }
.md th, .md td { padding: 9px 12px; text-align: left; border-bottom: 1px solid var(--rule); vertical-align: top; }
.md thead th {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
}

/* callouts: :::tip, :::warn, :::exam */
.md-call {
  margin: 0 0 16px;
  padding: 13px 15px;
  border-radius: 12px;
  border: 1.5px solid var(--rule);
  background: var(--paper-2);
  font-size: 14.5px;
}
.md-call p:last-child { margin-bottom: 0; }
.md-call::before {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 5px;
  color: var(--faint);
}
.md-call-note::before { content: "Note"; }
.md-call-tip  { border-color: var(--yes); background: var(--yes-soft); }
.md-call-tip::before  { content: "Tip"; color: var(--yes); }
.md-call-warn { border-color: var(--no); background: var(--no-soft); }
.md-call-warn::before { content: "Careful"; color: var(--no); }
.md-call-exam { border-color: var(--mark-deep); background: var(--mark); }
.md-call-exam::before { content: "In the exam"; color: var(--mark-ink); }
.md-call-exam, .md-call-exam code { color: var(--mark-ink); }
