/* Static interlinear trainer — calm paper look, one accent color for linked
   groups, solved green tint for the solved-look, dimmed grey punctuation.
   Two short feedback animations: the wrong-answer red flash and the
   solved-slot green glow (story 46). */

:root {
  --paper: #f7f4ec;
  --card: #fffdf7;
  --ink: #2d2b26;
  --muted: #8b8578;
  --line: #ded8c8;
  --accent: #b0511c;
  --accent-soft: rgba(176, 81, 28, 0.16);
  --solved-bg: #fffffe;
  --solved-ink: #3c6b41;
  --error: #4f5fc8;

  /* Design tokens (ticket 15, stories 66–68) — extend, never rename. */
  /* The serif of the book: French tier, headings, card titles, page number. */
  --ink-family: Georgia, "Times New Roman", "Droid Serif", serif;
  /* The printed page: warm cream surface, quiet edge rule, bound left side. */
  --page-paper: #fffbf6;
  --page-edge: #d8cdb0;
  /* Radius scale: s = controls, m = cards and panes. */
  --radius-s: 0.35rem;
  --radius-m: 0.5rem;
  /* Shadow scale: 1 = resting, 2 = lifted, page = a page lying on the desk,
     pop = anchored menus. */
  --shadow-1: 0 1px 2px rgba(45, 43, 38, 0.07), 0 2px 8px rgba(45, 43, 38, 0.05);
  --shadow-2: 0 2px 4px rgba(45, 43, 38, 0.07), 0 12px 26px -10px rgba(45, 43, 38, 0.18);
  --shadow-page: 0 1px 2px rgba(45, 43, 38, 0.06), 0 18px 40px -22px rgba(45, 43, 38, 0.35);
  --shadow-pop: 0 4px 14px rgba(45, 43, 38, 0.14);
  /* Satzspiegel: the printed page's generous type-area margins. */
  --satzspiegel-x: clamp(1.35rem, 3.5vw, 3.25rem);
  --satzspiegel-y: clamp(1.9rem, 4vw, 2.9rem);
  /* Sticky chrome: header-bar height plus breathing room — the scan pane
     sticks below the bar (story 68). */
  --sticky-below: 3.6rem;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  line-height: 1;
}

#app {
  max-width: 76rem; /* wide enough for the two-pane page view */
  margin: 0 auto;
  padding: 1.25rem 1rem 4rem;
}

.error-view {
  max-width: 60rem;
  margin: 0 auto;
}

/* Landing (story 51): wider than the old picker view — the grid gives the
   four manual sections the main column and the chapter picker a narrow
   right-hand aside. */
.landing {
  max-width: 72rem;
  margin: 0 auto;
}

/* Sticky running head (story 68): paper-backed with a quiet bottom rule,
   stacked above the panes and their popovers — mode toggle, sync chip and
   page reset stay reachable at every scroll position, and content never
   slides under a transparent bar. The hairline + soft edge read like a
   book's running head; they are constant (no scroll listener — the
   structure stays frozen). */
header.app {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flow-root; /* contains the floated controls */
  background: var(--paper);
  padding: 0.7rem 0 0.55rem;
  margin-bottom: 1.1rem;
  border-bottom: 1px solid var(--line);
  box-shadow: 0 0.55rem 1rem -0.8rem rgba(45, 43, 38, 0.3);
}

header.app h1 {
  font-family: var(--ink-family);
  font-size: 1.3rem;
  font-weight: 600;
  margin: 0;
  letter-spacing: 0.02em;
}

/* Safe controls (story 49): sync chip + the one reset float right in the
  header, out of the reading/decoding area. */
.header-controls {
  float: right;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.2rem;
}

/* Phones (story 68 — function unchanged): the floated controls would make
   the sticky bar taller than the viewport slice it protects; they unfloat
   and wrap under the title instead, keeping the bar compact. */
