/* =========================================================================
   IOLAI Minimal -- design tokens (iteration 15, replaces "IOLAI Sketchboard")

   Direct user feedback on the v1 hand-drawn/paper look, seen live on a
   phone: "that's still sad ... i also do not like fonts and design? research
   web for simplicity/minimalism". This iteration replaces the whole visual
   language -- fonts, palette, shape, texture, rotation, shadow depth -- with
   a restrained, flat, neutral-first system grounded in real research (see
   design/NOTES.md "Iteration 15" for sources: 2026 minimalist-web-design
   trend writeups on restrained 2-3 tone palettes + purposeful whitespace,
   and the current minimal-SaaS design-system convention of Inter + a single
   dominant neutral + one accent, e.g. Linear/Vercel). Explored first via
   Stitch (design system "IOLAI Minimal", assets/56f52b17a1b24532830e04d6643b540b)
   before being hand-implemented here.

   IMPORTANT (unchanged interaction rule, only the exact hex changed):
   --terracotta is reserved EXCLUSIVELY for the bot's own, deliberately-
   incomplete marks (dashed connectors, gap-question callouts -- voice-turn
   accents are NOT terracotta -- see concept-map-readback.md). Nothing in
   this stylesheet applies terracotta to a user-authored mark.
   ========================================================================= */
:root {
  --paper-cream: #fafaf9;       /* page background -- near-white, flat, no texture */
  --paper-cream-deep: #f2f1ee;  /* secondary region background (history rail) */
  --surface: #ffffff;           /* elevated card/surface background, sits on
    top of the page background behind a hairline border -- replaces the old
    "paper-stack" shadow-based depth with flat surface + border depth. */
  --ink-slate: #1a1a1a;         /* user's own marks/content -- neutral near-
    black (was a blue-slate hue in v1; a true neutral reads calmer/quieter,
    per the "restrained 2-3 tone palette" research finding). */
  --ink-slate-soft: #6b6b6b;    /* muted neutral gray for secondary/meta text */
  --ink-slate-rgb: 26,26,26; /* same value as --ink-slate, as an r,g,b triplet
    for use inside rgba(var(--ink-slate-rgb), alpha) -- lets every alpha-
    blended border/hover-state below flip with the theme too, not just
    the solid-color uses of --ink-slate itself. */
  --terracotta: #c1592e; /* bot-only, see comment above -- a cleaner, more
    "designed" rust than v1's more muted craft-paper terracotta (#c17a54) */
  --terracotta-soft: #e0a684;
  --terracotta-rgb: 193,89,46; /* same pairing as --ink-slate-rgb, for the
    one alpha-blended terracotta use below (.tool-btn--lens.is-lens-active) */

  --font-head: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-meta: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  /* One typeface family throughout (was Comfortaa/Work Sans/Space Mono) --
     hierarchy comes from weight/size/letter-spacing/case, not from mixing
     multiple font personalities. Research: Inter is the de facto clean
     minimal-SaaS UI typeface (Linear, Vercel, GitHub); label/meta text below
     uses uppercase + letter-spacing on the SAME family instead of a
     separate "typewriter" font. */

  --radius: 8px; /* ROUND_EIGHT -- moderate, not v1's bubbly 12px */
  --shadow-paper: 0 1px 2px rgba(0, 0, 0, 0.05); /* flat/hairline register --
    depth now comes mainly from --surface + a hairline border, this shadow is
    a barely-there separation cue, not v1's heavy multi-layer paper-stack. */
}

/* =========================================================================
   Dark theme (iteration 12, re-tokened for the iteration 15 minimal palette)
   -- toggled via #theme-toggle in the toolbar, applied as `data-theme="dark"`
   on <html> (set as early as possible by the inline script in index.html's
   <head>, before first paint, and persisted to localStorage by js/app.js's
   setTheme()). Same neutral-first system as the light theme, not a v1-style
   "warm paper" dark mode -- every value below is a deliberate,
   contrast-checked re-pick that preserves the *semantics* the light theme
   uses:

   - --terracotta stays reserved EXCLUSIVELY for the bot's own marks, in
     BOTH themes (see the comment at the top of this file and
     concept-map-readback.md) -- only its exact hex changes here. The
     light-mode terracotta (#c1592e) measures under 4.5:1 contrast against
     the near-black background below, so this is a brighter variant
     (~6.7:1) rather than reusing the light-mode value verbatim, while
     staying the same hue so it still reads as "the same accent, adapted."
   - --ink-slate (the user's OWN ink -- freehand strokes, typed cards, the
     voice squiggle) becomes a near-white neutral gray so it's legible on a
     dark background (~15:1 contrast) -- same neutral hue family as the
     light-mode ink-slate, just inverted in lightness.
   - --paper-cream becomes a true neutral near-black (#121212) -- no warm
     brown undertone (that was specifically the "paper" framing v1 wanted;
     this palette drops the paper metaphor entirely for a clean neutral
     SaaS-dark-mode register, matching Linear/Vercel-style dark surfaces).
   - --shadow-paper stays a true black shadow at low opacity -- consistent
     with the flat/hairline-border depth model used everywhere else.
   ========================================================================= */
