/* Rot Reader — RSVP speed reader
   Dark by default, light on request. All sizing is fluid so the word
   display stays centered from a phone to a 4K monitor. */

/* ------------------------------------------------------------------ type

   Both faces are self hosted. Not a preference: the whole promise of this
   site is that it makes no third party requests, and a Google Fonts link
   would quietly break that on every page load. They are also in the service
   worker shell, so the reader looks the same on a plane.

   Literata was drawn for long form reading on screens, which is the entire
   job here. The old stack fell through to Times New Roman on a plain Windows
   machine, so the same book looked like a different product depending on
   whose laptop it was.

   Two subsets each, split by unicode-range, so an English reader never
   downloads the accented one. */

@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/geist-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/geist-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/literata-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/literata-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  color-scheme: dark;
  --bg: #08090b;
  --bg-soft: #0e1015;
  --panel: #12151b;
  --panel-2: #171b23;
  --line: #232833;
  --line-soft: #1a1e26;
  --text: #edeff4;
  --text-2: #aab0bd;
  --dim: #767d8c;
  --accent: #ff4b4b;
  --accent-soft: rgba(255, 75, 75, 0.14);
  --blue: #6ea8ff;
  --ok: #3fc77f;
  --radius: 14px;
  --ui: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --serif: "Literata", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Shadows carry the hue of the ground they fall on rather than plain black,
     and every one of them implies the same light source, from above. */
  --shadow-1: 0 1px 2px rgba(3, 4, 6, 0.4), 0 2px 8px rgba(3, 4, 6, 0.28);
  --shadow-2: 0 8px 26px rgba(3, 4, 6, 0.5), 0 2px 6px rgba(3, 4, 6, 0.35);
  --shadow-3: 0 18px 50px rgba(3, 4, 6, 0.62);

  /* One scale, so a new panel never has to guess. The old values ran 2, 20,
     40, 50, 55, 56, 60, 70 with no rule behind them. */
  --z-context: 2;
  --z-header: 20;
  --z-scrim: 40;
  --z-drawer: 50;
  --z-panel: 55;
  --z-toast: 60;
  --z-loading: 70;
  --z-grain: 100;
}

:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f7f7f5;
  --bg-soft: #ffffff;
  --panel: #ffffff;
  --panel-2: #f0f1f3;
  --line: #dcdee3;
  --line-soft: #e8eaee;
  --text: #14161a;
  --text-2: #4a505c;
  --dim: #767d8c;
  --accent: #d92020;
  --accent-soft: rgba(217, 32, 32, 0.1);
  --blue: #2563eb;

  /* Light mode needs its own, much softer, and still tinted rather than grey. */
  --shadow-1: 0 1px 2px rgba(28, 26, 22, 0.06), 0 2px 8px rgba(28, 26, 22, 0.05);
  --shadow-2: 0 8px 26px rgba(28, 26, 22, 0.1), 0 2px 6px rgba(28, 26, 22, 0.06);
  --shadow-3: 0 18px 50px rgba(28, 26, 22, 0.16);
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--ui);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

button, input, select, textarea {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
}

:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
  border-radius: 6px;
}

.app {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}

/* ---------------------------------------------------------------- header */

header.top {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--bg);
  position: sticky;
  top: 0;
  z-index: var(--z-header);
}

.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  font-weight: 650;
  letter-spacing: 0.02em;
  font-size: 15px;
  white-space: nowrap;
}

.brand .mark {
  width: 22px;
  height: 22px;
  flex: none;
}

.brand .r { color: var(--accent); }

.doc-name {
  min-width: 0;
  flex: 1;
  color: var(--text-2);
  font-size: 13px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
}

.top-actions {
  display: flex;
  gap: 6px;
  flex: none;
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 34px;
  min-width: 34px;
  padding: 0 10px;
  border-radius: 9px;
  border: 1px solid var(--line);
  color: var(--text-2);
  background: var(--panel);
  font-size: 13px;
  transition: background 0.15s, color 0.15s, border-color 0.15s, transform 0.1s;
}

.icon-btn:hover { background: var(--panel-2); color: var(--text); }
.icon-btn:active { transform: scale(0.96); }
.icon-btn[aria-pressed="true"] { color: var(--text); border-color: var(--blue); }
.icon-btn svg { width: 16px; height: 16px; flex: none; }

/* ------------------------------------------------------------- drop zone */

.intro {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 26px;
  /* Optical, not mathematical: an equal top and bottom reads as bottom heavy
     once the header is above it. */
  padding: 40px 16px 64px;
  text-align: center;
  position: relative;
}

/* The first screen used to be text floating on a flat void. One ambient wash,
   sitting behind everything and catching nothing, gives it somewhere to sit.
   Radial rather than a 45 degree linear fade, which always reads as a
   template. */
