/* web/app/app.css — the Lampi design system (from the "Claude Design" pack Daniel
   supplied, applied here rather than re-invented). Mobile-first, 380px up, same
   convention as before: everything below is usable one-handed on a phone. Every
   class name and id setup.js reads or writes is unchanged — this file only
   restyles, it never renames.

   The pack also has a tablet-width marketing layout for the landing page (a nav
   bar, a side-by-side hero, a 3-column feature grid). Not built here: this app is
   a phone/tablet utility, not a marketing site, and the existing single-column,
   ~480px-wide convention already scales acceptably to a tablet held upright — a
   proper desktop marketing page is its own, separate piece of work. */

@import url('/fonts/fonts.css'); /* self-hosted since v0.34 — no request leaves for Google */

:root {
  --bg: #12162b;
  --bg-card: #1b2040;
  --bg-input: #232a4e;
  --bg-input-alt: #2a3356;
  --bg-chip: #2a3356;
  --border: #333c66;
  --border-input: #3d477a;
  --border-dashed: #4a548a;
  --text: #f7efe1;
  --text-dim: #a8b0cf;
  --text-dimmer: #8f98c0;
  --text-faint: #6f78a0;
  --accent: #f2a94b;
  --accent-soft: #ffd79a;
  --accent-text: #1b2040;
  --danger: #ff8a80;
  --danger-bg: #3a1f1d;
  --radius: 20px;
  --radius-sm: 14px;
  --tap: 48px;
  --font-serif: 'Petrona', Georgia, serif;
  --font-sans: 'Hanken Grotesk', system-ui, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100%;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.5 var(--font-sans);
  -webkit-text-size-adjust: 100%;
}

body {
  padding: max(20px, env(safe-area-inset-top)) 18px max(24px, env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

#app {
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 18px;
  flex: 1;
}

/* -- brand mark -------------------------------------------------------------- */

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
}
.brand-dot {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  flex: none;
  background: radial-gradient(circle at 40% 35%, #fff2d4, var(--accent) 70%);
  box-shadow: 0 0 14px rgba(242, 169, 75, .8);
}
.brand-name {
  font-family: var(--font-serif);
  font-size: 1.3rem;
  font-weight: 500;
  color: var(--text);
}

h1 {
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 1.9rem;
  line-height: 1.2;
  letter-spacing: -.01em;
  margin: 4px 0 0;
  color: var(--text);
}
h2 {
  font-family: var(--font-serif);
  font-size: 1.15rem;
  font-weight: 500;
  margin: 0 0 4px;
  color: var(--text);
}
p.sub {
  color: var(--text-dim);
  margin: 0 0 4px;
  font-size: 0.98rem;
  line-height: 1.5;
}

.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.9rem;
  color: var(--text-dim);
  font-weight: 500;
}

input[type="text"], input[type="email"], input[type="number"], textarea, select {
  background: var(--bg-input);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 1rem;
  padding: 13px 15px;
  min-height: var(--tap);
  font-family: var(--font-serif);
  width: 100%;
}
textarea { min-height: 78px; resize: vertical; line-height: 1.5; }
input:focus, textarea:focus, select:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
input::placeholder, textarea::placeholder { color: var(--text-faint); opacity: 1; }

.row {
  display: flex;
  gap: 10px;
}
.row > * { flex: 1; min-width: 0; }

button {
  font-family: var(--font-sans);
  font-size: 1rem;
  font-weight: 600;
  border-radius: var(--radius-sm);
  min-height: var(--tap);
  padding: 0 18px;
  border: 1px solid transparent;
  cursor: pointer;
}
button.primary {
  background: var(--accent);
  color: var(--accent-text);
  font-weight: 700;
}
/* Same treatment on a real <a> — home.html's main CTA is a genuine navigation to
   tonight.html, not a JS action, so it should be an <a>, styled the same as
   button.primary everywhere else (a.secondary just below does the same thing for
   the secondary style, for the same reason). */
a.primary {
  display: block;
  text-align: center;
  min-height: var(--tap);
  line-height: var(--tap);
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--accent-text);
  font-weight: 700;
  text-decoration: none;
}
button.secondary {
  background: transparent;
  color: var(--text-dim);
  border-color: var(--border-input);
}
/* Same visual treatment on a real <a> navigation, not a JS button — index.html's
   "Read a sample tale" is a genuine page link (right-click, open-in-new-tab all
   work), not an action, so it should be an <a>, but it reads as the same kind of
   secondary control as button.secondary everywhere else. */