html[data-theme="dark"] {
  --paper-cream: #121212;
  --paper-cream-deep: #191919;
  --surface: #1c1c1c;
  --ink-slate: #ededed;
  --ink-slate-soft: #9a9a9a;
  --ink-slate-rgb: 237,237,237;
  --terracotta: #e07f4f;
  --terracotta-soft: #eab68c;
  --terracotta-rgb: 224,127,79;
  --shadow-paper: 0 1px 2px rgba(0, 0, 0, 0.4);
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  /* `100%`/`100vh` resolve against the "large" viewport on mobile browsers
     (i.e. as if the address bar were already hidden), which is part of what
     produced the reported "huge empty gap" bug -- the page laid itself out
     taller than what was actually visible. `dvh` tracks the real, current
     visible viewport instead; kept as a second declaration (not a
     replacement) so browsers without dvh support keep the `100%` fallback. */
  height: 100dvh;
  margin: 0;
}

body {
  background: var(--paper-cream);
  color: var(--ink-slate);
  font-family: var(--font-body);
  display: flex;
  flex-direction: column;
  /* Flat fill, no paper-fiber texture, no gradients/glow (iteration 15 --
     minimalist restraint: the background is just the background). */
  transition: background-color 0.2s ease, color 0.2s ease;
}

/* ---------- top bar ---------- */
.topbar {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.9rem 1.4rem;
  border-bottom: 1px solid rgba(var(--ink-slate-rgb), 0.1);
}
.topbar__mark {
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 1.2rem;
  letter-spacing: -0.01em;
}
.topbar__sub {
  font-family: var(--font-meta);
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--ink-slate-soft);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  /* "quiet label" register via weight/case/spacing on the same Inter family,
     not a separate monospace typeface (iteration 15 -- see design tokens
     comment at the top of this file). */
}
.topbar__auth {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  /* Telegram Login Widget script mounts its iframe here (iteration 8). */
}

/* "Signed in as [name]" label -- shown after onTelegramAuth() completes the
   (stubbed) sign-in flow. Same margin-note register as other meta text. */
.auth-status {
  font-family: var(--font-meta);
  font-size: 0.78rem;
  color: var(--ink-slate);
  padding: 0.3rem 0.6rem;
  border: 1px solid rgba(var(--ink-slate-rgb), 0.16);
  border-radius: var(--radius);
  background: var(--surface);
  white-space: nowrap;
}
.auth-status--rejected {
  color: var(--terracotta);
  border-color: var(--terracotta-soft);
}

/* ---------- phone-width topbar fix (iteration 13) ---------- */
/* Reported bug (real phone screenshot): at true phone widths the topbar's
   desktop layout -- .topbar__mark, .topbar__sub, and #auth-slot (which
   contains the Telegram Login Widget iframe + #auth-status) all forced onto
   ONE row -- overflowed horizontally. Confirmed via real Chromium at 390px:
   #auth-slot's bounding rect right edge landed at x:547 in a 390px viewport
   (157px off-screen), clipping the sign-in control entirely, matching the
   user's "sign in is out of bounds" report. Fix: wrap onto two rows below
   480px -- mark+sub stay together on row 1 (unchanged from desktop), auth
   moves to its own full-width row 2 -- rather than cramming everything into
   one row and shrinking indefinitely. Also softens the "Sketchboard"
   subtitle (the user's other complaint, "sketchboard word left top as
   well") at the very smallest widths, since it's the least essential label
   once vertical space is already tight. */
@media (max-width: 480px) {
  .topbar {
    flex-wrap: wrap;
    row-gap: 0.4rem;
    padding: 0.7rem 0.9rem;
  }
  .topbar__auth {
    margin-left: 0;
    flex: 1 1 100%;
    justify-content: flex-end;
    /* #auth-slot can hold BOTH the Telegram widget iframe (its own error
       states, e.g. "Bot domain invalid", render at a fixed width the
       iframe's own content controls, not something this stylesheet can
       resize) AND the neutral "#auth-status" label at the same time --
       their combined width can exceed the available space at the
       narrowest widths (confirmed via real Chromium: 362px combined vs
       ~331px available at 360px viewport). Let them wrap onto their own
       rows instead of forcing a fixed-width overflow. */
    flex-wrap: wrap;
  }
}
@media (max-width: 360px) {
  .topbar__sub {
    font-size: 0.68rem;
  }
}