.intro::before {
  content: "";
  position: absolute;
  /* Horizontal inset stays at 0. A negative one bled 20% past each edge, and
     because nothing here clips, that alone gave the whole document 238px of
     sideways scroll. The gradients are positioned in percentages, so they
     spread perfectly well inside the box. */
  inset: -10% 0 auto;
  height: 70%;
  background:
    radial-gradient(58% 60% at 50% 0%, rgba(255, 75, 75, 0.10), transparent 70%),
    radial-gradient(40% 50% at 78% 18%, rgba(110, 168, 255, 0.06), transparent 72%);
  pointer-events: none;
  z-index: 0;
}

:root[data-theme="light"] .intro::before {
  background:
    radial-gradient(58% 60% at 50% 0%, rgba(217, 32, 32, 0.07), transparent 70%),
    radial-gradient(40% 50% at 78% 18%, rgba(37, 99, 235, 0.05), transparent 72%);
}

.intro > * { position: relative; z-index: 1; }

.intro h1 {
  margin: 0 0 12px;
  font-size: clamp(30px, 7vw, 54px);
  letter-spacing: -0.035em;
  line-height: 1.04;
  font-weight: 600;
  /* Stops a single word being orphaned onto its own line at awkward widths. */
  text-wrap: balance;
  max-width: 16ch;
  margin-inline: auto;
}

.intro h1 em {
  font-style: normal;
  color: var(--accent);
}

.intro p.lede {
  margin: 0;
  max-width: 48ch;
  margin-inline: auto;
  color: var(--text-2);
  font-size: clamp(14.5px, 3.4vw, 16.5px);
  line-height: 1.55;
  text-wrap: pretty;
}

.dropzone {
  width: min(620px, 100%);
  border: 1.5px dashed var(--line);
  border-radius: 20px;
  background: var(--bg-soft);
  box-shadow: var(--shadow-2);
  padding: 36px 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  transition: border-color 0.18s, background 0.18s, box-shadow 0.18s, transform 0.18s;
}

.dropzone:hover { border-color: var(--text-2); }

.dropzone.over {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: var(--shadow-3);
  transform: scale(1.006);
}

.dropzone .hint {
  color: var(--dim);
  font-size: 13px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 42px;
  padding: 0 20px;
  border-radius: 11px;
  background: var(--text);
  color: var(--bg);
  font-weight: 600;
  font-size: 14px;
  border: 1px solid transparent;
  box-shadow: var(--shadow-1);
  /* transform and opacity only, so this stays on the compositor. */
  transition: opacity 0.18s, transform 0.12s, background 0.18s, border-color 0.18s, box-shadow 0.18s;
}

.btn:hover { opacity: 0.88; transform: translateY(-1px); }
/* A press should feel like a press. Nothing here had any pressed state. */
.btn:active { transform: translateY(0) scale(0.985); box-shadow: none; }

.btn.ghost {
  background: transparent;
  color: var(--text);
  border-color: var(--line);
  box-shadow: none;
}

.btn.ghost:hover { background: var(--panel); border-color: var(--text-2); opacity: 1; }

.formats {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
}

.chip {
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--dim);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px 9px;
}

.paste-wrap {
  width: min(620px, 100%);
  display: flex;
  flex-direction: column;
  gap: 10px;
  text-align: left;
}

.paste-wrap textarea {
  width: 100%;
  min-height: 120px;
  resize: vertical;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 14px;
  font-size: 14px;
  line-height: 1.6;
}

.paste-wrap textarea::placeholder { color: var(--dim); }

.privacy {
  color: var(--dim);
  font-size: 12px;
  max-width: 44ch;
}

.intro-links {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  font-size: 12.5px;
}

.intro-links a {
  color: var(--text-2);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
  padding-bottom: 1px;
}

.intro-links a:hover { color: var(--text); border-bottom-color: var(--accent); }

/* ---------------------------------------------------------------- reader */

.reader {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.stage {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 18px 12px;
  min-height: 42svh;
  position: relative;
  user-select: none;
  cursor: pointer;
}

.rsvp {
  width: 100%;
  max-width: 900px;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
}

.guide {
  position: relative;
  height: 1px;
  background: var(--line);
}

.guide::after {
  content: "";
  position: absolute;
  left: 50%;
  width: 1px;
  height: 11px;
  background: var(--line);
  transform: translateX(-50%);
}

.guide.g-top::after { top: 0; }
.guide.g-bot::after { bottom: 0; }

.word-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  font-family: var(--serif);
  font-size: clamp(30px, 9.2vw, 76px);
  line-height: 1.25;
  letter-spacing: -0.01em;
  min-height: 1.25em;
  overflow: hidden;
  white-space: pre;
}