a.secondary {
  display: block;
  text-align: center;
  min-height: var(--tap);
  line-height: var(--tap);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-input);
  color: var(--text-dim);
  font-weight: 600;
  text-decoration: none;
}

/* -- home page (home.html) ---------------------------------------------------- */
.home-greeting {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 6px 4px;
}
.home-greeting img { width: 64px; height: auto; flex: none; }
.home-greeting p { margin: 0; font-size: 1.05rem; line-height: 1.4; }
#recent-list .child-item { cursor: default; } /* these are display cards, not links (yet) */
button.danger {
  background: transparent;
  color: var(--danger);
  border-color: var(--danger);
}
button.link {
  background: none;
  border: none;
  color: var(--accent);
  min-height: auto;
  padding: 6px 0;
  text-align: left;
  font-weight: 600;
}
button:disabled { opacity: 0.5; cursor: default; }
button:active:not(:disabled) { transform: translateY(1px); }
button:focus-visible, a:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.stack { display: flex; flex-direction: column; gap: 10px; }

/* Admin: the checks card (web/app/admin.js). */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 8px; }
.stat { background: var(--surface-2, rgba(255,255,255,0.04)); border-radius: var(--radius-sm); padding: 8px 10px; }
.stat b { display: block; font-size: 1.25rem; line-height: 1.2; }
.stat span { font-size: 0.78rem; opacity: 0.75; }
.stat.warn b { color: var(--danger); }
.rule-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.rule-table th { text-align: left; font-weight: 600; opacity: 0.75; padding: 4px 6px 4px 0; }
.rule-table th.n, .rule-table td.n { text-align: right; width: 4.5em; font-variant-numeric: tabular-nums; }
.rule-table td { padding: 3px 6px 3px 0; border-top: 1px solid rgba(255,255,255,0.06); word-break: break-word; }
.rule-table tr.group td { border-top: 0; padding-top: 10px; font-weight: 600; opacity: 0.85; }
.seg { display: flex; gap: 6px; }
.seg button { flex: 1; }
.seg button[aria-pressed="true"] { outline: 2px solid var(--accent, currentColor); }
.review-item { font-size: 0.85rem; padding: 6px 0; border-top: 1px solid rgba(255,255,255,0.06); }
.review-item code { word-break: break-all; }

/* Inline "this field is still missing" under a setup field (setup.js showMissing()). */
.field-error {
  color: var(--danger);
  font-size: 0.85rem;
  margin: 4px 2px 0;
}
.field-error.hidden { display: none; }
input.invalid, textarea.invalid { border-color: var(--danger); }
.ritual-steps.invalid { outline: 1px solid var(--danger); outline-offset: 4px; border-radius: var(--radius-sm); }

.error-banner {
  background: var(--danger-bg);
  border: 1px solid var(--danger);
  color: var(--danger);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  font-size: 0.9rem;
}

.child-item, .character-item {
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.child-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}
.child-header strong { font-family: var(--font-serif); font-size: 1.1rem; font-weight: 600; }
.child-meta { color: var(--text-dim); font-size: 0.85rem; }

.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  background: var(--bg-chip);
  border: 1px solid var(--border-input);
  border-radius: 999px;
  padding: 6px 12px;
  font-size: 0.85rem;
  color: var(--text-dim);
}

.ritual-steps { display: flex; flex-direction: column; gap: 8px; }
.ritual-step-row { display: flex; gap: 8px; align-items: center; }
.ritual-step-row input { flex: 1; }
.ritual-step-row button { min-height: 40px; padding: 0 12px; }

/* -- reassurance strip: mascot + a line of copy, used on landing and setup -- */
.reassure {
  background: var(--bg-input);
  border-radius: var(--radius-sm);
  padding: 14px 16px;
  display: flex;
  gap: 12px;
  align-items: center;
}
.reassure img { width: 56px; height: auto; display: block; flex: none; }
.reassure p { margin: 0; font-size: 0.9rem; line-height: 1.5; color: var(--text-dim); }