@media (max-width: 700px) {
  .header-controls {
    float: none;
    flex-wrap: wrap;
    gap: 0.4rem 0.6rem;
    margin-top: 0.5rem;
  }
}

/* Kapitel picker */

.picker-heading {
  font-family: var(--ink-family);
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--muted);
  margin: 0 0 0.75rem;
}

.chapters {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.6rem;
}

/* Chapter cards read as books (story 67): a spine on the left edge, serif
   titles, a gentle hover lift — calm surfaces, no noise. */
.chapter,
.landing-boom {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.8rem 1rem 0.75rem 1.1rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 4px solid var(--accent); /* the binding */
  border-radius: var(--radius-s);
  box-shadow: var(--shadow-1);
  text-decoration: none;
  color: inherit;
  transition: transform 0.16s ease-out, box-shadow 0.16s ease-out;
}

.landing-boom:hover,
.landing-boom:focus-visible,
.chapter:hover,
.chapter:focus-visible {
  transform: translateY(-2px);
  box-shadow: var(--shadow-2);
}

.picker-title,
.boom-title {
  font-family: var(--ink-family);
  font-size: 1.02rem;
  font-weight: 600;
}

.picker-meta,
.boom-meta {
  color: var(--muted);
  font-size: 0.85rem;
}

.picker-done {
  margin-left: auto;
  font-size: 0.8rem;
  color: var(--solved-ink);
}

/* Boom card (ticket design-mobile 1a): the vocabulary trainer as a quiet
   sibling of the chapter cards — same card family, muted binding, placed
   under the chapter list in the picker column. A plain relative link:
   boom/ leaves the hash routes, same tab. */
.landing-boom {
  margin-top: 0.9rem; /* a breath more than the list's own gap */
  border-left-color: var(--muted); /* quieter binding than the chapters' */
}

/* Landing page (story 51): four German sections about interlinear decoding
   plus the trainer manual — the chapter picker stays part of the same
   surface. The picker is the grid's first child: stacked layouts (phones)
   keep it at the top within one viewport, wide screens place it beside the
   text (explicit grid areas below). */

.landing-grid {
  display: grid;
  gap: 1.75rem;
}

.landing-text {
  max-width: 46rem;
  font-size: 1.02rem;
  line-height: 1.65;
}

.landing-section {
  margin: 0 0 1.9rem;
}

.landing-section:last-child {
  margin-bottom: 0;
}

/* Headings read like the book: the serif of the French tier. */
.landing-section h2 {
  font-family: var(--ink-family);
  font-size: 1.3rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  margin: 0 0 0.55rem;
}

.landing-section p {
  margin: 0 0 0.55rem;
}

.landing-section p:last-child {
  margin-bottom: 0;
}

.landing-steps {
  margin: 0;
  padding-left: 1.4rem;
}

.landing-steps li {
  margin: 0 0 0.55rem;
}

.landing-steps li:last-child {
  margin-bottom: 0;
}

/* Key names (Enter) in the manual copy get a quiet key-cap look. */
kbd {
  font-family: inherit;
  font-size: 0.85em;
  line-height: 1;
  padding: 0.1em 0.45em;
  background: var(--card);
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 0.3rem;
}

@media (min-width: 960px) {
  .landing-grid {
    grid-template-columns: minmax(0, 1fr) 18rem;
    gap: 3rem;
  }

  .landing-text {
    grid-column: 1;
    grid-row: 1;
  }

  .landing-picker {
    grid-column: 2;
    grid-row: 1;
  }
}

/* Page view */

.back {
  display: inline-block;
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
}

.back:hover {
  text-decoration: underline;
}

.progress {
  color: var(--muted);
  margin: 0.35rem 0 1.25rem;
}
/* Two panes (story 39): the book scan on the left is the orientation anchor
   and scrolls within itself (sticky while the drill scrolls past); the right
   pane carries the interactive drill. Below ~1000px the scan pane is removed
   entirely (owner ticket design-mobile: not stacked, no toggle on phones) —
   the drill takes the full width. */