body[data-font="sans"] .word-row { font-family: var(--ui); }
body[data-font="mono"] .word-row { font-family: var(--mono); }

.word-row .pre { text-align: right; overflow: hidden; }
.word-row .post { text-align: left; overflow: hidden; }
.word-row .orp { color: var(--accent); text-align: center; }

body[data-orp="off"] .word-row .orp { color: inherit; }
body[data-guides="off"] .guide { opacity: 0; }

/* Sentence at a time.

   The three cells collapse to one centered block that is allowed to wrap. The
   font size is not set here, because applySettings writes it inline and an
   inline style beats any rule in this file.

   min-height holds four lines whether the sentence needs them or not. Without
   it the controls below jump up and down as short and long sentences trade
   places, which is the one thing a fixed point display must not do. */
body[data-chunk="sentence"] .word-row {
  display: flex;
  align-items: center;
  justify-content: center;
  white-space: normal;
  min-height: 4.4em;
  line-height: 1.5;
  letter-spacing: 0;
  overflow: hidden;
}

body[data-chunk="sentence"] .word-row .orp {
  color: inherit;
  max-width: 100%;
  text-wrap: pretty;
}

/* The tick on the guide lines marks the column the focus letter sits in, and
   in this mode there is no such column. The rules themselves stay. */
body[data-chunk="sentence"] .guide::after { opacity: 0; }

.stage-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px 14px;
  color: var(--dim);
  font-size: 12.5px;
  letter-spacing: 0.01em;
  min-height: 20px;
}

.stage-meta .sep { opacity: 0.45; }
.stage-meta b { color: var(--text-2); font-weight: 600; }

.tap-hint {
  position: absolute;
  bottom: 6px;
  left: 50%;
  transform: translateX(-50%);
  color: var(--dim);
  font-size: 11.5px;
  opacity: 0.7;
  pointer-events: none;
}

.paused-badge {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px 11px;
  background: var(--panel);
}

/* -------------------------------------------------------------- controls */

.controls {
  border-top: 1px solid var(--line-soft);
  background: var(--bg-soft);
  padding: 12px 16px 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.scrub {
  display: flex;
  align-items: center;
  gap: 12px;
}

.scrub input[type="range"] { flex: 1; }

.scrub .pos {
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  color: var(--dim);
  min-width: 8ch;
  text-align: right;
}

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  height: 22px;
  background: transparent;
  cursor: pointer;
}

input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 999px;
  background: var(--line);
}

input[type="range"]::-moz-range-track {
  height: 4px;
  border-radius: 999px;
  background: var(--line);
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 15px;
  height: 15px;
  margin-top: -5.5px;
  border-radius: 50%;
  background: var(--text);
  border: none;
}

input[type="range"]::-moz-range-thumb {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--text);
  border: none;
}

.transport {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
}

.tbtn {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-width: 56px;
  height: 48px;
  padding: 0 10px;
  border-radius: 11px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text-2);
  transition: background 0.14s, color 0.14s;
}

.tbtn:hover { background: var(--panel-2); color: var(--text); }
.tbtn:active { transform: translateY(1px); }
.tbtn svg { width: 18px; height: 18px; }
.tbtn .lbl { font-size: 9.5px; letter-spacing: 0.07em; text-transform: uppercase; color: var(--dim); }

.tbtn.play {
  min-width: 76px;
  background: var(--text);
  color: var(--bg);
  border-color: transparent;
}

.tbtn.play .lbl { color: rgba(0, 0, 0, 0.55); }
:root[data-theme="light"] .tbtn.play .lbl { color: rgba(255, 255, 255, 0.65); }
.tbtn.play:hover { background: var(--text); opacity: 0.9; color: var(--bg); }

.dials {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 18px;
  justify-content: center;
}

.dial {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 12.5px;
  color: var(--dim);
}

.dial label { letter-spacing: 0.04em; text-transform: uppercase; font-size: 10.5px; }
.dial input[type="range"] { width: clamp(110px, 26vw, 190px); }

.dial .val {
  font-variant-numeric: tabular-nums;
  color: var(--text);
  font-weight: 600;
  min-width: 6ch;
}

select.mini {
  height: 30px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  padding: 0 8px;
  font-size: 12.5px;
}

/* --------------------------------------------------------------- context */

.context {
  position: relative;
  border-top: 1px solid var(--line-soft);
  background: var(--bg);
  max-height: 30svh;
  overflow: auto;
  padding: 14px 18px 22px;
  font-family: var(--serif);
  font-size: 15.5px;
  line-height: 1.85;
  color: var(--dim);
  -webkit-overflow-scrolling: touch;
}

body[data-font="sans"] .context { font-family: var(--ui); }
body[data-font="mono"] .context { font-family: var(--mono); }