footer.actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: auto;
  padding-top: 16px;
}

.spinner { color: var(--text-dim); font-size: 0.9rem; }
.hidden { display: none !important; }

/* -- landing hero (index.html) ------------------------------------------------ */

/* Hidden by default (phone) — the design's phone variant (1a) has no separate nav
   at all, brand + sign-in live inside the hero. Shown only at tablet width+, below. */
.landing-nav { display: none; }

.hero {
  border-radius: 28px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--bg-card);
}
.hero-image {
  position: relative;
  height: 200px;
  overflow: hidden;
}
.hero-image img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 62%;
}
.hero-image::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(32, 40, 69, .7) 0%, rgba(32, 40, 69, 0) 40%, rgba(27, 32, 64, .96) 92%);
}
.hero-image .brand {
  position: absolute;
  top: 14px;
  left: 18px;
  z-index: 1;
}
.hero-overlay {
  padding: 4px 22px 26px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.hero-overlay h1 { font-size: 1.7rem; text-wrap: pretty; }
.hero-overlay > p { margin: 0; font-size: 0.98rem; line-height: 1.55; color: var(--text-dim); }

.hero-below {
  padding: 4px 22px 26px;
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.feature-list { display: flex; flex-direction: column; gap: 14px; }
.feature {
  display: flex;
  gap: 12px;
}
.feature-num {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 10px;
  background: var(--bg-input-alt);
  display: grid;
  place-items: center;
  font-family: var(--font-serif);
  color: var(--accent);
  font-size: 0.85rem;
}
.feature-title { font-size: 0.92rem; font-weight: 700; color: var(--text); margin-bottom: 2px; }
.feature-body { font-size: 0.85rem; line-height: 1.5; color: var(--text-dim); }

.quote-line {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  padding-top: 4px;
}
.quote-line img { width: 68px; height: auto; display: block; }
.quote-line span {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 0.9rem;
  color: var(--text-dim);
  padding-bottom: 10px;
}

/* -- landing, tablet width and up --------------------------------------------
   Matches the design package's 1a tablet variant: a real nav bar above the hero
   (brand + a "Sign in with Google" pill, matching the design's literal copy — the
   two hero buttons underneath keep their own action-oriented labels rather than
   duplicating "sign in"), the heading/subhead/CTAs overlaid on the image instead
   of stacked below it, and the three feature blocks in a row instead of stacked.
   Content is identical to the phone layout on purpose — the design's tablet
   mockup has slightly different feature copy referencing a "three ways" choice
   that does not exist in the product yet (build plan Q5, not yet built), so
   using the phone copy everywhere avoids describing a feature that isn't there. */
@media (min-width: 760px) {
  #app.landing { max-width: 900px; gap: 24px; }

  .landing-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 8px;
  }
  .nav-signin {
    font-family: var(--font-sans);
    font-size: 0.9rem;
    font-weight: 600;
    padding: 10px 20px;
    border-radius: var(--radius-sm);
    background: var(--bg-input-alt);
    color: var(--text);
    border: none;
    cursor: pointer;
  }

  .hero-image { height: 420px; overflow: visible; }
  .hero-image .brand { display: none; } /* the real nav above already shows the brand */
  .hero-overlay {
    position: absolute;
    inset: 0;
    z-index: 1;
    justify-content: center;
    max-width: 460px;
    padding: 0 48px;
  }
  .hero-overlay h1 { font-size: 2.5rem; }
  /* A row of hero buttons, side by side — but never a FORM. The waitlist form (v0.33) has the
     .stack class too, and this rule (written before it existed) laid its email field, consent
     text and button side by side at tablet width and up: a 46px-wide email field, the consent
     wrapping a word per line, a 247px-tall button. Forms stay a column at every width. */
  .hero-overlay .stack:not(form) { flex-direction: row; }
  .hero-overlay .stack:not(form) .primary { flex: none; width: auto; padding: 0 26px; }
  #waitlist-form { flex-direction: column; }
  .hero-overlay a.secondary { flex: none; width: auto; padding: 0 26px; }

  .hero-below { padding: 32px 48px 40px; }
  .feature-list { flex-direction: row; gap: 28px; }
  .feature { flex-direction: column; gap: 8px; }
}

/* ============================================================================
   tonight.html — the 1d one-screen setup, the reading view, and rating.
   ========================================================================= */

.nav-link {
  font-size: 0.85rem;
  color: var(--accent);
  text-decoration: none;
  font-weight: 600;
}

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

/* -- "For" / child chips --------------------------------------------------- */
.child-chip-row { display: flex; flex-wrap: wrap; gap: 8px; }
.child-chip {
  flex: 1;
  min-width: 90px;
  text-align: center;
  padding: 13px 10px;
  border-radius: var(--radius-sm);
  border: 2px solid var(--border-input);
  background: var(--bg-input);
  color: var(--text-dim);
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
}
.child-chip.selected {
  border-color: var(--accent);
  background: var(--bg-input-alt);
  color: var(--text);
}

/* -- v0.57: "what makes reading a tale fun for you?" answers ---------------------- */
.enjoy-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.enjoy-chip {
  padding: 10px 14px;
  min-height: 44px;
  border-radius: 999px;
  border: 2px solid var(--border-input);
  background: var(--bg-input);
  color: var(--text-dim);
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.25;
  text-align: left;
  cursor: pointer;
}
.enjoy-chip.selected { border-color: var(--accent); background: var(--bg-input-alt); color: var(--text); }

/* -- length / bucket pills --------------------------------------------------- */
.bucket-row { display: flex; gap: 8px; }
.bucket-pill {
  flex: 1;
  text-align: center;
  padding: 12px 4px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-input);
  color: var(--text-dim);
  font-size: 0.85rem;
  cursor: pointer;
  background: transparent;
  min-height: auto;
}
.bucket-pill.selected {
  border: 2px solid var(--accent);
  background: var(--bg-input-alt);
  color: var(--text);
  font-weight: 700;
}