/* ---------- workspace layout ---------- */
.workspace {
  flex: 1;
  display: flex;
  min-height: 0;
}

.canvas-pane {
  position: relative;
  flex: 1 1 75%;
  min-width: 0;
  overflow: hidden;
}

/* ---------- preimage elicitation prompt ---------- */
/* Default empty state of the canvas itself (Language-Acquisition-Theory.md
   step 1: ask "what are you trying to express?" before any label/word).
   Faint, centered, no suggested topic. Hidden as soon as any mark exists. */
.preimage-prompt {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); /* iteration 15: rotation removed --
    minimalist direction drops all hand-tilted "notebook" framing */
  font-family: var(--font-head);
  font-weight: 400;
  font-size: 1.5rem;
  letter-spacing: -0.01em;
  color: rgba(var(--ink-slate-rgb), 0.32);
  text-align: center;
  pointer-events: none;
  margin: 0;
  width: 80%;
  transition: opacity 0.2s ease;
}
.preimage-prompt.is-hidden {
  opacity: 0;
}

.draw-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  touch-action: none; /* let pointer events own drag/scroll for drawing */
  cursor: crosshair;
}

/* ---------- typed-turn layer ---------- */
.type-layer {
  position: absolute;
  left: 6%;
  bottom: 6.5rem;
  width: min(420px, 60%);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  z-index: 5;
}
/* Real bug found this iteration (12), confirmed via actual Chromium
   rendering, not static review: the browser's default UA stylesheet rule
   `[hidden] { display: none; }` has the same specificity as the `.type-layer`
   class selector above, and author styles beat UA styles at equal
   specificity -- so `display: flex` above was silently winning over the
   `hidden` attribute in index.html, and the typed-turn card was rendering
   on EVERY page load regardless of whether "type" mode was toggled on. This
   selector is specific to `.type-layer[hidden]` (higher specificity than
   `.type-layer` alone), so it correctly wins only while the attribute is
   present, and the rule above takes back over the instant js/app.js removes
   `hidden`. */
.type-layer[hidden] {
  display: none;
}
.type-card {
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--ink-slate);
  background: var(--surface);
  border: 1px solid rgba(var(--ink-slate-rgb), 0.16);
  border-radius: var(--radius);
  padding: 0.9rem 1rem;
  box-shadow: var(--shadow-paper);
  resize: vertical;
  /* crisp, flat card -- deliberately the "analytical/edited" register,
     contrasted with the voice-turn squiggle treatment below */
}
.type-card:focus {
  outline: none;
  border-color: var(--ink-slate);
}
.ghost-btn {
  align-self: flex-end;
  font-family: var(--font-meta);
  font-size: 0.75rem;
  font-weight: 500;
  background: transparent;
  border: 1px solid rgba(var(--ink-slate-rgb), 0.25);
  color: var(--ink-slate);
  border-radius: var(--radius);
  padding: 0.35rem 0.75rem;
  cursor: pointer;
}
.ghost-btn:hover {
  border-color: var(--ink-slate);
  background: rgba(var(--ink-slate-rgb), 0.04);
}

/* ---------- voice turns ---------- */
.voice-turns {
  position: absolute;
  right: 6%;
  bottom: 6.5rem;
  width: min(360px, 55%);
  display: flex;
  flex-direction: column-reverse;
  gap: 0.75rem;
  z-index: 4;
  pointer-events: none;
}
.voice-card {
  pointer-events: auto;
  background: var(--surface);
  border-radius: var(--radius);
  padding: 0.7rem 0.9rem;
  box-shadow: var(--shadow-paper);
  border: 1px solid rgba(var(--ink-slate-rgb), 0.16);
  /* iteration 15: dropped the v1 rotation/no-border "hand-drawn" card
     treatment -- the card itself is now flat/orthogonal like .type-card.
     The raw-vs-edited distinction (design/NOTES.md iteration 3, Chi et al.
     self-explanation effect) still lives entirely in the CONTENT -- the
     irregular hand-scrawled squiggle polyline below, generated the same way
     as before -- not in the card chrome. */
}
.voice-card svg {
  display: block;
  width: 100%;
  height: 34px;
}
.voice-card__squiggle {
  stroke: var(--ink-slate); /* voice is the user's own signal -> ink-slate, NOT terracotta */
  stroke-width: 2;
  fill: none;
  stroke-linecap: round;
}
.voice-card__transcript {
  margin: 0.35rem 0 0;
  font-family: var(--font-body);
  font-style: italic;
  font-size: 0.85rem;
  color: var(--ink-slate-soft);
}
.voice-card__meta {
  margin: 0.2rem 0 0;
  font-family: var(--font-meta);
  font-size: 0.68rem;
  color: var(--ink-slate-soft);
}

