:root {
  --bg: #f6f6f4;
  --surface: #ffffff;
  --surface-2: #efeeea;
  --border: #dedcd5;
  --text: #1c1b19;
  --text-dim: #6b6862;
  --accent: #b44a1e;
  --accent-soft: #fbeade;
  --danger: #b3261e;
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.06), 0 1px 3px rgb(0 0 0 / 0.04);
  --shadow-md: 0 4px 12px rgb(0 0 0 / 0.08), 0 2px 4px rgb(0 0 0 / 0.04);
  --shadow-lg: 0 12px 32px rgb(0 0 0 / 0.14), 0 4px 8px rgb(0 0 0 / 0.06);
  --radius: 10px;
  --toolbar-h: 52px;
  --font: ui-sans-serif, -apple-system, "Segoe UI", Inter, system-ui, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}

:root:not([data-theme="light"]) {
  @media (prefers-color-scheme: dark) {
    --bg: #17181a;
    --surface: #202225;
    --surface-2: #2a2d31;
    --border: #383c41;
    --text: #e9e7e3;
    --text-dim: #9a968f;
    --accent: #e8814f;
    --accent-soft: #3a2519;
    --danger: #f2837c;
    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);
    --shadow-md: 0 4px 12px rgb(0 0 0 / 0.45);
    --shadow-lg: 0 12px 32px rgb(0 0 0 / 0.55);
  }
}

:root[data-theme="dark"] {
  --bg: #17181a;
  --surface: #202225;
  --surface-2: #2a2d31;
  --border: #383c41;
  --text: #e9e7e3;
  --text-dim: #9a968f;
  --accent: #e8814f;
  --accent-soft: #3a2519;
  --danger: #f2837c;
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);
  --shadow-md: 0 4px 12px rgb(0 0 0 / 0.45);
  --shadow-lg: 0 12px 32px rgb(0 0 0 / 0.55);
}

* { box-sizing: border-box; }

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

button { font: inherit; color: inherit; cursor: pointer; }
svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* Our own `display` rules outrank the UA's [hidden] rule, so state it explicitly. */
[hidden] { display: none !important; }
.empty { color: var(--text-dim); font-size: 0.9rem; text-align: center; padding: 1.5rem 0; }

/* ------------------------------- library -------------------------------- */

#library {
  max-width: 780px;
  margin: 0 auto;
  padding: 3rem 16px 4rem;
}

/* Sits in the library's top padding, so it moves nothing when it appears. */
.account { display: flex; justify-content: flex-end; align-items: center; gap: 0.25rem; margin: -1.9rem 0 0.4rem; font-size: 0.8rem; color: var(--text-dim); min-width: 0; }
.account span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The button's own padding would otherwise push its text in from the column's edge. */
.account form { margin: 0 -0.5rem 0 0; flex: none; }

.library-header h1 { margin: 0 0 0.35rem; font-size: 1.75rem; letter-spacing: -0.02em; }
.subtitle { margin: 0 0 2rem; color: var(--text-dim); font-size: 0.95rem; }

#dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  padding: 2.5rem 1rem;
  border: 1.5px dashed var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  text-align: center;
  transition: border-color 0.15s, background 0.15s;
}
#dropzone:hover, #dropzone:focus-visible { border-color: var(--accent); background: var(--accent-soft); outline: none; }
#dropzone.dragover { border-color: var(--accent); background: var(--accent-soft); border-style: solid; }
#dropzone svg { width: 28px; height: 28px; color: var(--text-dim); margin-bottom: 0.4rem; }
#dropzone strong { font-size: 1rem; }
#dropzone span { color: var(--text-dim); font-size: 0.875rem; }

.upload-status {
  margin-top: 0.9rem;
  padding: 0.7rem 0.9rem;
  border-radius: 8px;
  font-size: 0.875rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.upload-status.error { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); }

.doc-list-wrap h2 { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-dim); margin: 2.5rem 0 0.75rem; }
.doc-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }

.doc-card {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.85rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color 0.15s, transform 0.08s, box-shadow 0.15s;
}
.doc-card:hover { border-color: var(--accent); box-shadow: var(--shadow-sm); }
.doc-card:active { transform: translateY(1px); }

