/* mathtime — phone first, because a writing pad is a thumb's-width thing.
 *
 * TWO THEMES, AND LIGHT IS THE BASE, matching budget, words and mines. The
 * palette is the light one on bare :root; dark is a token swap in two guarded
 * blocks — the media query for "system", the attribute for a choice the user
 * made. Nothing outside those blocks names a literal colour. The duplication
 * between the two dark blocks is unavoidable: a media query cannot be OR-ed
 * with an attribute selector, and defining a colour in only one of them is how
 * a theme ends up half-applied.
 *
 * Insets go on PADDING, never on layout, and every one carries a 0px fallback —
 * `calc(6px + env(...))` with no fallback is an invalid length and drops the
 * whole declaration on every desktop browser.
 */

:root {
  --bg:       #f2f2f7;
  --panel:    #ffffff;
  --panel-2:  #f6f6f9;
  --line:     rgba(60, 60, 67, .16);
  --line-2:   rgba(60, 60, 67, .08);
  --ink:      #000000;
  --ink-2:    #3c3c43;
  --dim:      #8a8a8e;
  --dim-2:    #b0b0b6;
  --pill:     #efeff0;
  --seg-on:   #ffffff;   /* the chosen segment: lighter than its trough, as iOS's */
  --good:     #1a9e4b;
  --warn:     #b8730a;
  --bad:      #e5322b;
  --link:     #007aff;
  --shadow:   0 1px 2px rgba(0,0,0,.04), 0 6px 20px rgba(0,0,0,.05);
  /* The tip jar's heart — the same in both themes in every myjp.ca app, so
     it is set once here and the dark blocks leave it alone. */
  --heart:    #e0596e;

  /* The pad: paper and pen. The pen is the ink colour, read by pad.js from
     this token so the theme decides it rather than the canvas. */
  --paper:      #ffffff;
  --paper-line: rgba(60,60,67,.14);
  --pen:        #1c1c1e;

  --key:        #ffffff;
  --key-ink:    #000000;
  --key-del:    #d7d9de;

  --r-card: 20px;
  --r-mid:  13px;

  --font: -apple-system, BlinkMacSystemFont, system-ui, "SF Pro Text",
          "Helvetica Neue", sans-serif;
  --font-num: ui-rounded, -apple-system, "SF Pro Rounded", system-ui, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:       #000000;
    --panel:    #1c1c1e;
    --panel-2:  #2c2c2e;
    --line:     rgba(84, 84, 88, .5);
    --line-2:   rgba(84, 84, 88, .28);
    --ink:      #ffffff;
    --ink-2:    #ebebf5;
    --dim:      #8e8e93;
    --dim-2:    #636366;
    --pill:     #2c2c2e;
    --seg-on:   #636366;
    --good:     #30d158;
    --warn:     #ffd60a;
    --bad:      #ff453a;
    --link:     #0a84ff;
    --shadow:   0 1px 2px rgba(0,0,0,.5), 0 6px 20px rgba(0,0,0,.4);
    --paper:      #111113;
    --paper-line: rgba(255,255,255,.12);
    --pen:        #f2f2f7;
    --key:        #2c2c2e;
    --key-ink:    #ffffff;
    --key-del:    #48484c;
  }
}
:root[data-theme="dark"] {
  --bg:       #000000;
  --panel:    #1c1c1e;
  --panel-2:  #2c2c2e;
  --line:     rgba(84, 84, 88, .5);
  --line-2:   rgba(84, 84, 88, .28);
  --ink:      #ffffff;
  --ink-2:    #ebebf5;
  --dim:      #8e8e93;
  --dim-2:    #636366;
  --pill:     #2c2c2e;
  --seg-on:   #636366;
  --good:     #30d158;
  --warn:     #ffd60a;
  --bad:      #ff453a;
  --link:     #0a84ff;
  --shadow:   0 1px 2px rgba(0,0,0,.5), 0 6px 20px rgba(0,0,0,.4);
  --paper:      #111113;
  --paper-line: rgba(255,255,255,.12);
  --pen:        #f2f2f7;
  --key:        #2c2c2e;
  --key-ink:    #ffffff;
  --key-del:    #48484c;
}