/* ---------- bot annotation overlay (iteration 5) ---------- */
/* concept-map-readback.md: the bot's ENTIRE response is an overlay on the
   user's own canvas -- a dashed, trailing-off terracotta connector plus a
   sketchy sticky-note callout. This is the only rule in the whole stylesheet
   that is allowed to paint terracotta as a "mark" on the canvas (everything
   else -- ink-slate strokes, voice squiggle, type cards -- stays ink-slate).
   See app.js simulateGapAnnotation() for the frontend-simulation heuristic
   that stands in for real gap-detection. */
.bot-annotation-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2; /* above the ink canvas (z-index 0/1), below toolbar/cards */
}
.bot-annotation-line {
  stroke: var(--terracotta);
  stroke-width: 2.2;
  stroke-dasharray: 7 6;
  fill: none;
  stroke-linecap: round;
}
.bot-callout-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 7; /* above toolbar-adjacent cards, reads as the "latest" mark */
}
.bot-callout {
  position: absolute;
  pointer-events: auto;
  max-width: 220px;
  background: var(--surface);
  border: 1.5px dashed var(--terracotta);
  color: var(--terracotta);
  font-family: var(--font-meta);
  font-size: 0.78rem;
  font-weight: 500;
  line-height: 1.4;
  padding: 0.55rem 0.7rem;
  border-radius: var(--radius);
  box-shadow: var(--shadow-paper);
  /* iteration 15: rotation + tape-corner flourish removed (pure v1 "sticky
     note" decoration) -- the DASHED border is KEPT unchanged, on purpose:
     per the task's hard constraint, dashedness here is the theory-grounded
     "this is provisional/incomplete, not a finished answer" cue
     (concept-map-readback.md), not paper-craft styling, so it stays flat
     but still visibly unfinished rather than becoming a polished tooltip. */
}

/* ---------- musical lens (iteration 9) ---------- */
/* Same sticky-note visual language as .bot-callout -- musical framing is a
   copy/metaphor change plus one small accompanying glyph, not a new UI
   language. See design/NOTES.md iteration 9 and app.js simulateGapAnnotation()
   for why this stays text/visual instead of real audio (Multimodal Research
   doc's own effort/theory-fit table flags audio generation as Phase 5). */
.bot-callout--musical {
  /* intentionally no separate rules yet -- reserved for future refinement if
     the musical framing needs to read distinctly at a glance; today the
     wording + the chord glyph below already carry the distinction. */
}
.bot-annotation-chord-glyph {
  /* A small wavy "unresolved chord" motif near the callout -- NOT a
     data-accurate waveform (same rationale as .voice-card__squiggle: a
     precise plot would read as the audio-app "AI slop" register ZID warns
     against). Dashed + terracotta, echoing .bot-annotation-line's
     deliberately-incomplete register. */
  stroke: var(--terracotta);
  stroke-width: 1.6;
  fill: none;
  stroke-linecap: round;
  stroke-dasharray: 4 3;
  opacity: 0.55;
}

/* ---------- toolbar (iteration 13: collapsible, design/NOTES.md) ---------- */
/* #main-toolbar (.toolbar) is now a plain positioning/chrome shell -- it
   owns the pill background/border/shadow and the absolute placement, plus
   the collapse state (`.is-collapsed`). It always shows #toolbar-toggle (a
   small tab handle, same "toggle button + CSS class + transition" pattern
   as the history rail's #rail-toggle) stacked above #toolbar-buttons, the
   actual row of draw/type/voice/submit/lens/theme/clear/end controls. User
   ask: "could we move control panel down and have an arrow somewhere to
   reopen it?" -- collapsing hides #toolbar-buttons and the outer pill
   shrinks down to just the small round toggle tab, which stays reachable to
   bring it back. */