/* -- household mood picker (six, per BUILD-PLAN.md's step G) ----------------- */
.mood-row { display: flex; flex-wrap: wrap; gap: 8px; }
.mood-pill {
  flex: 1;
  min-width: 82px;
  text-align: center;
  padding: 12px 6px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-input);
  color: var(--text-dim);
  font-size: 0.85rem;
  cursor: pointer;
  background: transparent;
  min-height: auto;
}
.mood-pill.selected {
  border: 2px solid var(--accent);
  background: var(--bg-input-alt);
  color: var(--text);
  font-weight: 700;
}

/* -- per-child dyad sliders --------------------------------------------------- */
.dyad-row { display: flex; flex-direction: column; gap: 16px; }
.dyad-child { display: flex; flex-direction: column; gap: 4px; }
.dyad-name { font-size: 0.9rem; font-weight: 600; }
/* v0.57: both ends named, always; nothing names the value in between. */
.dyad-scale { display: flex; align-items: center; gap: 10px; }
.dyad-end { flex: none; font-family: var(--font-serif); color: var(--accent-soft); font-size: 0.9rem; }
.dyad-track {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 6px;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--accent), #3b4780);
  outline: none;
}
.dyad-track::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--text);
  box-shadow: 0 4px 12px rgba(0,0,0,.5);
  cursor: pointer;
}
.dyad-track::-moz-range-thumb {
  width: 26px; height: 26px; border: none; border-radius: 50%;
  background: var(--text); box-shadow: 0 4px 12px rgba(0,0,0,.5); cursor: pointer;
}

.eyebrow {
  font-size: 0.78rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-dimmer);
  font-weight: 600;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 4px;
}
.eyebrow small { text-transform: none; letter-spacing: 0; font-weight: 400; color: var(--text-faint); }

/* -- sticky submit ---------------------------------------------------------- */
.sticky-cta {
  position: sticky;
  bottom: 0;
  padding-top: 10px;
  margin-top: auto;
  background: linear-gradient(to top, var(--bg) 70%, rgba(18,22,43,0));
}

/* -- generating ---------------------------------------------------------- */
.generating-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 40px 20px;
  text-align: center;
}
.generating-box img { width: 130px; height: auto; } /* the only thing on this screen — Q5b */
.generating-box p { color: var(--text-dim); font-family: var(--font-serif); font-style: italic; }