.panes {
  display: grid;
  grid-template-columns: minmax(17rem, 5fr) minmax(0, 7fr);
  gap: 1.5rem;
  align-items: start;
}

/* The framed artifact (story 67): the scan lies on a mat inside the sticky
   pane — a page laid on a desk. It sticks BELOW the header bar (story 68). */
.book-pane {
  position: sticky;
  top: var(--sticky-below);
  max-height: calc(100vh - var(--sticky-below) - 1rem);
  overflow-y: auto;
  padding: 0.85rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-1);
}

/* Mat + shadow around the scan itself (render.js wraps it in the frame). */
.scan-frame {
  margin: 0;
  padding: 0.55rem;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  box-shadow: var(--shadow-1);
}

/* The caption sits under the framed artifact, like a plate label. */
.pane-heading {
  font-family: var(--ink-family);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--muted);
  margin: 0.7rem 0 0.1rem;
  text-align: center;
}

.book-image {
  display: block;
  width: 100%;
  height: auto;
}

/* The printed page (story 66): warm paper, generous Satzspiegel margins, a
   doubled quiet edge — outer rule plus inner hairline — and a soft binding
   shadow on the left. The drill reads as the book's page, not a web list;
   the row semantics inside (slots, notes, popovers, tiers) are untouched
   (story 58 parity: upcoming keeps reading exactly like passed). */
.drill-pane {
  position: relative;
  isolation: isolate; /* keeps the inner hairline behind the content */
  min-width: 0;
  padding: var(--satzspiegel-y) var(--satzspiegel-x) calc(var(--satzspiegel-y) * 0.8);
  background:
    linear-gradient(
      to right,
      rgba(247, 245, 242, 0.13),
      rgba(122, 103, 66, 0.04) 1rem,
      rgba(122, 103, 66, 0) 2.1rem
    ),
    var(--page-paper);
  border: 1px solid var(--page-edge);
  border-radius: var(--radius-s);
  box-shadow: var(--shadow-page);
}

/* Inner rule of the doubled page edge: painted above the paper, below the
   text (isolation + negative z-index), never catching pointer events. */
.drill-pane::before {
  content: '';
  position: absolute;
  inset: 0.45rem;
  border: 1px solid rgba(122, 103, 66, 0.16);
  border-radius: 1px;
  pointer-events: none;
  z-index: -1;
}

/* Page number as the page's own footer line (story 66): centered in the
   bottom margin, serif, quiet — render.js writes „Seite N" from state. */
.page-number {
  margin: 2.4rem 0 0;
  text-align: center;
  font-family: var(--ink-family);
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  color: var(--muted);
}

@media (max-width: 1000px) {
  .panes {
    grid-template-columns: 1fr;
  }

  .book-pane {
    display: none; /* removed, not stacked (design-mobile Nicht-Ziel) */
  }
}

.sentences {
  display: grid;
  gap: 1.75rem;
}

.sentence {
  position: relative; /* popover anchor for the translation's correction menu */
}

.error {
  color: var(--error);
  font-weight: 600;
}

/* Interlinear row: one wrapping flex row per sentence; the flex items are
   units (.unit, one per gloss unit — render.js) and bare columns for
   unclaimed tokens. The flex gap is the word gap; standalone punctuation
   columns get the same gap on both sides, which yields the French spacing.
   Units and columns keep their automatic min-width (min-content), so
   nothing is ever squeezed or split internally: rows wrap BETWEEN units
   only — a unit's French tokens never separate from its German slot. */

.row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.4rem 0.9rem;
}

.unit {
  display: flex;
  align-items: flex-start;
  gap: 0.4rem 0.9rem;
}

.col {
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative; /* popover anchor */
}

.toks {
  display: flex;
  align-items: baseline;
  white-space: nowrap;
  /* Book resemblance: the French tier reads in a serif like the printed
     page; the German glosses/notes stay in the system sans. */
  font-family: var(--ink-family);
}