.context.hidden { display: none; }
.context .w { cursor: pointer; border-radius: 3px; }
.context .w:hover { background: var(--panel-2); color: var(--text); }
.context .w.in-sentence { color: var(--text-2); }
.context .w.current {
  background: var(--accent-soft);
  color: var(--text);
  font-weight: 600;
  box-shadow: 0 0 0 2px var(--accent-soft);
}
.context .para-break { display: block; height: 0.7em; }
.context .block-label {
  display: block;
  margin: 14px 0 6px;
  font-family: var(--ui);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--line);
  border-top: 1px solid var(--line-soft);
  padding-top: 10px;
}

/* --------------------------------------------------------------- drawers */

.scrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: var(--z-scrim);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s;
}

.scrim.open { opacity: 1; pointer-events: auto; }

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  height: 100svh;
  width: min(420px, 92vw);
  background: var(--panel);
  border-left: 1px solid var(--line);
  z-index: var(--z-drawer);
  transform: translateX(100%);
  transition: transform 0.22s cubic-bezier(0.2, 0.7, 0.3, 1);
  display: flex;
  flex-direction: column;
}

.drawer.open { transform: none; }

.drawer header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line-soft);
  font-weight: 620;
}

.drawer .body {
  overflow: auto;
  padding: 14px 16px 40px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.field .row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.field .name { font-size: 13.5px; font-weight: 560; }
.field .desc { font-size: 12px; color: var(--dim); line-height: 1.45; }

.seg {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 9px;
  overflow: hidden;
  flex: none;
}

.seg button {
  padding: 6px 11px;
  font-size: 12.5px;
  color: var(--dim);
  background: var(--panel);
  border-right: 1px solid var(--line);
}

.seg button:last-child { border-right: none; }
.seg button[aria-pressed="true"] { background: var(--panel-2); color: var(--text); font-weight: 600; }

.switch {
  width: 42px;
  height: 24px;
  border-radius: 999px;
  background: var(--line);
  position: relative;
  flex: none;
  transition: background 0.15s;
}

.switch::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--text);
  transition: transform 0.15s;
}

.switch[aria-pressed="true"] { background: var(--ok); }
.switch[aria-pressed="true"]::after { transform: translateX(18px); background: #08090b; }

.lib-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--bg-soft);
  text-align: left;
  width: 100%;
}

.lib-item:hover { border-color: var(--blue); }
.lib-item .meta { flex: 1; min-width: 0; }
.lib-item .t {
  font-size: 13.5px;
  font-weight: 580;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lib-item .s { font-size: 11.5px; color: var(--dim); }
.lib-item .bar {
  height: 3px;
  border-radius: 999px;
  background: var(--line);
  margin-top: 6px;
  overflow: hidden;
}
.lib-item .bar i { display: block; height: 100%; background: var(--accent); }
.lib-item .del { color: var(--dim); padding: 6px; border-radius: 8px; flex: none; }
.lib-item .del:hover { color: var(--accent); background: var(--panel-2); }

.empty { color: var(--dim); font-size: 13px; text-align: center; padding: 26px 0; }

kbd {
  font-family: var(--mono);
  font-size: 11px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 5px;
  padding: 1px 5px;
  color: var(--text-2);
  background: var(--bg-soft);
  white-space: nowrap;
}

.keys {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 7px 12px;
  align-items: center;
  font-size: 12.5px;
  color: var(--text-2);
}

/* ---------------------------------------------------------------- toasts */

.toast {
  position: fixed;
  left: 50%;
  bottom: 22px;
  transform: translate(-50%, 14px);
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--text);
  padding: 9px 15px;
  border-radius: 10px;
  font-size: 13px;
  z-index: var(--z-toast);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s, transform 0.18s;
  max-width: 88vw;
  text-align: center;
}

.toast.show { opacity: 1; transform: translate(-50%, 0); }

.loading {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 14px;
  background: rgba(8, 9, 11, 0.86);
  z-index: var(--z-loading);
  color: var(--text-2);
  font-size: 13.5px;
}

:root[data-theme="light"] .loading { background: rgba(247, 247, 245, 0.9); }
.loading.show { display: flex; }