/* NATIVE CONTROLS FOLLOW THE APP'S CHOICE, NOT ONLY THE PHONE'S (2026-09-24,
   ~/claude/IOS.md §11). Switches, scrollbars and the page's own canvas read
   `color-scheme`; without it, Dark chosen in Settings on a light phone drew
   light native controls on a black page. theme.js repaints the status bar
   to match. */
:root { color-scheme: light dark; }
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"]  { color-scheme: dark; }

* { box-sizing: border-box; }

/* `[hidden]` MUST WIN, AND BY DEFAULT IT DOES NOT. The browser's own
 * `[hidden] { display: none }` lives in the UA stylesheet, so any author rule
 * setting `display` on the same element beats it outright. mines shipped an
 * element that sat in plain sight while its `hidden` property read true. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  min-height: 100%;
  font-family: var(--font);
  color: var(--ink);
  background-color: var(--bg);
  -webkit-font-smoothing: antialiased;
}

/* No text selection and no iOS long-press callout anywhere in the app: a
   long-press on the pad pops the magnifier and eats the stroke. */
body {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
input, textarea { -webkit-user-select: text; user-select: text; }

/* iOS 26 blurs the top edge of a full-screen web app against the status bar,
   ~20px PAST env(safe-area-inset-top). Both are applied, once, on .view. */
:root { --glass-t: 20px; }

/* ── shell ─────────────────────────────────────────────────────────────── */

/* NO TAB BAR (mathtime-v18, gems' and minesweeper's arrangement): the
   leaderboard and the settings are one menu sheet (below, "the menu
   sheet"), so main pads for nothing but the home indicator. */

/* A RUN IS THE SCREEN (2026-09-24; letters-v17, gems' lock, ~/claude/IOS.md
   §15 item 2). Set by app.js lockPage() while a run is on the Play tab: the
   page cannot scroll and the view is the screen's height. pad.js measures
   the canvas on every fit, so its size is free to vary. Everything else
   still scrolls the document.

   AND THE INPUT IS AT THE FOOT (2026-09-25, the owner: "the input for both
   modes should be as close to the user's hands as possible"). The header
   is not shown during a run — nothing in it is used mid-run. The sum, the
   reading and the pad or numpad settle to the bottom (the question's
   `margin-top: auto`), and whatever room is left goes to the top, beside
   Quit.

   AND THE INPUT TAKES THE ROOM (mathtime-v18, the owner: the space at the
   bottom is for the keypad and the writing area). The pad was capped at
   min(56dvh, 460px) and the numpad's keys at 72px; now the pad grows to
   fill everything under the sum, and the keys go to 88px on a tall phone. */
html.in-game, html.in-game body { height: 100%; min-height: 0; overflow: hidden; overscroll-behavior: none; }
html.in-game .play-head { display: none; }
html.in-game #view-play {
  height: 100dvh; display: flex; flex-direction: column;
  padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
}
html.in-game .run { flex: 1; min-height: 0; }
html.in-game .question { margin-top: auto; }
html.in-game .pad-wrap { min-height: 0; display: flex; flex-direction: column; }
html.in-game .pad-wrap { flex: 1 1 auto; }
html.in-game .pad { height: auto; flex: 1 1 auto; min-height: 140px; }
/* Tall keys on a tall phone, and on a short one (a 568pt SE) still over
   48px, wider than a thumb. */
html.in-game .np-key, html.in-game .np-gap { height: var(--np-h, clamp(48px, 10.5dvh, 88px)); }
/* THE NUMPAD'S SIZE (mathtime-v21, a player: "can you make the numpad
   smaller?"). Large is v18's, the default the owner chose; Medium and Small
   shrink height AND width together, so a key keeps its shape and the reach
   from 7 to 0 gets shorter. Fixed sizes, not a share of the screen: the same
   choice means the same keys on an SE and a Pro Max. Small still clears 44pt.
   The class is app.js applyNpSize(); the choice is the device's, not the
   account's — it is about a hand and a phone. */
html.np-medium { --np-h: clamp(48px, 9dvh, 72px); --np-w: 336px; }
html.np-small  { --np-h: clamp(44px, 7.5dvh, 60px); --np-w: 300px; }