/* -- reading view chrome: the toolbar around the tale surface. The tale surface
   itself (fonts, delivery-tag rendering, cue chips, night palette) is
   web/app/reading/reader.css's job — this only styles what wraps it. -- */
#reader {
  border-radius: var(--radius);
  background: var(--bg-card);
  border: 1px solid var(--border);
  padding: 22px 20px;
}
.reader-toolbar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}
.reader-toggle { display: flex; gap: 6px; }
.reader-toggle button {
  min-height: 36px;
  padding: 0 12px;
  font-size: 0.8rem;
  border-radius: 999px;
  border: 1px solid var(--border-input);
  background: transparent;
  color: var(--text-dim);
}
.reader-toggle button.active {
  background: var(--accent);
  color: var(--accent-text);
  border-color: var(--accent);
  font-weight: 700;
}
.reader-select {
  min-height: 36px;
  padding: 0 10px;
  font-size: 0.8rem;
  border-radius: 999px;
  border: 1px solid var(--border-input);
  background: var(--bg-input);
  color: var(--text-dim);
  font-family: var(--font-sans);
}

/* reader.css sets `body { font-family }` for its own standalone demo (where the
   whole page IS the reading surface) — here the page also hosts this app's own
   chrome, so .reading-content re-asserts the tale's own font explicitly rather
   than relying on inheritance winning a cascade order fight between the two
   stylesheets. Nothing else needs touching: .reading-content's background/color
   rules in reader.css are already class-scoped and win on specificity alone. */
.reading-content { font-family: var(--font-body); }

/* The "paper" theme choice (Daniel's decision on the design-pack comparison,
   logged via PATCH /auth/reading-theme) is a second palette for reader.css's own
   plain/advanced modes — not a replacement for them. reader.css exposes exactly
   the variables a theme needs to override: --bg-plain/--fg-plain (plain mode)
   and --bg-advanced/--fg-advanced (advanced/guidance mode), plus --accent for
   the cue chips. Scoped to #reader so it never leaks into the rest of the app. */
#reader[data-theme="paper"] {
  --bg-plain: #f4ecd8;
  --fg-plain: #2b2416;
  --bg-advanced: #ede2c8;
  --fg-advanced: #4a4022;
  --accent: #b5793a;
}

/* -- rating ---------------------------------------------------------- */
.star-row { display: flex; gap: 8px; justify-content: center; }
.star-btn {
  min-height: 52px;
  min-width: 52px;
  font-size: 1.6rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-input);
  background: var(--bg-input);
  color: var(--text-faint);
}
.star-btn.active { color: var(--accent); border-color: var(--accent); background: var(--bg-input-alt); }

/* -- archive: tale-detail overlay -------------------------------------------- */
.detail-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 12, 24, .88);
  z-index: 50;
  overflow-y: auto;
  padding: 20px 14px;
}
.detail-panel {
  max-width: 480px;
  margin: 0 auto;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px;
}
#detail-meta { margin: 4px 0 14px; }
#detail-checks { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }

/* Review §D4: the page underneath used to keep scrolling behind the overlay — on a
   phone that reads as two things fighting for the same gesture, not as a modal. */
body.overlay-open { overflow: hidden; height: 100%; }

/* -- error banner actions (build plan P4 / review §D5) ------------------------
   The banner used to be a dead end: no retry, no way back, and when init failed
   before rendering anything it was the only thing on the page. */
.error-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 10px;
}
.error-actions .link,
.error-actions a.link {
  font-size: 0.9rem;
  padding: 0;
  min-height: auto;
  text-decoration: underline;
}

/* -- Q5b: three ways in, and the batch loading screen ------------------------- */
.parallel-card {
  text-align: left;
  padding: 14px 16px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-input);
  background: var(--bg-input);
  color: var(--text);
  cursor: pointer;
  min-height: var(--tap);
}
.parallel-card.selected { border-color: var(--accent); background: var(--bg-input-alt); }
.parallel-card strong { display: block; font-family: var(--font-serif); font-size: 1.05rem; margin-bottom: 4px; }
.parallel-card span { color: var(--text-dim); font-size: 0.92rem; line-height: 1.45; font-weight: 400; } /* a <button> child inherits bold otherwise */
.progress-track { width: 70%; height: 4px; border-radius: 2px; background: var(--bg-input); overflow: hidden; }
.progress-fill { height: 100%; width: 4%; background: var(--accent); transition: width 0.6s ease; }