.row.current .tok {
  font-family: inherit;
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.25;
  color: inherit;
  background: none;
  border: 0;
  padding: 0 0.15em;
  cursor: pointer;
}

.row.current button.tok:hover {
  background: var(--accent-soft);
  border-radius: 0.35em;
}

/* Solved and upcoming rows share the calm book typography (story 58): the
  same size and weight, muted ink. Only the current row is elevated. */
.row.passed .tok,
.row.upcoming .tok {
  font-size: 1rem;
  font-weight: 600;
  color: var(--muted);
}

.row.passed .punct,
.row.passed .plain,
.row.upcoming .punct,
.row.upcoming .plain {
  font-size: 0.85rem;
}

/* Multi-index units: shared pill look, highlighted together when any member
   is hovered or focused. */

.tok.group {
  color: var(--accent);
}

.tok.group.linked {
  background: var(--accent-soft);
  border-radius: 0.35em;
}

.cont {
  color: var(--accent);
  font-weight: 700;
}

.punct,
.plain {
  color: var(--muted);
  pointer-events: none;
}

.row.current .punct,
.row.current .plain {
  font-size: 1.2rem;
  font-weight: 400;
}

/* Phones (ticket design-mobile): the tiers shrink a modest notch so the
   page fits small screens — no redesign. Passed and upcoming keep story
   58's parity, so they shrink together; the current row stays elevated. */
@media (max-width: 700px) {
  .row.current .tok {
    font-size: 1.3rem;
  }

  .row.current .punct,
  .row.current .plain {
    font-size: 1.05rem;
  }

  .row.passed .tok,
  .row.upcoming .tok {
    font-size: 0.95rem;
  }
}

/* Slot tier: an empty box sized by the invisible ghost text of the gloss.
   The ghost never wraps, so multi-word glosses keep one width. The slot is
   its own positioning context: the typed-answer input is confined to the
   slot box and can never cover the token or note tier (bug 1). */

.slot {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 1.5rem;
  margin-top: 0.2rem;
  padding: 0 0.3em;
  border-bottom: 2px solid var(--line);
}

.ghost {
  visibility: hidden;
  white-space: nowrap;
  font-weight: 200;
}

/* A revealed ghost is a button: it opens the correction menu. */
button.ghost {
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  font-weight: 200;
}

/* Only the current row's slot box is compact; passed and upcoming ghosts
   share the base ghost size (story 58 — identical typography). */
.row.current .ghost {
  font-size: 0.85rem;
}

.ghost.revealed {
  visibility: visible;
  color: var(--solved-ink);
  cursor: pointer;
}

.ghost.revealed:hover {
  text-decoration: underline dotted;
}

/* Small accent (i) on corrected German nodes (story 60 — peeked words
   carry no (i); the node itself opens the correction menu). */
.ind {
  font-size: 0.62rem;
  margin-left: 0.15em;
  white-space: nowrap;
}

.ind.accent {
  color: var(--accent);
}

.sentence.passed .slot {
  background: var(--solved-bg);
  border-bottom-color: transparent;
  border-radius: 0.35em;
}

.sentence.upcoming .slot {
  opacity: 0.45; /* visible but locked */
}

/* Green glow (story 46): a short box-shadow pulse that fades — applied to
  the freshly solved slot right after an Enter validation (interact.js). */
@keyframes solved-glow {
  0% {
    box-shadow: 0 0 0 0 rgba(60, 107, 65, 0.5);
    background: var(--solved-bg);
  }

  100% {
    box-shadow: 0 0 0 0.75rem rgba(60, 107, 65, 0);
    background: transparent;
  }
}

.slot.glow {
  animation: solved-glow 0.9s ease-out 1;
}

/* Note tier: placeholder space while unsolved; small wrapped lines once
   revealed. Literal notes are italic. */