.view {
  padding: calc(8px + var(--glass-t) + env(safe-area-inset-top, 0px)) 16px calc(24px + env(safe-area-inset-bottom, 0px));
  max-width: 560px;
  margin: 0 auto;
}

.view-head { padding: 12px 4px 18px; }
/* THE BAR — minesweeper's: the title on the left, one round button on the
   right. The menu's head. */
.view-head.bar { display: flex; align-items: center; gap: 10px; }
.bar-title { flex: 1; min-width: 0; }
.view-head h1 { margin: 0; font-size: 34px; font-weight: 700; letter-spacing: -.6px; }
.view-sub { margin: 4px 0 0; color: var(--dim); font-size: 15px; }

/* The round buttons: the menu, and the menu's ✕ — minesweeper's `.icon`,
   in this app's panel and shadow. */
.icon {
  font: inherit; font-size: 18px; line-height: 0;
  width: 40px; height: 40px; border-radius: 20px; border: 0;
  display: grid; place-items: center; flex: none; padding: 0;
  background: var(--panel); box-shadow: var(--shadow);
  color: var(--ink); cursor: pointer;
}
.icon:active { opacity: .7; }

/* The menu's two parts, Leaderboard and Settings, in minesweeper's size;
   the small grey heads under them are `.sec`. */
h2.part { margin: 26px 4px 12px; font-size: 24px; font-weight: 700; letter-spacing: -.4px; }
#sec-board h2.part { margin-top: 6px; }
.part + .sec { margin-top: 6px; }

.sec {
  margin: 28px 4px 8px;
  font-size: 13px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .5px; color: var(--dim);
}