.doc-icon { flex: none; width: 34px; height: 42px; border-radius: 4px; background: var(--accent-soft); color: var(--accent); display: grid; place-items: center; font-size: 0.6rem; font-weight: 700; letter-spacing: 0.04em; }
.doc-meta { flex: 1; min-width: 0; }
.doc-name { font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.doc-sub { font-size: 0.8rem; color: var(--text-dim); margin-top: 0.15rem; display: flex; gap: 0.5rem; flex-wrap: wrap; }
.doc-sub .resume { color: var(--accent); font-weight: 550; }

.progress-ring { flex: none; }
.delete-btn { flex: none; background: none; border: none; color: var(--text-dim); padding: 0.35rem; border-radius: 6px; opacity: 0; transition: opacity 0.15s, color 0.15s, background 0.15s; }
.doc-card:hover .delete-btn { opacity: 1; }
.delete-btn:hover { color: var(--danger); background: var(--surface-2); }

/* -------------------------------- sign-in -------------------------------- */
/* The page the server renders at /auth/login when AUTH=google. */

.signin { max-width: 400px; margin: 0 auto; padding: 18vh 16px 4rem; text-align: center; }
.signin h1 { margin: 0 0 0.35rem; font-size: 1.75rem; letter-spacing: -0.02em; }
.signin .subtitle { margin-bottom: 1.75rem; }
.signin-msg {
  margin: 0 0 1.25rem;
  padding: 0.7rem 0.9rem;
  border-radius: 8px;
  font-size: 0.875rem;
  line-height: 1.45;
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.signin-msg.error { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); }
.signin-btn {
  display: inline-block;
  padding: 0.65rem 1.3rem;
  border-radius: 8px;
  background: var(--accent); color: #fff;
  font-size: 0.95rem; font-weight: 550;
  text-decoration: none;
  box-shadow: var(--shadow-sm);
}
.signin-btn:hover { filter: brightness(1.08); }
.signin-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

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

#reader { display: flex; flex-direction: column; height: 100%; }

.toolbar {
  flex: none;
  height: var(--toolbar-h);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0 0.6rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  z-index: 20;
}

.icon-btn {
  display: grid;
  place-items: center;
  width: 32px; height: 32px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--text-dim);
  transition: background 0.12s, color 0.12s;
}
.icon-btn:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }
.icon-btn:disabled { opacity: 0.35; cursor: default; }
.icon-btn.active { color: var(--accent); }

.doc-title { flex: 1; min-width: 0; margin: 0; font-size: 0.925rem; font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.toolbar-group { display: flex; align-items: center; gap: 0.15rem; background: var(--surface-2); border-radius: 8px; padding: 2px; }
.page-indicator { display: flex; align-items: center; gap: 0.3rem; font-size: 0.85rem; color: var(--text-dim); padding: 0 0.2rem; }
#page-input {
  width: 3.6em; padding: 0.2rem 0.3rem; text-align: right;
  border: 1px solid transparent; border-radius: 5px;
  background: var(--surface); color: var(--text); font: inherit; font-size: 0.85rem;
  -moz-appearance: textfield;
}
#page-input::-webkit-inner-spin-button, #page-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
#page-input:focus { border-color: var(--accent); outline: none; }
.page-physical { font-size: 0.75rem; opacity: 0.8; font-variant-numeric: tabular-nums; white-space: nowrap; }
.zoom-level { font-size: 0.78rem; color: var(--text-dim); min-width: 3.5em; text-align: center; font-variant-numeric: tabular-nums; }

.save-badge {
  position: fixed; top: calc(var(--toolbar-h) + 10px); left: 50%; transform: translateX(-50%);
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow-md);
  padding: 0.3rem 0.75rem; border-radius: 999px; font-size: 0.75rem; color: var(--text-dim);
  z-index: 30; pointer-events: none; animation: fade-in-out 1.6s ease forwards;
}
@keyframes fade-in-out {
  0% { opacity: 0; transform: translate(-50%, -6px); }
  15%, 65% { opacity: 1; transform: translate(-50%, 0); }
  100% { opacity: 0; transform: translate(-50%, -4px); }
}

/* Outline on the left, pages on the right. The outline pushes the pages over rather
   than covering them; pages are sized by zoom, not width, so nothing reflows. */
.reader-body { flex: 1; min-height: 0; display: flex; }