.spinner {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2px solid var(--line);
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ----------------------------------------------------------------- small */

/* The header labels come off well before the phone breakpoint, because the
   width they need depends on the language. Measured with the real strings in
   place: English and Spanish need 644px of bar, German 646px, French 660px.
   Hiding them only below 560px left French clipped across the whole tablet
   range. 700px covers every language with room to spare, and the icons keep
   their tooltips. */
@media (max-width: 700px) {
  .icon-btn .txt { display: none; }
  .icon-btn { min-width: 38px; padding: 0 8px; }
}

@media (max-width: 560px) {
  header.top { padding: 9px 12px; gap: 8px; }
  .doc-name { display: none; }
  .controls { padding: 10px 8px 12px; gap: 10px; }
  .stage { min-height: 34svh; gap: 14px; }
  .transport { gap: 5px; }
  .tbtn { min-width: 43px; height: 44px; padding: 0 3px; border-radius: 10px; }
  .tbtn.play { min-width: 54px; }
  .tbtn .lbl { font-size: 9px; letter-spacing: 0.04em; }
  .dials { gap: 8px 12px; }
  .dial { gap: 7px; }
  .dial input[type="range"] { width: clamp(130px, 42vw, 220px); }
  .context { font-size: 15px; padding: 12px 14px 20px; max-height: 34svh; }
  .icon-btn .txt { display: none; }
  .icon-btn { min-width: 38px; padding: 0 8px; }
}

/* The header is a width budget, and adding the speed test made it a sixth
   button. At 375px that came to 405px of content in a 375px bar and clipped
   the help button clean off the right edge. The wordmark is the cheapest
   thing to give up: the mark still says whose app this is, and every button
   is something you cannot do any other way once a document is open. */
@media (max-width: 430px) {
  header.top { padding: 9px 10px; gap: 6px; }
  .top-actions { gap: 4px; }
  .brand span { display: none; }
  .icon-btn { min-width: 36px; padding: 0 6px; }
}

@media (min-width: 900px) {
  .stage { min-height: 48svh; }
}

[hidden] { display: none !important; }


/* ---------------------------------------------------------------- browse */

.intro .or {
  color: var(--dim);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.browse {
  position: fixed;
  inset: 0;
  z-index: var(--z-panel);
  background: var(--bg);
  display: flex;
  flex-direction: column;
}

.browse .bhead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 13px 18px;
  border-bottom: 1px solid var(--line-soft);
}

.browse .bhead strong { font-size: 15px; font-weight: 650; display: block; }
.browse .bsub { font-size: 12px; color: var(--dim); }

.bbar {
  display: flex;
  gap: 10px;
  padding: 12px 18px 0;
}

.bbar input[type="search"] {
  flex: 1;
  height: 40px;
  border-radius: 11px;
  border: 1px solid var(--line);
  background: var(--bg-soft);
  padding: 0 14px;
  font-size: 14px;
  min-width: 0;
}

.bbar input[type="search"]::placeholder { color: var(--dim); }
.bbar select.mini { height: 40px; flex: none; }

.chips {
  display: flex;
  gap: 7px;
  overflow-x: auto;
  padding: 12px 18px;
  scrollbar-width: none;
  /* fade the right edge so it reads as a scrollable row */
  mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 34px), transparent 100%);
  -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 34px), transparent 100%);
}

.chips::-webkit-scrollbar { display: none; }

.chips button {
  flex: none;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 13px;
  font-size: 12.5px;
  color: var(--text-2);
  background: var(--panel);
  white-space: nowrap;
}

.chips button:hover { background: var(--panel-2); color: var(--text); }
.chips button[aria-pressed="true"] {
  background: var(--text);
  color: var(--bg);
  border-color: transparent;
  font-weight: 600;
}

.bbody {
  flex: 1;
  overflow: auto;
  padding: 4px 18px 40px;
}

.bgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: 20px 16px;
}

.book {
  display: flex;
  flex-direction: column;
  gap: 8px;
  text-align: left;
  border-radius: 10px;
}

.book .cov {
  position: relative;
  display: block;
  aspect-ratio: 2 / 3;
  border-radius: 8px;
  overflow: hidden;
  background: var(--panel-2);
  border: 1px solid var(--line-soft);
  transition: border-color 0.15s, transform 0.15s;
}

.book:hover .cov { border-color: var(--accent); transform: translateY(-2px); }
/* Positioned, because .fallback below is absolute and would otherwise paint
   over the cover: a positioned element beats a static sibling no matter which
   one comes later in the DOM. The covers were downloading fine and sitting
   underneath the title card. */
.book .cov img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.book .cov .fallback {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  padding: 14px 12px;
  font-family: var(--serif);
  font-size: 14px;
  line-height: 1.3;
  color: var(--text-2);
  background: linear-gradient(160deg, var(--panel-2), var(--panel));
}