.note {
  max-width: 16ch;
  min-height: 1em;
  margin-top: 0.2rem;
  text-align: center;
  font-size: 0.72rem;
  color: var(--muted);
}

.note-line {
  display: block;
}

/* Note lines are buttons once revealed: same menu pattern as the gloss. */
button.note-line {
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 0.72rem;
  text-align: center;
  color: var(--muted);
  cursor: pointer;
}

button.note-line:hover {
  text-decoration: underline dotted;
}

.note-line.literal {
  font-style: italic;
}

.translation {
  color: var(--muted);
  margin: 0.4rem 0 0;
}

/* The natural translation is shown on passed sentences (render.js) and via
   the toggle on the current one; either way it is a button that opens the
   correction menu — same reset as the other revealed German nodes. */
button.translation {
  display: block;
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 0.85rem;
  text-align: left;
  cursor: pointer;
}

button.translation:hover {
  text-decoration: underline dotted;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* One calm control language (story 67): the boxed controls — mode toggle,
   sync chip, menu buttons, danger resets — share one quiet shape: hairline
   border, card surface, small radius, muted ink. Safe controls turn accent
   on hover; destructive ones keep the error color. */
.mode-toggle,
.sync-status,
.correction-save,
.correction-reset,
.reset.danger,
.app-reset {
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--card);
  color: var(--muted);
}

/* Interaction layer: typed-answer input, choice popover (options, divider,
   „Nachsehen"), correction menu, (i) indicators, note-ind star,
   natural-translation toggle, mode button, completion, reset. Same calm
   palette; red reserved for wrong typed answers. */

/* Typed-answer input: absolutely positioned against the slot (the nearest
   positioned ancestor), inset 0 — geometrically confined to the slot box,
   never overlapping the token or note tier. */
.slot-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 1px dashed var(--line);
  border-radius: 0.35em;
  background: var(--card);
  font: inherit;
  font-size: 1.05rem;
  text-align: center;
  color: inherit;
}

.slot-input:focus {
  outline: none;
  border-color: var(--accent);
}

.slot-input.wrong {
  border-color: var(--error);
  background: rgba(163, 58, 42, 0.08);
}

/* Prefix hint (story 46): after the first miss the solution's first
  characters sit in the input as ghost-toned text; the learner keeps typing
  after the visible prefix. The tone drops on success or blur. */
.slot-input.hinted {
  border-color: var(--muted);
  color: var(--muted);
  font-style: italic;
}

/* Note indicator (story 56): French tokens of a note-carrying unit wear a
   small always-visible star — CSS-generated, so the token text itself stays
   clean. Both modes, all phases. The token is the click affordance for
   re-opening a fully solved sentence's notes (story 57), hence the pointer. */
.note-ind {
  cursor: pointer;
}

.note-ind::after {
  content: '*';
  vertical-align: super;
  font-size: 0.65em;
  color: var(--accent);
}

.popover {
  position: absolute;
  top: calc(100% + 0.35rem);
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 9rem;
  padding: 0.35rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-pop);
}

.option {
  padding: 0.25rem 0.5rem;
  border: 1px solid transparent;
  border-radius: var(--radius-s);
  background: none;
  font: inherit;
  text-align: left;
  color: inherit;
  cursor: pointer;
}

.option:hover:not(:disabled) {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.option.burnt {
  color: var(--muted);
  text-decoration: line-through;
  cursor: not-allowed;
}

/* Divider + „Nachsehen" as the popover's last entry (decision 3) —
   visually a menu row like the options, not a floating chip. */
.divider {
  border-top: 1px solid var(--line);
}

.peek {
  padding: 0.25rem 0.5rem;
  border: 1px solid transparent;
  border-radius: var(--radius-s);
  background: none;
  font: inherit;
  font-size: 0.8rem;
  text-align: left;
  color: var(--muted);
  cursor: pointer;
}

.peek:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
}