/* -- Q5c: re-roll row and post-reading verdict --------------------------------- */
.reroll-row { display: flex; flex-direction: column; gap: 6px; margin: 4px 0 14px; text-align: left; }
.reroll-row .row { gap: 8px; }
.reroll-row .row button { flex: 1; font-size: 0.78rem; padding: 4px 6px; min-height: 40px; line-height: 1.2; }
.verdict-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.verdict-btn {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 10px 4px; border-radius: var(--radius-sm); border: 1px solid var(--border-input);
  background: var(--bg-input); color: var(--text-dim); cursor: pointer; min-height: var(--tap);
}
.verdict-btn span { font-size: 1.5rem; line-height: 1; }
.verdict-btn small { font-size: 0.72rem; line-height: 1.25; font-weight: 400; }
.verdict-btn.selected { border-color: var(--accent); background: var(--bg-input-alt); color: var(--text); }

/* -- private-beta waitlist (landing) -------------------------------------------- */
.beta-notice { margin: 0; font-size: 0.92rem; line-height: 1.5; color: var(--text-dim);
  border-left: 3px solid var(--accent); padding-left: 10px; }
.consent-row { display: flex; flex-direction: row; gap: 10px; align-items: flex-start; font-size: 0.82rem; line-height: 1.45; color: var(--text-dim); }
.consent-row input { width: 20px; height: 20px; flex: none; margin-top: 1px; accent-color: var(--accent); }
.hp { position: absolute; left: -10000px; width: 1px; height: 1px; opacity: 0; }
.signin-line { margin: 0; font-size: 0.85rem; color: var(--text-dim); text-align: center; }
.signin-line .link { font-size: 0.85rem; padding: 0; min-height: auto; }
@media (min-width: 760px) { .hero-overlay form { max-width: 380px; } .hero-image { height: auto; min-height: 520px; } .hero-overlay { position: relative; padding: 48px; } }

/* -- landing hero, phone layout FIX (v0.33) -------------------------------------
   Since Q1 the hero text sat INSIDE .hero-image — a 200px box with overflow:hidden and
   a gradient ::after painted above it — so on phones the heading, subhead and (now) the
   waitlist form were clipped away and covered. The elements existed, so every DOM check
   passed; only a screenshot showed it. Phone: the image is an in-flow 200px banner and
   the text flows below it. Tablet+ (below): back to the image behind the text. */
.hero-image { height: auto; }
.hero-image img { position: relative; inset: auto; display: block; height: 200px; }
.hero-image::after { bottom: auto; height: 200px; }
.hero-overlay { position: relative; z-index: 1; padding-top: 16px; }
@media (min-width: 760px) {
  .hero-image img { position: absolute; inset: 0; height: 100%; }
  .hero-image::after { bottom: 0; height: auto; }
  .hero-overlay { padding: 48px; }
}

/* -- tap targets (v0.35) ----------------------------------------------------------
   A mobile audit (iPhone emulation, controls checked for being the topmost element at
   their centre) found text-link controls 18–22px tall — including "Sign in", the ONLY
   sign-in path on a phone, since the nav pill is tablet-only. Padding, not font size:
   they look the same, but the hit area is 44px (Apple HIG / Material guidance). */
.nav-link { display: inline-flex; align-items: center; min-height: 44px; padding: 0 4px; }
.signin-line .link { display: inline-flex; align-items: center; min-height: 44px; padding: 0 8px; }
.signin-line { display: flex; justify-content: center; align-items: center; flex-wrap: wrap; gap: 0 4px; }
.consent-row input { width: 24px; height: 24px; }

/* --- character pictures (v0.53, web/app/portraits.js) --------------------------------------- */
.avatar { display: inline-flex; align-items: center; justify-content: center; flex: none;
  border-radius: 50%; overflow: hidden; background: var(--bg-chip); color: var(--accent-soft);
  font-family: var(--serif, Georgia, serif); font-weight: 600; }
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar-sm { width: 28px; height: 28px; font-size: 0.85rem; }
.avatar-md { width: 44px; height: 44px; font-size: 1.1rem; }
.avatar-lg { width: 72px; height: 72px; font-size: 1.6rem; }
.character-head { display: flex; align-items: center; gap: 12px; }
.character-head .grow { flex: 1; min-width: 0; }
.character-head .grow strong { display: block; overflow: hidden; text-overflow: ellipsis; }
.pick-row { display: flex; align-items: flex-end; gap: 10px; }
.pick-row > label { flex: 1; }