.card {
  background: var(--panel);
  border-radius: var(--r-card);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.fineprint { margin: 14px 6px 0; color: var(--dim); font-size: 12.5px; line-height: 1.55; }
.fineprint strong { color: var(--ink-2); font-weight: 600; }

/* ── buttons ───────────────────────────────────────────────────────────── */

.btn {
  font: inherit; font-size: 16px; font-weight: 600;
  padding: 13px 18px;
  border: 0; border-radius: var(--r-mid);
  background: var(--pill); color: var(--ink);
  cursor: pointer;
}
.btn:active { opacity: .7; }
.btn:disabled { opacity: .45; cursor: default; }
.btn-primary { background: var(--link); color: #fff; }
.btn-danger  { background: transparent; color: var(--bad); }
.btn-quiet   { background: var(--pill); color: var(--ink-2); font-weight: 500; }
.btn-wide    { display: block; width: 100%; margin-top: 18px; }
.btn-big     { font-size: 19px; padding: 16px 18px; }
.btn-small   { font-size: 13.5px; padding: 8px 14px; border-radius: 10px; }

.pill {
  display: block; width: 100%; margin: 0 0 12px;
  font: inherit; font-size: 13.5px; font-weight: 600;
  padding: 10px 14px; border: 0; border-radius: 999px;
  background: color-mix(in srgb, var(--link) 12%, var(--panel)); color: var(--link);
  cursor: pointer;
}

/* ── the gate ──────────────────────────────────────────────────────────── */

.gate { min-height: 100dvh; display: grid; place-items: center; padding: 24px; }
.gate-card { max-width: 340px; text-align: center; }
.gate-mark { display: flex; gap: 6px; justify-content: center; align-items: center; margin-bottom: 14px; font-family: var(--font-num); font-weight: 700; font-size: 26px; }
.gate-mark span { width: 40px; height: 40px; border-radius: 10px; display: grid; place-items: center; background: var(--panel); box-shadow: var(--shadow); }
.gate-mark .op { background: transparent; box-shadow: none; color: var(--dim); width: 22px; }
.gate-mark .ink { color: var(--link); width: 54px; font-style: italic; }
.gate-card h1 { margin: 8px 0 6px; font-size: 32px; letter-spacing: -.5px; }
.gate-sub { margin: 0 0 24px; color: var(--dim); font-size: 15px; line-height: 1.5; }
.gate-note { margin-top: 16px; color: var(--dim); font-size: 12.5px; line-height: 1.5; }
.gate-msg {
  margin: 0 0 18px; padding: 11px 13px; border-radius: var(--r-mid);
  background: color-mix(in srgb, var(--warn) 14%, transparent); color: var(--warn);
  font-size: 13px; line-height: 1.45; text-align: left;
}

/* ── play: header and streak ───────────────────────────────────────────── */

.play-head { display: flex; align-items: center; gap: 10px; padding: 4px 4px 10px; }
.play-title { font-size: 22px; font-weight: 700; letter-spacing: -.3px; }
.play-sub { font-size: 12px; color: var(--dim); margin-top: 1px; }
.play-head .spacer { margin-left: auto; }
/* The title block gives way to the streak and the menu, never the other
   way: a two-line sub ("Today counted. Come back tomorrow.") squeezed the
   pill until 🔥 and the number broke onto two lines (mathtime-v26). */
.play-head > div:first-child { flex: 1 1 auto; min-width: 0; }

.streak {
  display: flex; align-items: baseline; gap: 5px; flex: none; white-space: nowrap;
  padding: 6px 12px; border-radius: 999px;
  background: var(--panel); box-shadow: var(--shadow);
}
.streak-n { font-family: var(--font-num); font-weight: 800; font-size: 20px; font-variant-numeric: tabular-nums; }
.streak-k { font-size: 11px; color: var(--dim); font-weight: 500; }
.streak.on .streak-n { color: var(--warn); }
.streak.on .streak-n::before { content: "🔥"; font-size: 15px; margin-right: 3px; }
.streak.due .streak-n { color: var(--dim); }

/* ── play: the controls at the foot ────────────────────────────────────── */

/* Off a run, the Play view is at least the screen and the go controls
   (index.html, "go") are pushed to its foot, so the way of answering and
   Start / Again are under the thumb before and after every run — on the
   bottom edge since the tab bar went (mathtime-v18). In-flow content of a
   document that scrolls — IOS.md §15's shape, so it reaches the edge in
   the installed app too. */
#view-play { display: flex; flex-direction: column; min-height: 100dvh; padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
.play-go { margin-top: auto; padding-top: 18px; display: flex; flex-direction: column; gap: 10px; }
.play-go .seg button { padding-top: 11px; padding-bottom: 11px; }
.go-row { display: flex; gap: 10px; }
.go-row .btn { flex: 1 1 0; min-width: 0; }

/* ── play: idle ────────────────────────────────────────────────────────── */

.idle { padding: 14px 8px; }
.idle-stats { display: flex; justify-content: space-around; }
.idle-note { margin: 12px 8px 0; font-size: 13.5px; line-height: 1.5; color: var(--ink-2); }
.idle-note[hidden] { display: none; }
.play-sub:empty { display: none; }

/* THE SPEAKER (CLAUDE.md 5e, letters' .snd-g): drawn like the other glyphs,
   crossed out and a shade dimmer when off. */
.snd-g { width: 22px; height: 22px; fill: currentColor; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.snd-g .ol { fill: none; }
.sound-btn[aria-pressed="true"] .snd-off,
.sound-btn[aria-pressed="false"] .snd-on { display: none; }
.sound-btn[aria-pressed="false"] { opacity: .62; }
.sound-btn[hidden] { display: none; }

/* ── play: running ─────────────────────────────────────────────────────── */

.run { display: flex; flex-direction: column; }
.run-top { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; padding: 0 2px; }
.run-quit { justify-self: start; }
.run-right { justify-self: end; text-align: right; }
.run-n { font-family: var(--font-num); font-weight: 600; font-size: 15px; color: var(--dim); font-variant-numeric: tabular-nums; }
.run-clock { font-family: var(--font-num); font-weight: 700; font-size: 26px; font-variant-numeric: tabular-nums; letter-spacing: -.5px; }
.run-miss { text-align: right; font-family: var(--font-num); font-size: 13px; color: var(--bad); font-weight: 600; font-variant-numeric: tabular-nums; }

.question {
  margin: 10px 0 0; text-align: center;
  font-family: var(--font-num); font-weight: 800;
  font-size: clamp(44px, 14vw, 66px); letter-spacing: -1px; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.question.countdown { color: var(--dim); }

.reading {
  min-height: 40px; margin: 2px 0 6px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--font-num); font-weight: 700; font-size: 30px;
  font-variant-numeric: tabular-nums; color: var(--dim);
}
.reading.ok { color: var(--good); }
.reading.no { color: var(--bad); }
.reading-mark { font-size: 24px; }
.reading small { font-size: 13px; font-weight: 500; color: var(--dim); }

/* THE PAD. Tall enough for a two-digit answer written big — the net is
   shown a normalised copy, but a person writes the size they write, and a
   short pad makes them cramp. In a run it fills the screen under the sum
   (html.in-game, above); this is its size anywhere else. */
.pad-wrap { position: relative; }
.pad {
  display: block; width: 100%; height: min(46dvh, 380px);
  border-radius: var(--r-card);
  background: var(--paper);
  box-shadow: var(--shadow), inset 0 0 0 1px var(--paper-line);
  /* A faint baseline, as on a card. */
  background-image: linear-gradient(to top, var(--paper-line) 1px, transparent 1px);
  background-size: 100% 25%;
  background-position: 0 100%;
  touch-action: none;
}
.pad-wrap.ok .pad { box-shadow: var(--shadow), inset 0 0 0 3px var(--good); }
.pad-wrap.no .pad { box-shadow: var(--shadow), inset 0 0 0 3px var(--bad); }
/* Three columns with equal sides, so the hint sits under the middle of the
   pad or numpad whatever width Clear and Quit have. */
.pad-tools { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px; padding: 10px 4px 0; }
.pad-tools > :first-child { justify-self: start; }
.pad-tools > :last-child { justify-self: end; }
.pad-hint { font-size: 12px; color: var(--dim); }

/* THE NUMPAD. Three columns of buttons over 100pt wide each; no nearest-
   centre machinery is needed at this size. A GRID, not flex rows: with
   flex-basis 0 a <button> still floors at its own padding while the empty
   cell beside 0 does not, so the last row came out 0 and ⌫ wider than the
   keys above them (the owner's screenshot, 2026-09-25). */
.numpad { display: flex; flex-direction: column; gap: 8px; max-width: var(--np-w, 440px); width: 100%; margin: 0 auto; }
.np-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.np-key, .np-gap { min-width: 0; height: 60px; padding: 0; }
.np-key {
  border: 0; border-radius: 14px;
  background: var(--key); color: var(--key-ink);
  box-shadow: var(--shadow);
  font-family: var(--font-num); font-size: 26px; font-weight: 600;
  cursor: pointer;
}
.np-key:active { filter: brightness(.86); transform: scale(.97); }
.np-key:disabled { opacity: .5; }
.np-del { background: var(--key-del); font-size: 22px; }

/* ── play: done ────────────────────────────────────────────────────────── */

.done { margin-top: 12px; }
.done-head { padding: 20px 16px 8px; text-align: center; }
.done-head h2 { margin: 0 0 2px; font-size: 22px; letter-spacing: -.4px; }
.done-time { font-family: var(--font-num); font-size: 46px; font-weight: 800; letter-spacing: -1px; font-variant-numeric: tabular-nums; }
.done-time small { font-size: 18px; font-weight: 600; color: var(--dim); margin-left: 2px; }
.done-line { margin: 4px 0 0; color: var(--ink-2); font-size: 14px; line-height: 1.5; }
.done-verify { margin: 6px 0 0; color: var(--dim); font-size: 12.5px; line-height: 1.5; }
.done-verify.best { color: var(--warn); font-weight: 600; }
/* The reminders offer under a result (mathtime-v29): one row, the switch at the right. */
.done-remind { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin: 4px 16px 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.done-btns { display: flex; gap: 10px; padding: 8px 16px 16px; }
.done-btns .btn { flex: 1; }

/* ── segmented control ─────────────────────────────────────────────────── */

.seg { display: flex; gap: 2px; padding: 2px; background: var(--pill); border-radius: 10px; }
.seg button {
  flex: 1; font: inherit; font-size: 14px; font-weight: 500;
  padding: 7px 6px; border: 0; border-radius: 8px;
  background: transparent; color: var(--ink); cursor: pointer;
}
.seg button[aria-selected="true"], .seg button.is-on {
  background: var(--seg-on); font-weight: 600;
  box-shadow: 0 1px 3px rgba(0,0,0,.12);
}
.seg-sm { max-width: 230px; }

/* ── the leaderboard ───────────────────────────────────────────────────── */

.board-list { margin-top: 12px; }
.board-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line-2);
}
.board-row:last-child { border-bottom: 0; }
.board-row.you { background: color-mix(in srgb, var(--link) 9%, var(--panel)); }
.board-rank {
  width: 26px; flex: none; text-align: right;
  font-family: var(--font-num); font-weight: 700; font-size: 15px;
  font-variant-numeric: tabular-nums; color: var(--dim);
}
.board-row.you .board-rank { color: var(--link); }
.board-row.you .board-name { font-weight: 700; }
.board-who { flex: 1; min-width: 0; }
.board-name { font-size: 15px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.board-meta { font-size: 11.5px; color: var(--dim); margin-top: 1px; }
.board-score {
  font-family: var(--font-num); font-size: 18px; font-weight: 600;
  font-variant-numeric: tabular-nums; text-align: right;
}
.board-score small { display: block; font-size: 11px; font-weight: 500; color: var(--dim); }
.board-empty { padding: 30px 20px; text-align: center; color: var(--dim); font-size: 14px; line-height: 1.5; }

/* ── stats and settings rows ───────────────────────────────────────────── */

.stat-row { display: flex; justify-content: space-around; padding: 16px 8px; border-bottom: 1px solid var(--line-2); }
.stat { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.stat .v { font-family: var(--font-num); font-size: 24px; font-weight: 700; font-variant-numeric: tabular-nums; }
.stat .k { font-size: 10.5px; color: var(--dim); text-transform: uppercase; letter-spacing: .4px; text-align: center; }

.rows > .row {
  padding: 14px 16px;
  border-bottom: 1px solid var(--line-2);
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
}
.rows > .row:last-child { border-bottom: 0; }
.rows > .row.row-stack { flex-direction: column; align-items: stretch; gap: 8px; }
.row-head { display: flex; align-items: center; justify-content: space-between; }
.row-k { font-size: 15px; font-weight: 500; }
.row-v { font-family: var(--font-num); font-weight: 600; font-variant-numeric: tabular-nums; color: var(--ink-2); }
.row-note { margin: 0; font-size: 12.5px; line-height: 1.5; color: var(--dim); }
/* THE TIP JAR (index.html "THE TIP JAR"): the one row here that is tapped
   rather than switched — the same row as any above it (`.rows > .row` gives
   it the padding, the flex and the gap), as a <button> so haptics.js lays
   its switch over it; the heart is the only colour (thanks, not a price
   tag) and the chevron says it opens a page. Its card holds the row and
   nothing else, so the row's own padding is all the padding there is. */
#tipjar-card { margin-top: 14px; }
.rows > button.row-tap {
  appearance: none; -webkit-appearance: none; width: 100%; background: none; border: 0;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.rows > button.row-tap:active { background: var(--pill); }
.row-tap .row-k { flex: 1; }
.row-tap .chev { color: var(--dim); font-size: 22px; line-height: 1; margin-top: -2px; }
#tipjar .tip-glyph { color: var(--heart); font-size: 18px; line-height: 1; margin-right: 2px; }
/* MYJP.CA GAMES (index.html, the foot): the lockup from myjp.ca/games —
   the wordmark in the rounded face, "games" tucked under it in the games'
   gold (games/index.php) — then "More games" and the caret. */
:root { --games-gold: #c48a12; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --games-gold: #f2b93a; } }
:root[data-theme="dark"] { --games-gold: #f2b93a; }
#games-card { margin-top: 14px; }
#games-row { padding: 12px 16px; }
.games-lockup { display: inline-flex; flex-direction: column; align-items: flex-end; line-height: 1; font-family: "SF Pro Rounded", ui-rounded, var(--font); font-weight: 700; }
.games-lockup .gl-mark { font-size: 22px; letter-spacing: -0.01em; color: var(--ink); }
.games-lockup .gl-ca { color: var(--dim); }
.games-lockup .gl-sub { font-size: 10px; letter-spacing: .02em; color: var(--games-gold); margin-top: -1px; margin-right: 1px; }
#games-row .games-more { flex: 1; text-align: right; color: var(--dim); font-weight: 400; }
/* ACCOUNT: who, and Sign out as a row in the danger colour (the colour
   .btn-danger used when Sign out was a wide button). */
#account-card { padding: 14px 16px 0; }
#account-card .row-note { margin: 0 0 12px; }
#account-card .rows { margin: 0 -16px; }
#account-card .rows > button.row-tap { padding: 14px 16px; border-bottom: 0; border-top: 1px solid var(--line-2); }
.rows > button.row-tap.danger { color: var(--bad); }
/* TECHNICAL (index.html): a folded card — the summary is a row with a caret
   that turns; inside, a key/value list in the mono face and one note.
   list-style none + the -webkit-details-marker rule hide the browser's own
   triangle. */
details.technical { margin-top: 14px; }
details.technical > summary { list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 14px 16px; }
details.technical > summary::-webkit-details-marker { display: none; }
details.technical > summary .chev { color: var(--dim); font-size: 22px; line-height: 1; margin-top: -2px; transition: transform .15s; }
details.technical[open] > summary .chev { transform: rotate(90deg); }
details.technical > summary:active { background: var(--pill); }
details.technical .kv { margin: 0; padding: 4px 16px 12px; border-top: 1px solid var(--line-2); }
details.technical .kv > div { display: flex; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--line-2); }
details.technical .kv > div:last-child { border-bottom: 0; }
details.technical .kv dt { flex: 0 0 76px; font-size: 13px; color: var(--dim); }
details.technical .kv dd { margin: 0; flex: 1; min-width: 0; font-size: 12.5px; font-family: var(--font-mono); color: var(--ink-2); line-height: 1.5; overflow-wrap: anywhere; }
details.technical > .row-note { padding: 0 16px 14px; }

.switch { position: relative; display: inline-block; width: 51px; height: 31px; flex: none; }
.switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; z-index: 2; }
.switch span { position: absolute; inset: 0; border-radius: 999px; background: var(--pill); transition: background .2s ease; }
.switch span::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 27px; height: 27px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.25);
  transition: transform .2s ease;
}
.switch input:checked + span { background: var(--good); }
.switch input:checked + span::after { transform: translateX(20px); }
.switch input:disabled + span { opacity: .4; }

.prose { padding: 16px; }
.prose p { margin: 0 0 12px; font-size: 14px; line-height: 1.6; color: var(--ink-2); }
.prose p:last-child { margin-bottom: 0; }
.update-note { color: var(--warn); }

/* ── the menu sheet ────────────────────────────────────────────────────── */

/* IN FLOW, NOT FIXED (minesweeper-v32, bubbles-v34's menu): the page is the
   menu's scroller, so the menu runs under the status bar and to the bottom
   edge (IOS.md §15). Its head is the bar — the title and ✕ scroll away with
   the rest. The Play screen under it leaves the flow while it is open: a
   run cannot open the menu, so there is nothing on Play to hold the size
   of, and the pad is fitted again whenever a run starts. */
.sheet { position: relative; z-index: 30; }
.sheet-body {
  padding: calc(8px + var(--glass-t) + env(safe-area-inset-top, 0px)) calc(16px + env(safe-area-inset-right, 0px)) calc(32px + env(safe-area-inset-bottom, 0px)) calc(16px + env(safe-area-inset-left, 0px));
  max-width: 560px; width: 100%; margin: 0 auto;
}
.sheet-body > .view-head { padding-bottom: 4px; }
body:has(#sheet-menu:not([hidden])) main { display: none; }

/* ── the banner ────────────────────────────────────────────────────────── */

.banner {
  position: fixed; left: 12px; right: 12px;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px;
  background: var(--ink); color: var(--bg);
  border-radius: var(--r-mid);
  font-size: 13.5px; line-height: 1.45;
  box-shadow: var(--shadow);
  z-index: 20;
}
.banner button {
  margin-left: auto; flex: none;
  font: inherit; font-size: 20px; line-height: 1;
  border: 0; background: transparent; color: inherit; cursor: pointer;
}
.banner .banner-retry {
  margin-left: auto; padding: 6px 13px;
  font-size: 12.5px; font-weight: 600; line-height: 1.2;
  border-radius: 999px; background: var(--bg); color: var(--ink);
}
.banner .banner-retry:disabled { opacity: .45; }
.banner .banner-retry + button { margin-left: 4px; }