/* Correction menu: original line, editable field, actions (decision 4).
   Same anchored-popover look as the choice menu. */
.correction-menu {
  min-width: 13rem;
  gap: 0.35rem;
}

.correction-original {
  padding: 0 0.25rem;
  font-size: 0.72rem;
  color: var(--muted);
}

/* Story 61: the correction field is a wrapping, auto-growing textarea —
  one row to start, height follows the content (interact.js sets it from
  scrollHeight on open and on every input). Full width of the menu, so
  long sentence corrections wrap instead of clipping. */
.correction-input {
  display: block;
  width: 100%;
  resize: none;
  overflow: hidden;
  min-height: 2.2em;
  line-height: 1.35;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--paper);
  font: inherit;
  font-size: 0.85rem;
  padding: 0.2rem 0.4rem;
  color: inherit;
}

.correction-input:focus {
  outline: none;
  border-color: var(--accent);
}

.correction-actions {
  display: flex;
  gap: 0.35rem;
}

.correction-save,
.correction-reset {
  padding: 0.15rem 0.5rem;
  font: inherit;
  font-size: 0.72rem;
  color: inherit;
  cursor: pointer;
}

.correction-save:hover,
.correction-reset:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.correction-reset {
  color: var(--muted);
}

.natural-toggle,
.reset {
  border: none;
  background: none;
  font: inherit;
  font-size: 0.75rem;
  color: var(--muted);
  text-decoration: underline dotted;
  cursor: pointer;
}

.natural-toggle:hover,
.reset:hover {
  color: var(--accent);
}

.natural-toggle {
  display: block;
  margin: 0.5rem auto 0;
  font-size: 0.85rem;
  color: var(--accent);
}

/* Story 52: the mode button lives with chip + reset in the header controls.
   A quiet boxed label (like the chip, not the danger reset) that shows the
   ACTIVE mode; one click switches in-flight. No mode-specific tier styles
   exist — story 53 keeps every tier's typography identical across modes. */
.mode-toggle {
  font: inherit;
  font-size: 0.75rem;
  padding: 0.15rem 0.6rem;
  cursor: pointer;
  white-space: nowrap;
}

.mode-toggle:hover {
  color: var(--accent);
  border-color: var(--accent);
}

/* The page reset lives in the header controls (story 49) — no side margin.
  Page-scoped label and confirm (story 64): red-bordered, both devices. */
.reset.danger {
  padding: 0.2rem 0.6rem;
  border-color: var(--error);
  color: var(--error);
  text-decoration: none;
}

.reset.danger:hover {
  color: var(--error);
  background: rgba(163, 58, 42, 0.08);
}

/* Sentence reset (story 63): a quiet small (x) at the top-right of every
  fully solved sentence, out of the text flow; it turns red on hover —
  destructive, but bounded (only that sentence, corrections stay). */
.sentence-reset {
  position: absolute;
  top: 0;
  right: 0;
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 0.72rem;
  line-height: 1.25;
  color: var(--muted);
  cursor: pointer;
}

.sentence-reset:hover {
  color: var(--error);
}

/* Whole-app reset (story 65): a small disclosure menu at the end of the
  landing text — the ONLY place the app-wide reset exists. Native
  details/summary opens without JS; the button shares the danger look. */
.danger-zone {
  margin-top: 1.5rem;
}

.danger-zone summary {
  width: fit-content;
  font-size: 0.85rem;
  color: var(--muted);
  cursor: pointer;
}

.danger-zone summary:hover {
  color: var(--error);
}

.app-reset {
  margin-top: 0.5rem;
  padding: 0.2rem 0.6rem;
  border-color: var(--error);
  font: inherit;
  font-size: 0.75rem;
  color: var(--error);
  cursor: pointer;
}

.app-reset:hover {
  background: rgba(163, 58, 42, 0.08);
}