body.sheet-open { overflow: hidden; }
.sheet-overlay { position: fixed; inset: 0; z-index: 50; background: rgba(8, 10, 24, 0.66);
  display: flex; align-items: flex-end; justify-content: center; }
.sheet { width: 100%; max-width: 520px; max-height: 92vh; overflow-y: auto; background: var(--bg-card);
  border-radius: var(--radius) var(--radius) 0 0; padding: 18px 18px calc(18px + env(safe-area-inset-bottom));
  box-shadow: 0 -8px 40px rgba(0, 0, 0, 0.4); }
@media (min-width: 640px) { .sheet-overlay { align-items: center; } .sheet { border-radius: var(--radius); } }
.sheet-head { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.sheet-head h2 { flex: 1; margin: 0; font-size: 1.15rem; }
.sheet-close { min-width: 44px; min-height: 44px; font-size: 1.6rem; line-height: 1; }
.sheet-error { color: var(--danger); margin: 6px 0; }
.sheet-footer { display: flex; flex-direction: column; gap: 6px; margin-top: 14px; }
.sheet-footer .cost-line { margin: 0; text-align: center; }
.portrait-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 10px 0; }
.portrait-tile { position: relative; padding: 0; aspect-ratio: 1; border-radius: var(--radius-sm); overflow: hidden;
  border: 2px solid transparent; background: #f6efe2; min-height: 44px; }
.portrait-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.portrait-tile.chosen { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(242, 169, 75, 0.35); }
.chosen-badge { position: absolute; left: 6px; bottom: 6px; background: var(--accent); color: var(--accent-text);
  font-size: 0.8rem; font-weight: 700; padding: 2px 8px; border-radius: 999px; }
.portrait-earlier summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; color: var(--text-dim); }
.portrait-note { font-style: italic; }
.lantern-wait { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 22px 0; text-align: center; }
.lantern-glow { width: 56px; height: 56px; border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, #fff2d4, var(--accent) 70%);
  box-shadow: 0 0 30px 8px rgba(242, 169, 75, 0.45); animation: lantern-breathe 2.4s ease-in-out infinite; }
@keyframes lantern-breathe { 0%, 100% { transform: scale(0.92); opacity: 0.8; } 50% { transform: scale(1.05); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .lantern-glow { animation: none; } }

/* --- colouring pages (v0.55, web/app/colouring.js) ------------------------------------------- */
.chip-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; margin: 8px 0; }
.char-chip { display: flex; align-items: center; gap: 10px; text-align: left; padding: 8px 10px; min-height: 56px;
  border: 2px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-input); color: var(--text); }
.char-chip.on { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(242, 169, 75, 0.3); }
.char-chip:disabled { opacity: 0.55; }
.chip-name { display: flex; flex-direction: column; min-width: 0; }
.chip-name strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scene-card { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 12px; background: var(--bg-input); }
.scene-card p { margin: 4px 0; }
.scene-card .row { margin-top: 8px; }
.scene-text { width: 100%; min-height: 84px; }
.page-preview { display: block; width: 100%; max-width: 420px; margin: 8px auto; border-radius: var(--radius-sm); background: #fff; }
.page-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.page-card { display: flex; flex-direction: column; gap: 6px; }
.page-card img { width: 100%; aspect-ratio: 1; object-fit: contain; border-radius: var(--radius-sm); background: #fff; }
.page-wait { aspect-ratio: 1; display: flex; align-items: center; justify-content: center; text-align: center; padding: 8px;
  border: 1px dashed var(--border-dashed); border-radius: var(--radius-sm); }
.page-title { font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.danger-link { color: var(--danger); }
/* a.primary and a.secondary (the PDF download) already have their styles above. */
.row > a.primary { flex: 1; }
@media (min-width: 760px) { .page-grid { grid-template-columns: repeat(4, 1fr); } }
.sub a { color: var(--accent-soft); }