.book .bt {
  font-size: 13px;
  font-weight: 580;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.book .ba { font-size: 11.5px; color: var(--dim); line-height: 1.3; }

.bnote {
  color: var(--dim);
  font-size: 13px;
  text-align: center;
  padding: 26px 0 0;
  line-height: 1.6;
}

.bmore { display: flex; justify-content: center; padding: 24px 0 0; }

.bfoot {
  border-top: 1px solid var(--line-soft);
  padding: 11px 18px;
  font-size: 11.5px;
  color: var(--dim);
  line-height: 1.5;
}

.bfoot a { color: var(--text-2); }

.skel {
  border-radius: 8px;
  background: linear-gradient(90deg, var(--panel) 25%, var(--panel-2) 50%, var(--panel) 75%);
  background-size: 300% 100%;
  animation: shimmer 1.3s linear infinite;
  aspect-ratio: 2 / 3;
}

@keyframes shimmer { to { background-position: -300% 0; } }

.source-link {
  color: var(--dim);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
}

.source-link:hover { color: var(--text-2); }

@media (max-width: 560px) {
  .browse .bhead, .bbar, .chips, .bbody, .bfoot { padding-left: 14px; padding-right: 14px; }
  .bgrid { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 16px 12px; }
  .browse .bsub { display: none; }
}

/* ===================================================== the speed test */

.stest {
  position: fixed;
  inset: 0;
  z-index: calc(var(--z-panel) + 1);
  background: var(--bg);
  display: flex;
  flex-direction: column;
}

/* The hidden attribute alone loses to the display above. */
.stest[hidden] { display: none; }
.stest [hidden] { display: none !important; }

.stest .sthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 13px 18px;
  border-bottom: 1px solid var(--line-soft);
}

.stest .sthead strong { font-size: 15px; font-weight: 650; display: block; }
.stest .stsub { font-size: 12px; color: var(--dim); }

.stbody {
  flex: 1;
  overflow: auto;
  padding: 22px 18px 60px;
  max-width: 760px;
  width: 100%;
  margin: 0 auto;
}

.st-lede { color: var(--text-2); font-size: 14.5px; margin: 0 0 22px; max-width: 58ch; }
.st-h { font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--dim); margin: 0 0 12px; font-weight: 650; }
.st-fine { color: var(--dim); font-size: 12.5px; margin: 26px 0 0; max-width: 58ch; }

/* ------------------------------------------------------- passage picker */

.st-picks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;
}

.st-pick {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  text-align: left;
  padding: 16px;
  border-radius: var(--radius);
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--text);
  cursor: pointer;
  transition: border-color 0.15s, transform 0.15s, background 0.15s;
}

.st-pick:hover { border-color: var(--accent); background: var(--panel-2); transform: translateY(-2px); }
.st-kind { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent); font-weight: 650; }
.st-name { font-family: var(--serif); font-size: 19px; line-height: 1.2; }
.st-note { font-size: 13px; color: var(--text-2); }
.st-count { font-size: 12px; color: var(--dim); font-variant-numeric: tabular-nums; margin-top: 2px; }

/* ------------------------------------------------------------- reading */

.st-readbar {
  position: sticky;
  top: 0;
  z-index: var(--z-context);
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 4px 0 14px;
  background: linear-gradient(var(--bg) 70%, transparent);
}

.st-clock {
  font-family: var(--mono);
  font-size: 22px;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}

.st-hint { font-size: 13px; color: var(--dim); }

.st-passage {
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1.62;
  color: var(--text);
  max-width: 62ch;
}

.st-passage p { margin: 0 0 1.05em; }
.st-ptitle { font-size: 24px; line-height: 1.2; margin: 0 0 0.8em; font-weight: 600; }

.st-done { margin-top: 24px; }

/* ----------------------------------------------------------- questions */

.st-q { margin: 0 0 26px; }
.st-qtext { font-size: 16px; line-height: 1.45; margin: 0 0 10px; }

.st-opts { display: grid; gap: 8px; }

.st-opt {
  text-align: left;
  padding: 11px 14px;
  border-radius: 10px;
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--text-2);
  font-size: 14.5px;
  cursor: pointer;
  transition: border-color 0.12s, color 0.12s, background 0.12s;
}

.st-opt:hover { border-color: var(--text-2); color: var(--text); }
.st-opt.on { border-color: var(--accent); background: var(--accent-soft); color: var(--text); font-weight: 550; }

.btn:disabled { opacity: 0.4; cursor: default; }

/* --------------------------------------------------------------- score */

.st-hero { text-align: center; padding: 18px 0 26px; }

.st-big {
  font-size: clamp(64px, 18vw, 108px);
  line-height: 0.95;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.st-bigsub { font-size: 14px; color: var(--text-2); margin-top: 8px; }

.st-band {
  display: inline-block;
  margin-top: 14px;
  padding: 5px 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--panel);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-weight: 650;
  color: var(--text-2);
}

.st-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  overflow: hidden;
}

.st-stat { background: var(--panel); padding: 14px 16px; display: flex; flex-direction: column; gap: 3px; }
.st-statk { font-size: 11.5px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--dim); }
.st-statv { font-size: 17px; font-variant-numeric: tabular-nums; }