/* Shared state (stories 43–45): the sync status chip in the header controls.
   Stores are automatic — the chip reports instead of a button. The server
   reset button is gone (story 50): a local reset syncs anyway. The chip
   shares the boxed control shape (story 67). */
.sync-status {
  padding: 0.15rem 0.6rem;
  font-size: 0.75rem;
  line-height: 1.45;
  white-space: nowrap;
}

.sync-status--saving {
  font-style: italic;
}

.sync-status--offline {
  color: var(--accent);
}

/* Ticket08: the session's username beside the sync chip — display only
  (identity is the Passwort), quiet muted text like the picker meta. */
.header-user {
  font-size: 0.85rem;
  color: var(--muted);
  white-space: nowrap;
}

/* Transient status pill (story 42): bottom edge, stacks when several land. */
.toast {
  position: fixed;
  left: 50%;
  bottom: 1.25rem;
  transform: translateX(-50%);
  margin: 0;
  padding: 0.5rem 1rem;
  background: var(--ink);
  color: var(--paper);
  font-size: 0.85rem;
  border-radius: 999px;
  box-shadow: 0 2px 10px rgba(45, 43, 38, 0.35);
  z-index: 50;
  white-space: nowrap;
}

.toast + .toast {
  bottom: 3.5rem;
}

.done {
  margin-top: 1.75rem;
  padding: 1.25rem;
  background: var(--solved-bg);
  border-radius: var(--radius-m);
  text-align: center;
}

.done-line {
  margin: 0;
  font-size: 1.3rem;
  font-weight: 700;
  color: var(--solved-ink);
}

/* Login gate (ticket08): the landing's copy stays; the two auth paths sit
  above it as two cards — „Anmelden“ and „Neu hier?“ — sharing the calm
  control language (hairline border, card surface, small radius). */
.login-paths {
  display: grid;
  gap: 1rem;
  margin-bottom: 2.25rem;
}

@media (min-width: 700px) {
  .login-paths {
    grid-template-columns: 1fr 1fr;
    gap: 1.75rem;
  }
}

.auth-unreachable {
  margin: 0 0 1.25rem;
  padding: 0.55rem 0.9rem;
  background: var(--accent-soft);
  border-radius: var(--radius-s);
  color: var(--accent);
  font-size: 0.9rem;
}

.auth-card {
  padding: 1.25rem 1.5rem 1.4rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-1);
}

.auth-card h2 {
  font-family: var(--ink-family);
  font-size: 1.3rem;
  font-weight: 600;
  margin: 0 0 0.85rem;
}

.auth-card form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
}

.auth-card label {
  flex-basis: 100%;
  font-size: 0.9rem;
  color: var(--muted);
}

.auth-card input {
  flex: 1 1 12rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--page-paper);
  font: inherit;
  font-size: 1.02rem;
  color: inherit;
}

.auth-card input:focus {
  outline: none;
  border-color: var(--accent);
}

.auth-submit,
.auth-continue,
.copy-passwort {
  padding: 0.45rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--card);
  font: inherit;
  font-size: 0.9rem;
  color: var(--ink);
  cursor: pointer;
}

.auth-submit:hover,
.auth-continue:hover,
.copy-passwort:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.auth-submit:disabled {
  opacity: 0.6;
  cursor: default;
}

/* Errors talk quietly but clearly; hidden until main.js fills them in. */
.auth-error {
  margin: 0.85rem 0 0;
  font-size: 0.9rem;
  color: var(--error);
}

/* Step two of „Neu hier?“: the minted Passwort, shown exactly once. */
.passwort-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin: 0.25rem 0 0.6rem;
}

.minted-passwort {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 0.35rem 0.7rem;
  background: var(--page-paper);
  border: 1px dashed var(--line);
  border-radius: var(--radius-s);
  user-select: all; /* one tap selects the whole Passwort */
}

.auth-hint {
  margin: 0 0 1rem;
  font-size: 0.9rem;
  color: var(--muted);
}