.toolbar {
  position: absolute;
  left: 50%;
  bottom: 1.6rem;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  background: var(--surface);
  border: 1px solid rgba(var(--ink-slate-rgb), 0.14);
  border-radius: 999px;
  padding: 0.4rem;
  box-shadow: var(--shadow-paper);
  z-index: 6;
  transition: bottom 0.2s ease;
}
/* Iteration 15: fix "bottom panel doesn't move down when closed" -- when
   collapsed, the pill shrinks to just the small toggle tab but previously
   stayed anchored at the same 1.6rem offset the full 8-button row needs for
   breathing room, leaving a visually dead gap below a now-tiny control.
   Docking it closer to the true edge when collapsed reads as "tucked away
   at the bottom," matching the "move it down when closed" request. */
.toolbar.is-collapsed {
  bottom: 0.6rem;
}
.toolbar-toggle {
  border: none;
  background: transparent;
  color: var(--ink-slate-soft);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.15rem 0.7rem;
  transition: transform 0.15s ease, color 0.15s ease;
}
.toolbar-toggle:hover {
  color: var(--ink-slate);
}
/* Chevron points DOWN by default/expanded, rotates to point UP when
   collapsed -- "tap to send the panel down" / "tap to bring it back up",
   same rotate-on-collapse mechanic as .rail-toggle above. */
.toolbar.is-collapsed .toolbar-toggle svg {
  transform: rotate(180deg);
}
/* Iteration 16: real-Chromium testing (design/NOTES.md) at 320-430px with a
   larger root font-size (simulating real-world "larger text" / accessibility
   zoom settings, a common real-device cause the task explicitly asked to
   check) found the previous `.toolbar__buttons { max-height: 220px; overflow:
   hidden; }` -- a fixed, hand-picked PIXEL ceiling -- silently CLIPPED whole
   rows of buttons once the button row's real wrapped height exceeded 220px.
   That happens once root font-size grows past roughly 155-175% at these
   phone widths: at default zoom every button wraps and stays fully on-screen
   (confirmed via getBoundingClientRect at all 6 widths), but at ~160%+ zoom
   `#toolbar-buttons`'s scrollHeight exceeds its clientHeight, and
   `submit`/`musical lens`/`dark`/`clear`/`done for now` become genuinely
   invisible AND unreachable -- not visually "cut off" (no jagged edge), the
   row is just silently truncated, matching a user report of "some buttons
   are out of bounds" that doesn't show an obvious clip in a screenshot.
   Fix: `.toolbar__buttons-collapse` (new wrapper, index.html) does the
   collapse animation via a CSS-grid `1fr` -> `0fr` row-track instead of a
   guessed max-height -- this sizes to the button row's ACTUAL rendered
   height at ANY zoom level (no pixel guess to outgrow), so no future
   content/font-size change can silently clip a button again. */
.toolbar__buttons-collapse {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 0.2s ease;
}
.toolbar.is-collapsed .toolbar__buttons-collapse {
  grid-template-rows: 0fr;
}
.toolbar__buttons {
  display: flex;
  gap: 0.6rem;
  min-height: 0; /* lets this grid item shrink below its content's natural
    height when the parent grid-track above animates down to 0fr -- required
    for the grid 1fr/0fr collapse trick to work */
  overflow: hidden;
  margin-top: 0.15rem;
  transition: opacity 0.15s ease, margin-top 0.2s ease;
}
.toolbar.is-collapsed .toolbar__buttons {
  opacity: 0;
  margin-top: 0;
  pointer-events: none;
}
.tool-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  border: none;
  background: transparent;
  color: var(--ink-slate);
  font-family: var(--font-meta);
  font-weight: 500;
  font-size: 0.65rem;
  padding: 0.5rem 0.9rem;
  border-radius: var(--radius); /* iteration 15: was 999px (bubble), now
    matches the flat/grid corner radius used everywhere else */
  cursor: pointer;
}
.tool-btn:hover {
  background: rgba(var(--ink-slate-rgb), 0.08);
}
/* Deliberately no visual hierarchy implying one mode is "the" mode --
   .is-active only marks current input target, all three are equal weight. */