.st-verdict {
  margin: 22px 0 0;
  padding: 16px 18px;
  border-left: 2px solid var(--accent);
  background: var(--panel);
  border-radius: 0 10px 10px 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--text-2);
  max-width: 62ch;
}

.st-review { margin-top: 30px; }

.st-rev {
  display: flex;
  gap: 12px;
  padding: 11px 0;
  border-top: 1px solid var(--line-soft);
  font-size: 14px;
}

.st-mark { flex: none; width: 18px; font-weight: 700; }
.st-rev.ok .st-mark { color: var(--ok); }
.st-rev.no .st-mark { color: var(--accent); }
.st-revtext { display: flex; flex-direction: column; gap: 3px; }
.st-revq { color: var(--text); }
.st-reva { color: var(--dim); font-size: 13px; }
.st-revc { color: var(--ok); font-size: 13px; }

.st-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 30px; }

@media (max-width: 560px) {
  .stest .sthead, .stbody { padding-left: 14px; padding-right: 14px; }
  .stest .stsub { display: none; }
  .st-passage { font-size: 17px; }
  .st-actions .btn { width: 100%; }
}

/* ================================================== the 2026-09-14 pass

   Depth, texture and motion. Everything here is additive: no layout rule
   above was moved, so nothing that worked can stop working. */

/* ------------------------------------------------------------ grain

   A flat dark ground looks like an unfinished mockup. One fixed, non
   interactive noise layer at very low opacity breaks the flatness without
   anyone consciously noticing it. Inline SVG so it costs no request and
   cannot be blocked by the CSP. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  opacity: 0.032;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

:root[data-theme="light"] body::after,
body[data-theme="light"]::after { opacity: 0.022; }

/* While reading, the grain goes. Nothing should sit between the eye and the
   word it is trying to catch. */
body.is-playing::after { opacity: 0; transition: opacity 0.25s; }

/* ------------------------------------------------- elevation and edges */

.drawer { box-shadow: var(--shadow-3); }
.toast { box-shadow: var(--shadow-2); }
.loading .spinner { will-change: transform; }

.book .cov { box-shadow: var(--shadow-1); }
.book:hover .cov { box-shadow: var(--shadow-2); }

.st-pick { box-shadow: var(--shadow-1); }
.st-pick:hover { box-shadow: var(--shadow-2); }
.st-pick:active { transform: translateY(0) scale(0.99); }

.st-opt:active { transform: scale(0.995); }
.st-stats { box-shadow: var(--shadow-1); }

/* The header earns a hairline of its own once the page is scrolled under it,
   rather than sitting on the content with nothing between them. */
header.top { box-shadow: 0 1px 0 var(--line-soft); }

/* --------------------------------------------------------------- motion */

html { scroll-behavior: smooth; }

@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* Staggered rather than everything arriving at once, which is the tell of a
   page that was never art directed. Three steps is enough to read as
   deliberate without making anyone wait. */
.intro > div:first-child { animation: rise 0.5s cubic-bezier(0.22, 1, 0.36, 1) both; }
.intro .dropzone { animation: rise 0.5s 0.07s cubic-bezier(0.22, 1, 0.36, 1) both; }
.intro .paste-wrap { animation: rise 0.5s 0.13s cubic-bezier(0.22, 1, 0.36, 1) both; }
.intro .privacy { animation: rise 0.5s 0.19s cubic-bezier(0.22, 1, 0.36, 1) both; }

.st-hero .st-big { animation: rise 0.45s cubic-bezier(0.22, 1, 0.36, 1) both; }
.st-hero .st-band { animation: rise 0.45s 0.1s cubic-bezier(0.22, 1, 0.36, 1) both; }

/* Everything above is decoration. Anyone who has asked their system to stop
   moving things gets none of it, including the smooth scroll. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* ----------------------------------------------------------- typography */

/* Tabular figures everywhere a number changes in place, so the layout stops
   twitching as the count climbs. */
.stage-meta, .lib-item .s, .st-count { font-variant-numeric: tabular-nums; }

/* A touch more weight range than Regular and Bold, now that the face has it. */
.drawer header span, .bhead strong, .sthead strong { font-weight: 600; letter-spacing: -0.01em; }
.intro .lede, .privacy { font-weight: 350; }

/* ================================================== score, rank, badges

   Two surfaces. The card that appears when a document is finished, and the
   shelf that sits at the top of the Library drawer.

   Nothing here knows anything about the server. Every number on screen is
   read out of this browser, apart from the referral count, which is a single
   integer fetched from our own domain. */

.scorecard {
  position: fixed;
  inset: 0;
  z-index: calc(var(--z-panel) + 2);
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(3, 4, 6, 0.62);
  backdrop-filter: blur(3px);
}