.outline {
  flex: none;
  width: 280px;
  display: flex; flex-direction: column;
  background: var(--surface);
  border-right: 1px solid var(--border);
  z-index: 10;
}
.outline-head {
  flex: none;
  padding: 0.7rem 0.9rem 0.5rem;
  font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim);
}
.outline-tree, .outline-tree ul { list-style: none; margin: 0; padding: 0; }
.outline-tree { flex: 1; overflow-y: auto; padding: 0 0.4rem 1.5rem; overscroll-behavior: contain; }
.outline-tree ul { padding-left: 0.85rem; }
.outline-row { display: flex; align-items: flex-start; gap: 0.1rem; border-radius: 6px; }
.outline-row:hover { background: var(--surface-2); }
.outline-row.active { background: var(--accent-soft); }
.outline-row.active .outline-link { color: var(--accent); font-weight: 550; }
.outline-toggle, .outline-spacer { flex: none; width: 20px; height: 26px; }
.outline-toggle {
  display: grid; place-items: center; padding: 0;
  border: none; background: none; color: var(--text-dim); border-radius: 5px;
}
.outline-toggle:hover { color: var(--text); }
.outline-toggle svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 2.4; transition: transform 0.12s; }
.outline-item[aria-expanded="true"] > .outline-row .outline-toggle svg { transform: rotate(90deg); }
.outline-item[aria-expanded="false"] > ul { display: none; }
.outline-link {
  flex: 1; min-width: 0;
  display: flex; align-items: baseline; gap: 0.5rem;
  padding: 0.3rem 0.4rem 0.3rem 0.1rem;
  border: none; background: none; text-align: left;
  font: inherit; font-size: 0.82rem; line-height: 1.3; color: var(--text);
}
.outline-tree > .outline-item > .outline-row .outline-link { font-weight: 550; }
.outline-title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.outline-page { flex: none; font-size: 0.72rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.outline-link:focus-visible, .outline-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.viewer-container {
  flex: 1;
  min-width: 0;
  overflow: auto;
  position: relative;
  padding: 1.25rem 0 3rem;
  scroll-behavior: auto;
  /* Pinch-to-zoom is handled in JS and applied to the pages, not the page. */
  touch-action: pan-x pan-y;
}
.viewer {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  /* `safe` keeps a page wider than the window from being clipped past the left
     edge, where centring would otherwise put it out of scroll reach. */
  align-items: center;
  align-items: safe center;
  width: fit-content;
  min-width: 100%;
  padding: 0 1.25rem;
}

.page {
  position: relative;
  background: #fff;
  box-shadow: var(--shadow-md);
  border-radius: 2px;
  overflow: hidden;
  flex: none;
  /* Size comes from the page's own unscaled dimensions times the viewer's zoom,
     so a pinch resizes every page by setting one variable. */
  width: calc(var(--base-w, 612) * var(--zoom, 1) * 1px);
  height: calc(var(--base-h, 792) * var(--zoom, 1) * 1px);
  /* Ink multiplies into the page; this keeps the blend inside the sheet. */
  isolation: isolate;
}
/* Holds the canvas and text layer together so one transform scales both during a pinch,
   keeping the selectable text lined up with the glyphs while the gesture is in flight. */
.page-inner {
  position: relative;
  transform-origin: 0 0;
  transform: scale(var(--zoom-ratio, 1));
  will-change: transform;
}
.page canvas { display: block; }
.page .textLayer { z-index: 2; }
.page .textLayer ::selection { background: color-mix(in srgb, var(--accent) 35%, transparent); }
/* Sits above the canvas but below the text layer (z-index 2), so the words stay
   selectable and the mark reads as part of the page rather than on top of it. */
.lookup-highlight {
  position: absolute;
  z-index: 1;
  border-radius: 2px;
  pointer-events: none;
  background: color-mix(in srgb, var(--accent) 28%, transparent);
  animation: lookup-found 1.4s ease-out;
}
@keyframes lookup-found {
  0%   { background: color-mix(in srgb, var(--accent) 85%, transparent); }
  30%  { background: color-mix(in srgb, var(--accent) 70%, transparent); }
  100% { background: color-mix(in srgb, var(--accent) 28%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .lookup-highlight { animation: none; }
}

.page-number-tag {
  position: absolute; bottom: 6px; right: 8px; z-index: 3;
  font-size: 0.68rem; color: #999; background: rgb(255 255 255 / 0.85);
  padding: 1px 6px; border-radius: 4px; pointer-events: none; user-select: none;
}
/* Dark pages: invert the rendered page, then rotate hues back so photos and coloured
   figures keep roughly their own colours. Stopping short of a full invert lands paper
   on a soft charcoal rather than pure black. Only the canvas is filtered, so the text
   layer, selection and lookup highlight keep their normal colours. */
#reader.pages-dark .page { background: #1d1d1d; }
#reader.pages-dark .page canvas { filter: invert(0.9) hue-rotate(180deg); }
#reader.pages-dark .page-number-tag { color: #aaa; background: rgb(0 0 0 / 0.6); }
.page.placeholder { display: grid; place-items: center; background: var(--surface-2); box-shadow: none; border: 1px solid var(--border); }
.page.placeholder::after { content: ""; width: 22px; height: 22px; border: 2px solid var(--border); border-top-color: var(--text-dim); border-radius: 50%; animation: spin 0.7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

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

/* One pill for the whole document, moved by transform from tracker.js. It sits above
   the pages but lets every click through, and multiplies so the glyphs stay crisp. */
.tracker-marker {
  position: absolute;
  top: 0; left: 0;
  z-index: 3;
  width: 0; height: 0;
  border-radius: 0.4em;
  pointer-events: none;
  background: color-mix(in srgb, var(--accent) 34%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent);
  mix-blend-mode: multiply;
  transform-origin: 50% 50%;
  will-change: transform, width, height;
  opacity: 0;
  transition: opacity 0.25s ease;
}
.tracker-marker.visible { opacity: 1; }
#reader.pages-dark .tracker-marker {
  background: color-mix(in srgb, var(--accent) 45%, transparent);
  mix-blend-mode: screen;
}
/* Clicking picks a word, so say so. */
#reader.tracking .page .textLayer { cursor: pointer; }

.tracker-bar, .draw-bar {
  position: fixed;
  left: 50%; bottom: 20px;
  z-index: 30;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 0.25rem;
  padding: 0.3rem 0.45rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: var(--shadow-lg);
  animation: tracker-bar-in 0.32s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes tracker-bar-in {
  from { opacity: 0; transform: translate(-50%, 14px) scale(0.94); }
  to   { opacity: 1; transform: translate(-50%, 0) scale(1); }
}
.tracker-play { background: var(--accent); color: #fff; border-radius: 999px; }
.tracker-play:hover:not(:disabled) { background: var(--accent); color: #fff; filter: brightness(1.08); }
.tracker-play .icon-play { fill: currentColor; stroke: none; }
.tracker-play .icon-pause, .tracker-play.playing .icon-play { display: none; }
.tracker-play.playing .icon-pause { display: block; }
.tracker-voice-pick {
  font: inherit; font-size: 0.78rem; color: var(--text); background: var(--surface-2);
  border: 0; border-radius: 7px; padding: 0.3rem 0.4rem; max-width: 9.5rem; cursor: pointer;
}
.tracker-voice-pick:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Waiting on the voice: the speaker breathes until the sound starts. */
.icon-btn.busy svg { animation: voice-busy 1.1s ease-in-out infinite; }
@keyframes voice-busy { 50% { opacity: 0.35; } }
.tracker-hint { font-size: 0.75rem; color: var(--text-dim); padding: 0 0.35rem; white-space: nowrap; }
.tracker-speed { width: 120px; accent-color: var(--accent); }
.tracker-wpm { font-size: 0.78rem; color: var(--text-dim); min-width: 5.2em; text-align: center; font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) {
  .tracker-bar, .draw-bar { animation: none; }
  .icon-btn.busy svg { animation: none; opacity: 0.6; }
}
@media (max-width: 640px) {
  .tracker-bar, .draw-bar { left: 16px; right: 16px; bottom: 12px; transform: none; justify-content: space-between; }
  @keyframes tracker-bar-in { from { opacity: 0; } to { opacity: 1; } }
  .tracker-speed { flex: 1; min-width: 0; width: auto; }
  .tracker-hint { display: none; }
  .tracker-voice-pick { display: none; }
}

/* ---------------------------------- ink ---------------------------------- */

/* Ink lies over the page and multiplies into it, so a highlighter tints the paper
   without greying the words, and black ink stays black. On dark pages ink.js turns the
   colours the way the canvas filter turns the page, and the blend becomes screen. The
   layer ignores the pointer unless the pen is out, so reading and selecting are as before. */
.ink-layer { fill: none; stroke: none; } /* the global svg rule would outline every stroke */
.page .ink-layer {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  pointer-events: none;
  mix-blend-mode: multiply;
}
#reader.pages-dark .ink-layer { mix-blend-mode: screen; }
#reader.drawing .page .ink-layer,
.pad-sheet .ink-layer {
  pointer-events: auto;
  touch-action: none; /* a finger or pen on the sheet draws rather than scrolls */
  cursor: crosshair;
}
/* The circle is the eraser's reach: ERASER_PX in ink.js. */
#reader.erasing .ink-layer {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18'%3E%3Ccircle cx='9' cy='9' r='8' fill='%23fff' fill-opacity='.55' stroke='%23555' stroke-width='1.2'/%3E%3C/svg%3E") 9 9, cell;
}
#reader.drawing .page { -webkit-user-select: none; user-select: none; }

/* Above the scratch pad, which reaches the bottom of the screen on a phone. */
.draw-bar { z-index: 45; }
/* Both bars at once: the drawing tools sit above the tracker's. */
#reader.tracking .draw-bar { bottom: 76px; }
.bar-sep { flex: none; width: 1px; height: 20px; margin: 0 0.2rem; background: var(--border); }
.draw-swatches { display: flex; align-items: center; gap: 0.1rem; }
.draw-swatch {
  display: grid; place-items: center;
  width: 26px; height: 26px; padding: 0;
  border: none; border-radius: 50%; background: transparent;
}
.draw-swatch::after {
  content: "";
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--swatch);
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.18);
}
.draw-swatch[aria-checked="true"]::after { box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--text); }
.draw-swatch:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.draw-size .size-dot { display: block; width: var(--dot, 7px); height: var(--dot, 7px); border-radius: 50%; background: currentColor; }
.draw-size[data-size="fine"] { --dot: 4px; }
.draw-size[data-size="bold"] { --dot: 11px; }
.draw-status {
  min-width: 4.2em; max-width: 15rem; padding: 0 0.35rem;
  font-size: 0.75rem; line-height: 1.25; color: var(--text-dim);
}
.draw-status:empty { min-width: 0; padding: 0; }
.draw-status.problem { color: var(--danger); }

/* The scratch pad pushes the pages over from the right, as the outline does from the left. */
#reader { --pad-w: min(400px, 36vw); }
.pad {
  flex: none;
  width: var(--pad-w);
  display: flex; flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--border);
  z-index: 10;
}
.pad-head {
  flex: none;
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  padding: 0.35rem 0.4rem 0.35rem 0.9rem;
  font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim);
}
.pad-head .text-btn { text-transform: none; letter-spacing: normal; }
.pad-scroll {
  flex: 1; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  padding: 0 0.75rem 0.75rem;
}
.pad-sheet {
  background: #fff;
  border-radius: 2px;
  box-shadow: var(--shadow-md);
  isolation: isolate;
}
/* Its height follows its viewBox, which ink.js grows as the notes do. */
.pad-sheet .ink-layer { display: block; width: 100%; height: auto; mix-blend-mode: multiply; }
#reader.pages-dark .pad-sheet { background: #1d1d1d; }
#reader.pages-dark .pad-sheet .ink-layer { mix-blend-mode: screen; }