.tool-btn.is-active {
  background: rgba(var(--ink-slate-rgb), 0.14);
}
.tool-btn--quiet {
  color: var(--ink-slate-soft);
  border-left: 1px solid rgba(var(--ink-slate-rgb), 0.14);
  margin-left: 0.3rem;
  padding-left: 0.9rem;
}
.tool-btn--submit {
  /* Terracotta outline marks this as "hands the map to the bot" -- UI chrome
     accent only (like .is-recording below), never a canvas mark. Solid
     border now (iteration 15 drops decorative dashed borders everywhere
     except the theory-required bot-annotation connector/callout). */
  color: var(--terracotta);
  border: 1px solid var(--terracotta-soft);
  margin-left: 0.3rem;
}
.tool-btn--submit:hover {
  border-color: var(--terracotta);
  background: rgba(var(--terracotta-rgb), 0.06);
}
.tool-btn.is-recording {
  color: var(--terracotta); /* transient recording state indicator only --
    not a user "mark" on the canvas, so this is the one UI accent exception;
    the recorded voice-card itself still renders ink-slate, not terracotta */
  animation: pulse 1.1s ease-in-out infinite;
}
.tool-btn--lens {
  /* Musical lens toggle (iteration 9) -- a persistent view-mode toggle, not
     a transient action like submit/clear/end, so it keeps its accent when
     active rather than flashing back off. Quiet/muted when off, matching
     .tool-btn--quiet's understated register; terracotta-tinted only when
     active -- same UI-chrome-accent precedent as .tool-btn--submit and
     .is-recording (chrome only, never a canvas mark). */
  color: var(--ink-slate-soft);
  border: 1px solid rgba(var(--ink-slate-rgb), 0.14);
  margin-left: 0.3rem;
}
.tool-btn--lens:hover {
  border-color: rgba(var(--ink-slate-rgb), 0.35);
}
.tool-btn--lens.is-lens-active {
  color: var(--terracotta);
  border-color: var(--terracotta-soft);
  background: rgba(var(--terracotta-rgb), 0.08);
}
.tool-btn--theme {
  /* Dark-theme toggle (iteration 12) -- a persistent view preference like
     .tool-btn--lens, not a transient action, so it keeps the same "quiet
     until relevant" treatment: muted ink-slate when off. Deliberately
     ink-slate, never terracotta -- this is app chrome, not a bot mark, and
     terracotta stays reserved for the bot per the rule at the top of this
     file. */
  color: var(--ink-slate-soft);
  border: 1px solid rgba(var(--ink-slate-rgb), 0.14);
  margin-left: 0.3rem;
}
.tool-btn--theme:hover {
  border-color: rgba(var(--ink-slate-rgb), 0.35);
}
.tool-btn--theme.is-theme-dark {
  color: var(--ink-slate);
  border-color: var(--ink-slate-soft);
  background: rgba(var(--ink-slate-rgb), 0.1);
}
.tool-btn--end {
  /* "canvas collapses to the side" trigger (iteration 6) -- an action like
     submit/clear, not a fourth input modality, so it gets its own visual
     treatment (solid ink-slate, not the bot's terracotta) rather than
     joining the equal-weight draw/type/voice trio. */
  color: var(--ink-slate);
  border: 1px solid rgba(var(--ink-slate-rgb), 0.35);
  margin-left: 0.3rem;
}
.tool-btn--end:hover {
  background: rgba(var(--ink-slate-rgb), 0.1);
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

/* ---------- history rail ---------- */
.history-rail {
  flex: 0 0 25%;
  max-width: 340px;
  min-width: 220px;
  border-left: 1px solid rgba(var(--ink-slate-rgb), 0.1);
  background: var(--paper-cream-deep);
  display: flex;
  flex-direction: column;
  transition: flex-basis 0.15s ease, max-width 0.15s ease, min-width 0.15s ease, padding 0.15s ease;
  overflow: hidden;
}
.history-rail.is-collapsed {
  flex-basis: 0;
  max-width: 0;
  min-width: 0;
  border-left: none;
}
.history-rail__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 1.1rem 0.5rem;
}
.history-rail__header h2 {
  font-family: var(--font-head);
  font-size: 1rem;
  margin: 0;
}
.rail-toggle {
  border: 1px solid rgba(var(--ink-slate-rgb), 0.2);
  background: var(--surface);
  color: var(--ink-slate);
  border-radius: 50%;
  width: 1.7rem;
  height: 1.7rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  line-height: 1;
  transition: transform 0.15s ease;
  flex: none; /* iteration 13: on mobile this header sits in a row with the
    "My Notebook" heading -- without this the toggle's own circular box
    could get squeezed by flex if the heading text is long; keep it a fixed
    circle regardless of container width. */
}
/* Chevron points DOWN by default/expanded (iteration 13, per user feedback
   on rail-toggle direction), rotates to point UP when collapsed -- reads as
   "closed, tap to bring back down." */