/* The hidden attribute alone loses to the display above, the same trap the
   speed test panel already carries. */
.scorecard[hidden] { display: none; }

:root[data-theme="light"] .scorecard { background: rgba(28, 26, 22, 0.34); }

.sc-panel {
  width: 100%;
  max-width: 420px;
  max-height: 92svh;
  overflow: auto;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 18px;
  box-shadow: var(--shadow-3);
  animation: scpop 0.24s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes scpop {
  from { opacity: 0; transform: translateY(10px) scale(0.985); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .sc-panel { animation: none; }
}

.sc-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--line-soft);
}

.sc-head strong { font-size: 15px; font-weight: 650; }

.sc-body { padding: 20px 18px 18px; }

.sc-hero { text-align: center; margin-bottom: 18px; }

.sc-big {
  font-family: var(--serif);
  font-size: 52px;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.sc-bigsub { font-size: 12.5px; color: var(--dim); margin-top: 6px; }

.sc-stats, .shelf-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: 18px;
}

.shelf-stats { grid-template-columns: repeat(4, 1fr); }

.sc-stat, .shelf-stat {
  background: var(--panel-2);
  padding: 11px 8px;
  text-align: center;
}

.sc-stat b, .shelf-stat b {
  display: block;
  font-size: 16px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.sc-stat span, .shelf-stat span {
  display: block;
  font-size: 10.5px;
  color: var(--dim);
  margin-top: 2px;
  line-height: 1.3;
}

.sc-rank { margin-bottom: 18px; }
.sc-rankname { font-size: 14px; font-weight: 650; margin-bottom: 7px; }
.sc-ranknext, .shelf-next { font-size: 12px; color: var(--dim); margin-top: 7px; }

.rank-bar {
  height: 6px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--line-soft);
  overflow: hidden;
}

.rank-bar i {
  display: block;
  height: 100%;
  background: var(--accent);
  border-radius: 999px;
  transition: width 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.sc-badgeshead {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dim);
  font-weight: 700;
  margin-bottom: 9px;
}

.sc-badgerow { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }

.sc-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 11px 7px 8px;
  border-radius: 10px;
  background: var(--accent-soft);
  border: 1px solid var(--line);
  font-size: 12.5px;
  font-weight: 600;
}

.sc-badge i { font-style: normal; color: var(--accent); font-size: 14px; line-height: 1; }

.sc-actions { display: flex; gap: 8px; justify-content: flex-end; }
.sc-actions .btn { font-size: 13.5px; padding: 9px 15px; }

/* ---------------------------------------------------------------- shelf */

#shelf {
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: var(--radius);
  padding: 15px 15px 16px;
  margin-bottom: 14px;
}

#shelf:empty { display: none; }

.shelf-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 9px;
}

.shelf-rank { font-family: var(--serif); font-size: 19px; font-weight: 600; letter-spacing: -0.015em; }
.shelf-points { font-size: 12px; color: var(--dim); font-variant-numeric: tabular-nums; }
.shelf-next { margin-bottom: 14px; }

.shelf-label {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dim);
  font-weight: 700;
  margin-bottom: 9px;
}

.badge-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
  gap: 7px;
  margin-bottom: 18px;
}

.badge {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  text-align: center;
  padding: 11px 5px 9px;
  border-radius: 11px;
  border: 1px solid var(--line-soft);
  background: var(--panel-2);
  cursor: default;
}

/* An unearned badge is shown rather than hidden, because the shelf is most
   useful when it tells you what is still on it. */
.badge i {
  font-style: normal;
  font-size: 19px;
  line-height: 1;
  color: var(--dim);
  opacity: 0.45;
}

.badge span { font-size: 10.5px; line-height: 1.25; color: var(--dim); }

.badge.on { border-color: var(--line); background: var(--accent-soft); }
.badge.on i { color: var(--accent); opacity: 1; }
.badge.on span { color: var(--text-2); font-weight: 600; }

.shelf-share { border-top: 1px solid var(--line-soft); padding-top: 14px; }
.shelf-note { font-size: 12.5px; color: var(--dim); margin: 0 0 11px; line-height: 1.55; }

.share-row { display: flex; gap: 7px; margin-bottom: 8px; }

.share-link {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 12.5px;
  font-family: var(--mono);
  padding: 8px 10px;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--text-2);
}

.shelf-share .btn { font-size: 12.5px; padding: 8px 13px; white-space: nowrap; }
.shelf-count { font-size: 12px; color: var(--dim); margin-top: 9px; font-variant-numeric: tabular-nums; }

@media (max-width: 420px) {
  .shelf-stats { grid-template-columns: repeat(2, 1fr); }
  .sc-big { font-size: 44px; }
  .share-row { flex-wrap: wrap; }
  .share-link { flex-basis: 100%; }
}