@media (min-width: 641px) {
  /* What floats in the right-hand corner moves aside for the pad. */
  #reader.pad-open .panel,
  #reader.pad-open .history,
  #reader.pad-open .recaps,
  #reader.pad-open .recap-range { right: calc(var(--pad-w) + 16px); }
  #reader.pad-open .draw-bar { left: calc((100% - var(--pad-w)) / 2); }
}
@media (max-width: 640px) {
  .pad {
    position: fixed; top: var(--toolbar-h); bottom: 0; right: 0;
    width: min(340px, 88vw);
    box-shadow: var(--shadow-lg);
    z-index: 40;
  }
  .pad-scroll { padding-bottom: 76px; } /* room to write above the drawing tools */
  .bar-sep, .draw-status:not(.problem) { display: none; }
  .draw-swatch { width: 22px; }
}

/* ---------------------------- selection actions ---------------------------- */

/* The wrapper is what gets positioned; the buttons inside keep their own `hidden`. */
.sel-actions {
  position: fixed;
  z-index: 40;
  display: flex; align-items: center; gap: 0.35rem;
}

.explain-btn {
  display: flex; align-items: center; gap: 0.4rem;
  padding: 0.42rem 0.75rem;
  border: none; border-radius: 999px;
  background: var(--accent); color: #fff;
  font-size: 0.8rem; font-weight: 550;
  box-shadow: var(--shadow-lg);
  white-space: nowrap;
  animation: pop 0.12s ease;
}
.explain-btn svg { width: 14px; height: 14px; fill: currentColor; stroke: none; }
.explain-btn:hover { filter: brightness(1.08); }
@keyframes pop { from { opacity: 0; transform: scale(0.92); } to { opacity: 1; transform: scale(1); } }