.history-rail.is-collapsed .rail-toggle {
  transform: rotate(180deg);
}
.history-rail__cards {
  flex: 1;
  overflow-y: auto;
  padding: 0.5rem 1.1rem 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

/* Stub thumbnail cards -- hardcoded placeholders, no backend session data
   wired yet. Iteration 15: dropped the torn-paper jagged clip-path and the
   per-card rotation classes in favor of a plain flat rounded rectangle with
   a hairline border -- content sits on a calm, aligned grid instead of a
   "scattered notebook" look. The .thumb-card--rot-N classnames are still
   assigned by js/app.js's cycling logic (harmless, now inert -- no CSS rule
   targets them, so no behavior change was needed there). */
.thumb-card {
  position: relative;
  background: var(--surface);
  border: 1px solid rgba(var(--ink-slate-rgb), 0.12);
  border-radius: var(--radius);
  box-shadow: var(--shadow-paper);
  padding: 0.75rem 0.85rem 0.6rem;
}

.thumb-card__scrap {
  height: 54px;
  border-radius: 4px;
  margin-bottom: 0.5rem;
  background: var(--paper-cream-deep);
  /* flat placeholder standing in for a future real canvas snapshot
     thumbnail -- iteration 15 drops the decorative repeating-stripe
     "sketch" texture in favor of a plain neutral fill */
}
/* Real snapshot cards (iteration 6, pushed by js/app.js pushHistoryEntry()) --
   an actual composited canvas.toDataURL() PNG in place of the placeholder
   fill above. Same flat card as the example cards -- only the fill differs. */
.thumb-card__scrap--real {
  background-color: var(--paper-cream-deep);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
.thumb-card__label {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.85rem;
}
.thumb-card__label em {
  font-style: normal;
  font-family: var(--font-meta);
  font-size: 0.68rem;
  color: var(--ink-slate-soft);
}
.thumb-card__date {
  margin: 0.15rem 0 0;
  font-family: var(--font-meta);
  font-size: 0.7rem;
  color: var(--ink-slate-soft);
}

/* ---------- small screens ---------- */
@media (max-width: 720px) {
  .workspace { flex-direction: column; }
  .history-rail {
    flex: 0 0 auto;
    max-width: none;
    border-left: none;
    border-top: 1px solid rgba(var(--ink-slate-rgb), 0.1);
  }
  .history-rail__cards { flex-direction: row; overflow-x: auto; }
  .type-layer, .voice-turns { width: 80%; }

  /* Reported bug (iteration 13): on mobile, .workspace switches to
     flex-direction: column (above), which flips .history-rail's own main
     axis from horizontal to vertical -- so the DESKTOP .is-collapsed rule
     (flex-basis: 0; max-width: 0; min-width: 0;), which was written to
     collapse a *width*, ends up collapsing the rail's *height* to ~0
     instead. Confirmed via real Chromium at 390px: after clicking
     #rail-toggle, #history-rail's box shrank to 0x1px and -- because
     .history-rail__header (containing the toggle button itself) is INSIDE
     that same collapsing, overflow:hidden box -- the toggle button
     disappeared along with the cards, leaving no way to tap it again to
     re-expand. Fix: on mobile, collapsing only hides the cards row;
     .history-rail__header (title + toggle) always stays visible and
     reachable, exactly the "predictable" behavior asked for. */
  .history-rail.is-collapsed {
    flex-basis: auto;
    max-width: none;
    min-width: 0;
    /* Iteration 15: fix "bottom panel doesn't move down when closed". On
       mobile, .workspace (flex-direction: column) is exactly the remaining
       viewport height, but .canvas-pane is height-capped (min/max-height
       below) -- once the rail collapses down to just its header, the two
       children together no longer fill .workspace, leaving a dead empty
       gap at the true bottom of the screen, below the now-small header.
       margin-top: auto pushes this flex item to consume all that leftover
       space ABOVE itself, so the collapsed header genuinely docks flush
       against the bottom edge instead of floating with empty space under
       it -- reads as "tucked away at the bottom," per the request. */
    margin-top: auto;
  }
  .history-rail.is-collapsed .history-rail__cards {
    display: none;
  }

  /* Reported bug (iteration 12): on a real phone, .canvas-pane's desktop
     sizing (`flex: 1 1 75%` of a .workspace whose own height is only
     implicitly constrained by the body flexbox) read as a huge empty gap
     between the header and the toolbar/input row -- worsened by `height:
     100%` on html/body (see below) resolving against the "large" viewport
     (address bar hidden) rather than what's actually visible, so the
     canvas pane's real rendered height didn't track the visible screen.
     Bounding it explicitly here makes it track the *actual* viewport (dvh,
     with a vh fallback for browsers/engines that don't support dvh) and
     caps how much of the screen an empty canvas is allowed to dominate. */
  .canvas-pane {
    flex: 1 1 auto;
    min-height: 42vh;
    min-height: 42dvh;
    max-height: 62vh;
    max-height: 62dvh;
  }

  /* Iteration 15: fix "toolbar doesn't move down when closed" (the other
     half of the same bug the .history-rail.is-collapsed margin-top:auto
     above fixes). The toolbar is `position: absolute` inside .canvas-pane,
     anchored near ITS bottom edge -- but .canvas-pane's own height is capped
     above (62dvh) specifically to leave room for the full 8-button toolbar
     plus the expanded history rail below it. Once the toolbar collapses
     down to a small tab, that reserved headroom is no longer needed, but
     the cap stayed fixed, so the collapsed tab still sat near the OLD
     (now much too high) canvas-pane bottom edge, with a large dead gap
     between it and the true screen edge. :has() lets .canvas-pane relax its
     own height cap specifically when it contains a collapsed toolbar, so it
     grows to fill the freed-up space and the toolbar's own anchor point
     moves down with it -- reading as "tucked at the bottom" instead of
     floating mid-screen. (Chromium supports :has(); jsdom does not, so
     test/smoke.mjs can only assert this rule's text is present, not that it
     visually applies -- same documented limitation as the other @media
     checks in that file.)

     Iteration 16: user's exact ask ("green selected part [toolbar] --
     could be moved down when my notebook is closed?") is about the
     HISTORY RAIL's collapsed state, not just the toolbar's own -- the two
     panels collapse independently, and this rule only covered the case
     where the TOOLBAR was the one collapsed. Confirmed via real Chromium
     at 390/430px: collapsing ONLY the rail (toolbar left open) already
     correctly docks the rail header flush to the viewport bottom (the
     iteration-15 margin-top:auto fix above), but the toolbar itself never
     moved -- canvas-pane stayed capped at 62dvh regardless of the rail's
     state, leaving a measured 195.8px dead gap between the open toolbar's
     bottom edge and the collapsed rail header. Second :has() clause below
     (general sibling combinator -- .canvas-pane is #history-rail's
     preceding sibling inside .workspace) relaxes the same height cap
     whenever the RAIL is collapsed, independent of the toolbar's own
     state, so .canvas-pane grows and the toolbar's bottom-anchored
     position drops down with it to close that gap -- exactly like the
     existing toolbar-collapsed case, just triggered by the other panel. */
  .canvas-pane:has(.toolbar.is-collapsed),
  .canvas-pane:has(~ .history-rail.is-collapsed) {
    max-height: none;
  }
}

/* ---------- phone-width toolbar fix (iteration 12) ---------- */
/* Reported bug: at true phone widths (~390-430px, confirmed with a real
   headless Chromium instance -- see design/NOTES.md iteration 12) the
   toolbar's desktop layout (`left: 50%; transform: translateX(-50%)`,
   unconstrained button widths) rendered wider than the viewport itself --
   measured ~510px wide in a 390px viewport, overflowing both edges -- so
   the rightmost buttons (musical-lens/theme/clear/end-session) were
   unreachable, not just visually clipped. Below this breakpoint the
   toolbar switches from "one centered pill sized by its content" to "inset
   from both viewport edges, wrapping onto a second row" so every button
   stays on-screen and reachable without horizontal scrolling. */
@media (max-width: 480px) {
  .toolbar {
    left: 0.5rem;
    right: 0.5rem;
    bottom: 0.5rem;
    transform: none;
    width: auto;
    border-radius: 20px;
    padding: 0.45rem;
  }
  /* Iteration 13: when collapsed on mobile, don't stay stretched full-width
     (the `left/right: 0.5rem` insets above would otherwise force a
     full-width bar even with nothing but the toggle showing) -- recenter
     as a small tab, same shrink-to-content behavior the desktop toolbar
     already has via `left: 50%; transform: translateX(-50%)`. */
  .toolbar.is-collapsed {
    left: 50%;
    right: auto;
    transform: translateX(-50%);
    width: auto;
  }
  .toolbar__buttons {
    flex-wrap: wrap;
    justify-content: center;
    row-gap: 0.35rem;
    width: 100%;
  }
  .tool-btn {
    padding: 0.4rem 0.55rem;
    font-size: 0.6rem;
  }
  /* The hairline left-divider look these carry on desktop (a visual
     "this is a group of actions, not a fourth input mode" cue) reads as a
     stray line when the button wraps to the start of a new row, so drop
     both the divider and its margin at this width -- the wrapped grouping
     plus reduced gap already convey "separate from draw/type/voice." */
  .tool-btn--quiet,
  .tool-btn--submit,
  .tool-btn--lens,
  .tool-btn--theme,
  .tool-btn--end {
    margin-left: 0;
    border-left: none;
  }
}