/* The second action is the quieter of the two — a recap is the bigger commitment. */
.recap-here, .mindmap-here {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
}
.recap-here svg, .mindmap-here svg { fill: none; stroke: currentColor; stroke-width: 2; }

/* ------------------------------ recap range ------------------------------ */

.recap-range {
  position: fixed;
  top: calc(var(--toolbar-h) + 8px);
  right: 16px;
  z-index: 55;
  width: min(300px, calc(100vw - 32px));
  display: flex; flex-direction: column; gap: 0.6rem;
  padding: 0.8rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  animation: slide-up 0.16s ease;
}
.recap-range-row { display: flex; gap: 0.6rem; }
.recap-range-row label {
  flex: 1;
  display: flex; flex-direction: column; gap: 0.25rem;
  font-size: 0.72rem; color: var(--text-dim);
}
.recap-range-row input {
  width: 100%;
  padding: 0.3rem 0.4rem;
  font: inherit; font-size: 0.85rem;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.recap-range-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.recap-go {
  padding: 0.4rem 0.8rem;
  border: none; border-radius: 8px;
  background: var(--accent); color: #fff;
  font-size: 0.82rem; font-weight: 550;
}
.recap-go:hover { filter: brightness(1.08); }
.recap-go:disabled { opacity: 0.55; }
.recap-cut {
  margin: 0;
  font-size: 0.75rem; font-style: italic; color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* -------------------------------- panels -------------------------------- */

.panel, .history, .recaps {
  position: fixed; right: 16px; bottom: 16px;
  width: min(400px, calc(100vw - 32px));
  max-height: min(65vh, 620px);
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  z-index: 50;
  overflow: hidden;
  animation: slide-up 0.16s ease;
}
@keyframes slide-up { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

.panel-head {
  flex: none;
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  padding: 0.55rem 0.6rem 0.55rem 0.9rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.875rem;
}
.kind-chip {
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600;
  color: var(--accent); background: var(--accent-soft);
  padding: 0.18rem 0.5rem; border-radius: 999px;
}
.panel-body { padding: 0.9rem; overflow-y: auto; font-size: 0.9rem; line-height: 1.55; }

.panel-headline { margin: 0 0 0.15rem; font-size: 1.1rem; font-weight: 600; letter-spacing: -0.01em; }
.panel-selection { margin: 0 0 0.85rem; font-size: 0.78rem; color: var(--text-dim); font-style: italic; border-left: 2px solid var(--border); padding-left: 0.6rem; max-height: 4.2em; overflow: hidden; }
.panel-section { margin-bottom: 0.85rem; }
.panel-section:last-child { margin-bottom: 0; }
.panel-label { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); font-weight: 600; margin-bottom: 0.2rem; }
.panel-section p { margin: 0; }
.detail-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.detail-list li { display: grid; grid-template-columns: minmax(70px, auto) 1fr; gap: 0.6rem; font-size: 0.85rem; }
.detail-list .detail-label { color: var(--text-dim); }

.meaning-figure { margin: 0.7rem 0 0; animation: fade-in 0.25s ease; }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.meaning-image {
  display: block;
  width: 100%;
  max-height: 220px;
  object-fit: contain;
  border-radius: 8px;
  border: 1px solid var(--border);
  /* Many encyclopaedia diagrams are transparent PNGs drawn in black ink, which
     disappear on a dark panel — so the picture keeps its own light backing. */
  background: #fff;
}

.meaning-figure figcaption {
  margin-top: 0.3rem;
  font-size: 0.7rem;
  color: var(--text-dim);
  line-height: 1.35;
}
.meaning-figure figcaption a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.meaning-figure figcaption a:hover { color: var(--accent); }

.panel-loading { display: flex; align-items: center; gap: 0.6rem; color: var(--text-dim); padding: 0.4rem 0; }
.panel-loading::before { content: ""; width: 15px; height: 15px; border: 2px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.7s linear infinite; flex: none; }
.panel-error { color: var(--danger); }
.panel-error .hint { display: block; margin-top: 0.4rem; color: var(--text-dim); font-size: 0.8rem; }
.panel-error code { font-family: var(--mono); font-size: 0.78rem; background: var(--surface-2); padding: 0.1rem 0.3rem; border-radius: 4px; }
.cached-note { font-size: 0.7rem; color: var(--text-dim); margin-top: 0.7rem; }

/* -------------------------------- recap ---------------------------------- */

.recap-points { list-style: disc; margin: 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: 0.35rem; }
.recap-points li { font-size: 0.87rem; }

/* A page reference sits inline in the text, so it reads as part of the sentence. */
.page-ref {
  border: none; background: transparent;
  padding: 0 0.1rem;
  font: inherit; font-size: 0.78em;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.page-ref:hover { filter: brightness(1.15); }

.recap-diagram svg { display: block; width: 100%; height: auto; }
/* The global rule up top strokes every svg; labels are text and must not be outlined. */
.recap-diagram svg text { stroke: none; stroke-width: 0; }
.recap-diagram .dg-label { font-size: 13px; font-weight: 550; fill: var(--text); }
.recap-diagram .dg-page  { font-size: 10px; fill: var(--text-dim); }
.recap-diagram .dg-edge  { font-size: 11px; fill: var(--text-dim); }
.recap-diagram .dg-node-link { cursor: pointer; }
.recap-diagram .dg-node-link:hover .dg-label { fill: var(--accent); }
.recap-diagram .dg-node-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Mind map: the panel widens so the two sides have room. */
.panel.panel-wide { width: min(720px, calc(100vw - 32px)); max-height: min(80vh, 760px); }
.mindmap svg { display: block; width: 100%; height: auto; }
.mindmap svg text { stroke: none; stroke-width: 0; }
.mindmap .mm-root-label   { font-size: 14px; font-weight: 650; fill: var(--text); }
.mindmap .mm-branch-label { font-size: 12.5px; font-weight: 550; fill: var(--text); }
.mindmap .mm-leaf         { font-size: 11px; fill: var(--text-dim); }
.dg-caption { margin: 0.4rem 0 0; font-size: 0.75rem; color: var(--text-dim); font-style: italic; }

.head-actions { display: flex; align-items: center; gap: 0.25rem; }

.text-btn {
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-size: 0.78rem;
  padding: 0.25rem 0.5rem;
  border-radius: 6px;
  transition: background 0.12s, color 0.12s;
}
.text-btn:hover { background: var(--surface-2); color: var(--danger); }

.history-list { list-style: none; margin: 0; padding: 0.5rem; overflow-y: auto; display: flex; flex-direction: column; gap: 0.3rem; }
.history-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.4rem 0.5rem 0.6rem;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.12s;
}
.history-item:hover { background: var(--surface-2); }
.history-text { flex: 1; min-width: 0; }
.history-term { display: block; font-weight: 550; font-size: 0.875rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.history-sub { display: block; font-size: 0.75rem; color: var(--text-dim); margin-top: 0.1rem; }
/* Revealed on hover, but always reachable by keyboard and on touch. */
.history-item .delete-btn { opacity: 0; }
.history-item:hover .delete-btn,
.history-item .delete-btn:focus-visible { opacity: 1; }
@media (hover: none) { .history-item .delete-btn { opacity: 1; } }

@media (max-width: 640px) {
  /* More buttons than a phone is wide: the bar scrolls sideways rather than cutting them off. */
  .toolbar { gap: 0.25rem; padding: 0 0.35rem; overflow-x: auto; scrollbar-width: none; }
  .toolbar > * { flex: none; }
  .doc-title { display: none; }
  .panel, .panel.panel-wide, .history, .recaps { right: 8px; left: 8px; bottom: 8px; width: auto; }
  .recap-range { right: 8px; left: 8px; width: auto; }
  /* No room to push the pages aside on a phone: float over them instead. */
  .outline {
    position: fixed; top: var(--toolbar-h); bottom: 0; left: 0;
    width: min(300px, 85vw); box-shadow: var(--shadow-lg); z-index: 40;
  }
  .page-physical { display: none; }
}

/* Hidden while scrolling with the keyboard (reader.js). */
body.cursor-hidden, body.cursor-hidden * { cursor: none !important; }
