/* ============================================================
   Markdown To — the playground  (site/app/index.html)

   The workbench of the same publication. ../styles.css loads
   first and carries the whole system — the typography, the
   vermillion, the tokens, the inked plate — and this file adds
   only the bench: a control rail, two panes, and the status line
   between them.

   Light is the primary design; the dark block at the end is the
   automatic prefers-color-scheme variant, derived from it. Every
   token used here is one ../styles.css already defines, so a
   value tuned there stays tuned here.

   Two rules govern the layout:

     · The page never scrolls sideways. The editor scrolls inside
       its textarea, the rendered document scrolls inside its
       iframe, and the rail wraps.
     · The panes are side by side from 900px and stacked below it,
       where a segmented control chooses which one is on screen —
       two half-width panes on a phone would be two useless panes.

   No arrow glyphs: the subset fonts have none.
   ============================================================ */

/* ------------------------------------------------------------
   0. Bench-only tokens
   ------------------------------------------------------------ */
:root {
  /* The editor's metrics live in variables because the gutter has
     to agree with the textarea to the pixel — one line-height,
     one font-size, one top padding, read by both. */
  --ed-size: 0.8rem;
  --ed-line: 1.75;
  --ed-pad-y: 1rem;
  --ed-gutter: 3.1rem;

  /* The bench runs wider than the publication's --wide (74rem).
     It is not a column of prose: the rendered pane has to clear
     44rem on its own, because that is the width at which the
     renderers lay a board out as columns rather than stacking it —
     and a playground for a board format that cannot show a board
     side by side with its source has missed the point. The topbar
     and the colophon are widened to match so the page still reads
     as one measure. */
  --bench: min(100%, 92rem);

  /* A resolved severity palette, matching specs/specs.css. */
  --sev-ok:    #2f6a3f;
  --sev-warn:  #8a5f0e;
  --sev-err:   var(--acc);
  --tint-ok:   #eef5ef;
  --tint-warn: #faf3e6;
}

/* The bench is a fixed-height application surface, not an
   article: the panes fill what is left of the viewport rather
   than growing a page that scrolls past them. */
.app { min-height: 100dvh; display: flex; flex-direction: column; }
.app .foot { margin-top: auto; padding-top: clamp(1.6rem, 3vw, 2.4rem); }

.app .topbar__in,
.app .foot__rule { max-width: var(--bench); }

.bench {
  width: 100%;
  max-width: var(--bench);
  margin-inline: auto;
  padding: clamp(1.4rem, 3.4vw, 2.6rem) clamp(1rem, 4vw, 2.5rem) clamp(1.6rem, 3vw, 2.4rem);
  display: flex;
  flex-direction: column;
  gap: clamp(.9rem, 1.8vw, 1.25rem);
}

/* ------------------------------------------------------------
   1. Head — a masthead for a tool, not for an article

   The publication's display scale is right for a page you read
   and wrong for a page you work in: at 3.1rem the title and its
   lede took the first third of the window every time, and what
   the window is for is the two panes underneath. So the title
   drops to a size that still opens the page and no longer owns
   it, and the lede runs wider and smaller so the same sentences
   take three lines instead of five. Nothing here is hidden and
   nothing collapses on interaction — the network sentence has to
   be legible on first load and on every load after it.
   ------------------------------------------------------------ */
.bench__head { max-width: 64rem; }
.bench__title {
  font-size: clamp(1.5rem, 1.05rem + 1.5vw, 2.15rem);
  line-height: 1.06;
  letter-spacing: -.021em;
  font-weight: 400;
  text-wrap: balance;
}
.bench__lede {
  margin-top: .5rem;
  max-width: 60rem;
  font-size: .88rem;
  line-height: 1.55;
  color: var(--ink-2);
  text-wrap: pretty;
}
.bench__lede em { font-style: italic; color: var(--ink); }

/* ------------------------------------------------------------
   2. Control rail
   ------------------------------------------------------------ */
.rail {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: .7rem 1.1rem;
  margin-top: clamp(.4rem, 1.4vw, .9rem);
}
.rail__set { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.rail__set--end { margin-left: auto; }
.rail__lbl {
  font-family: var(--font-mono);
  font-size: .6rem;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Format starters, grouped by what a person is trying to do. The groups are
   quiet capsules rather than a second navigation bar; they wrap as units. */
.rail__set--examples {
  display: grid;
  align-items: start;
  gap: .38rem;
}
.rail__examples-picker {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem;
}
.format-description {
  min-height: 1.1em;
  max-width: 76ch;
  font-size: .74rem;
  line-height: 1.45;
  color: var(--ink-2);
  text-wrap: pretty;
}
.seg {
  display: inline-flex;
  flex-wrap: wrap;
  gap: .38rem;
}
.seg__group {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .2rem;
  background: var(--paper-3);
  border-radius: 100px;
  padding: .26rem;
  padding-left: .62rem;
  max-width: 100%;
}
.seg__group-label {
  margin-right: .08rem;
  font-family: var(--font-mono);
  font-size: .49rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.seg__b {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: -.005em;
  color: var(--ink-2);
  padding: .38rem .85rem;
  border-radius: 100px;
  transition: color .18s, background .18s, box-shadow .18s;
}
.seg__b:hover { color: var(--ink); }
.seg__b[aria-pressed="true"] {
  color: var(--ink);
  background: var(--card);
  font-weight: 500;
  box-shadow: var(--shadow-s), var(--ring);
}
.seg__b--soon,
.seg__b--soon:hover {
  display: inline-flex;
  align-items: center;
  gap: .42rem;
  cursor: not-allowed;
  color: var(--ink-3);
  background: transparent;
  box-shadow: none;
}
.seg__soon {
  padding: .14rem .34rem .12rem;
  border-radius: 100px;
  background: var(--card);
  font-size: .46rem;
  font-weight: 600;
  letter-spacing: .08em;
  line-height: 1;
  text-transform: uppercase;
  color: var(--ink-3);
  box-shadow: var(--ring);
}

/* Open / Download. `.pill` is `.btn` at the rail's scale — the
   label wraps a hidden file input, which is why it is a label. */
.pill {
  position: relative;          /* holds the visually hidden file input */
  display: inline-block;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .005em;
  padding: .52rem 1.05rem;
  border-radius: 100px;
  background: var(--card);
  color: var(--ink-2);
  box-shadow: var(--shadow-s), var(--ring);
  transition: box-shadow .22s cubic-bezier(.2,.8,.3,1),
              transform .22s cubic-bezier(.2,.8,.3,1), color .2s, background .2s;
}
.pill:hover { color: var(--ink); box-shadow: var(--shadow-m), var(--ring); transform: translateY(-1px); }
.pill:has(input:focus-visible) { outline: 2px solid var(--acc); outline-offset: 3px; }
.pill input[type="file"] {
  position: absolute; width: 1px; height: 1px;
  opacity: 0; overflow: hidden; clip: rect(0 0 0 0);
}
.pill--go { color: var(--acc); background: var(--tint); }
.pill--go:hover { color: var(--acc); }
/* `.pill` supplies display, so the element-level `hidden` contract must outrank it explicitly. */
.pill[hidden] { display: none; }

/* Save to Hub is the only control here that leaves the machine, so
   it is deliberately the quietest of the three on the right: plain
   `.pill`, no accent, no mark. Download is the accented one because
   it is the promise this page makes to everybody; saving is the one
   it makes to whoever has an account. While a save is in flight the
   control says so and stops taking presses. */
.pill--hub[aria-busy="true"] { color: var(--ink-3); cursor: progress; }

/* Present carries a mark because it is the one control on the rail
   that changes what the *page* is rather than what the file is.
   Four corner brackets, drawn — the subset fonts have no glyph for
   this and every mark on this site is a path. */
.pill--present { display: inline-flex; align-items: center; gap: .5rem; }
.pill--present[aria-pressed="true"] { color: var(--ink); background: var(--paper-3); }
.pill__i {
  width: .86em;
  height: .86em;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* File and directory examples share one selector. Their source unit is
   implementation metadata; the visible choices stay typographically equal. */
.rail__set--examples .seg { flex-wrap: wrap; }

/* A directory-scoped example uses the same workbench shell but a
   full-measure render surface. The app owns the directory handle and
   mounts the self-contained renderer directly: one host, one sandbox. */
.pane--view > .workspace-stage-embed { display: none; }
.workspace-controls { align-items: center; gap: .55rem; }
[data-workspace-ui][hidden] { display: none; }
.workspace-controls__status {
  max-width: 30ch;
  color: var(--ink-3);
  font-size: .62rem;
  line-height: 1.35;
}
.is-workspace [data-file-ui],
.is-workspace #status,
.is-workspace .hint { display: none; }
.is-workspace .statusbar { min-height: 0; }
.is-workspace .statusbar:has(.hubline[hidden]) { display: none; }
.is-workspace .rail__set--examples { margin-right: auto; }
.is-workspace .rail__set--present { margin-left: auto; }
.is-workspace .panes {
  height: clamp(34rem, 70dvh, 58rem);
}
.is-workspace .pane--view > .stage:not(.workspace-stage-embed) { display: none; }
.is-workspace .workspace-stage-embed { display: block; }
.is-workspace #fname { display: none; }
[data-workspace-source][hidden] { display: none; }
.is-workspace .workspace-file:not([hidden]) { display: block; }
.is-workspace .workspace-source-actions:not([hidden]) { display: flex; }

@media (max-width: 760px) {
  .workspace-controls { width: 100%; }
  .workspace-controls__status { margin-right: auto; max-width: 17ch; }
}

@media (max-width: 520px) {
  .is-workspace .pane__meta { display: none; }
}

/* ------------------------------------------------------------
   3. The status bar — one instrument, two zones

   The parse zone answers "what is this file"; the Hub zone
   answers "where is it, and whose". They were two stacked bars a
   full line apart and read as two unrelated readouts. They now
   share one row whenever there is room for one, and the only
   thing separating the zones is space: the gap between them is
   twice the gap inside either, which is enough for the eye and
   is one drawn element fewer than a rule would have been.

   The DOM stays two elements — index.html says why, and it is
   not cosmetic: the parse line is rebuilt on every keystroke and
   the Hub line has to survive that.
   ------------------------------------------------------------ */
.statusbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: 1.5rem;
  row-gap: .15rem;
  min-height: 2.1rem;
}
/* ../styles.css carries a `.status` of its own — the note under a
   tier card on the landing page — and it loads first. This line has
   been silently wearing that one's `margin-top: 1.9rem` and
   `max-width: 46rem` the whole time: the margin is why the bar sat
   a third further from the rail than the page's own rhythm asked
   for, and the max-width is why the Hub zone could never use the
   width it was given, whatever the flex basis said. Both are
   answered here. Renaming one of the two classes is the real fix
   and belongs to whoever owns the landing page's markup. */
.statusbar .status { margin: 0; max-width: none; line-height: 1.5; }
.status {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .45rem .7rem;
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .01em;
  color: var(--ink-2);
}
.sev {
  font-size: .62rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  padding: .26rem .68rem .22rem;
  border-radius: 100px;
  font-weight: 600;
  white-space: nowrap;
}
.sev--ok    { color: var(--sev-ok);   background: var(--tint-ok); }
.sev--warn  { color: var(--sev-warn); background: var(--tint-warn); }
.sev--error { color: var(--sev-err);  background: var(--tint); }
.status__spec { color: var(--ink); font-weight: 500; }
/* "3 cards across 3 columns" — the one thing on this line the
   rendered frame also says, in its own caption, and says better:
   that one is recomputed by the board after every drag and counts
   what is done as well as what is there. From 900px both are on
   screen at once and this is the copy that steps back. Below it
   only one pane is visible at a time, so it stays and is the only
   place the shape is stated. `is-live` is set by app.js §4 when
   the frame it just mounted is a live board. */
@media (min-width: 900px) {
  .is-live .status__shape { display: none; }
}
/* The jump control is a real button: it moves the caret to the
   line and column the diagnostic names. */
.jump {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: .72rem;
  color: var(--acc);
  border-radius: var(--r-xs);
  padding: .1rem .15rem;
  text-decoration: underline;
  text-decoration-color: var(--acc-line);
  text-underline-offset: .2em;
}
.jump:hover { text-decoration-color: var(--acc); }

/* ---------- the Hub zone ----------
   Same idiom, at the other end of the same row, and absent
   entirely until there is an account to talk about — `hidden` has
   to be spelled out because `.status` sets `display: flex` and
   would otherwise outrank the user-agent's rule for it. It takes
   the rest of the row so its identity chip lands at the far edge
   of the bar rather than halfway across it, and drops to its own
   line when the two zones no longer fit on one. Its controls are
   `.jump`s: a real button in a status line is a pattern this page
   already has. */
.hubline { flex: 1 1 20rem; }
.hubline[hidden] { display: none; }

/* The conflict band. Every other hub state is bookkeeping; this
   one is a decision with a destructive branch, so the whole zone
   steps forward — full row, vermillion ground, ringed — instead
   of asking a small chip to carry it. */
.hubline--conflict {
  flex-basis: 100%;
  padding: .6rem .9rem;
  border-radius: var(--r);
  background: var(--tint);
  box-shadow: inset 0 0 0 2px var(--acc-line);
}
.hubline--conflict .sev {
  font-size: .72rem;
  padding: .32rem .85rem .28rem;
}
.hubline--conflict .jump {
  color: var(--acc);
  font-weight: 600;
  text-decoration-thickness: 2px;
}
/* Identity sits at the far end, quieter than anything it shares the
   line with: it is context, not an instruction. */
.hubline__who {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  color: var(--ink-3);
}
.jump--quiet { color: var(--ink-3); text-decoration-color: var(--rule-soft); }
.jump--quiet:hover { color: var(--ink-2); text-decoration-color: var(--ink-3); }
/* A URL is the one thing here that can be long. It wraps rather
   than pushing the page sideways, which §0's first rule forbids. */
.hublink { overflow-wrap: anywhere; max-width: min(100%, 34rem); }
/* Work in flight is not a severity, so it reads as neither: the
   badge shape, in the page's own grey. */
.sev--work { color: var(--ink-2); background: var(--paper-3); }

/* ---------- narration studio ----------
   A manuscript earns one compact listening rail between its truth line and its two panes. It is
   intentionally an instrument, not a dashboard: one chapter, one delivery, one preview.
   The Gemini credential remains server-held; this surface only ever carries the Hub session
   already owned by the page. */
.narration {
  display: grid;
  grid-template-columns: minmax(13rem, 1fr) minmax(0, 2.2fr);
  gap: 1rem 1.5rem;
  align-items: center;
  padding: .9rem 1rem;
  border-radius: var(--r);
  background: color-mix(in srgb, var(--tint) 48%, var(--card));
  box-shadow: inset 0 0 0 1px var(--acc-line);
}
.narration[hidden] { display: none; }
.narration__eyebrow {
  display: block;
  margin-bottom: .2rem;
  font-family: var(--font-mono);
  font-size: .56rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--acc);
}
.narration h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 400;
  line-height: 1.08;
  color: var(--ink);
}
.narration__intro p {
  margin: .35rem 0 0;
  font-size: .73rem;
  line-height: 1.45;
  color: var(--ink-2);
  text-wrap: pretty;
}
.narration__controls {
  display: grid;
  grid-template-columns: minmax(8rem, 1.2fr) minmax(8rem, 1.2fr) minmax(5.6rem, .7fr) auto;
  gap: .45rem;
  align-items: end;
}
.narration__field {
  display: grid;
  gap: .22rem;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: .57rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.narration__field select {
  min-width: 0;
  width: 100%;
  border: 1px solid var(--rule);
  border-radius: var(--r-xs);
  background: var(--card);
  color: var(--ink);
  padding: .48rem .55rem;
  font: 500 .71rem/1.2 var(--font-mono);
  letter-spacing: 0;
  text-transform: none;
}
.narration__field select:focus-visible,
.narration__preview:focus-visible,
.narration__generate:focus-visible,
.narration__hub-link:focus-visible,
.narration__download:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }
.narration__field select:disabled { color: var(--ink-3); cursor: wait; }
.narration__preview,
.narration__generate,
.narration__hub-link,
.narration__download {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.15rem;
  padding: .5rem .85rem;
  border-radius: 100px;
  background: var(--acc);
  color: #fff;
  font: 600 .68rem/1 var(--font-mono);
  letter-spacing: .01em;
  white-space: nowrap;
  transition: transform .18s, box-shadow .18s;
}
.narration__preview:hover,
.narration__generate:hover,
.narration__hub-link:hover,
.narration__download:hover { transform: translateY(-1px); box-shadow: var(--shadow-s); }
.narration__preview:disabled,
.narration__generate:disabled { cursor: progress; opacity: .62; transform: none; }
.narration__generate {
  grid-column: 1 / -1;
  justify-self: end;
  border-color: var(--ink);
  background: var(--ink);
}
.narration__result {
  grid-column: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem .8rem;
  min-height: 1.25rem;
}
.narration__status {
  margin: 0;
  font: .65rem/1.35 var(--font-mono);
  color: var(--ink-2);
}
.narration__audio { height: 2rem; max-width: min(100%, 21rem); }
.narration__download,
.narration__hub-link { background: var(--card); color: var(--acc); box-shadow: var(--ring); }
.narration__audio[hidden],
.narration__download[hidden],
.narration__hub-link[hidden] { display: none; }
@media (max-width: 980px) {
  .narration { grid-template-columns: 1fr; }
  .narration__result { grid-column: 1; }
}
@media (max-width: 620px) {
  .narration__controls { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .narration__field--pace { grid-column: 1; }
  .narration__preview { grid-column: 2; }
  .narration__generate { grid-column: 1 / -1; width: 100%; }
}

/* ------------------------------------------------------------
   4. The pane switch (narrow screens only)
   ------------------------------------------------------------ */
.swap {
  display: inline-flex;
  gap: .25rem;
  background: var(--paper-3);
  border-radius: 100px;
  padding: .26rem;
  width: fit-content;
}
.swap__b {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: .72rem;
  color: var(--ink-2);
  padding: .4rem 1.1rem;
  border-radius: 100px;
  transition: color .18s, background .18s, box-shadow .18s;
}
.swap__b[aria-pressed="true"] {
  color: var(--ink);
  background: var(--card);
  font-weight: 500;
  box-shadow: var(--shadow-s), var(--ring);
}
@media (min-width: 900px) { .swap { display: none; } }

/* ------------------------------------------------------------
   5. The two panes
   ------------------------------------------------------------ */
.panes {
  display: grid;
  gap: clamp(.9rem, 2vw, 1.4rem);
  grid-template-columns: minmax(0, 1fr);
  /* The panes are the product, so they deliberately dominate the
     viewport and let the explanatory note fall below the fold. dvh
     keeps the single mobile pane clear of collapsing browser chrome. */
  height: clamp(30rem, 76dvh, 60rem);
}
/* The editor column is sized backwards from the rendered pane: it
   takes what is left after the frame has enough room to draw a
   board as columns (44rem inside the renderer's own stylesheet).
   Below that the board stacks, which is the renderer being right
   about a narrow viewport, not this page being wrong. */
@media (min-width: 900px) {
  .panes {
    grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
    height: clamp(36rem, 80dvh, 68rem);
  }
}
@media (min-width: 1200px) { .panes { grid-template-columns: minmax(0, 24rem) minmax(0, 1fr); } }
@media (min-width: 1440px) { .panes { grid-template-columns: minmax(0, 30rem) minmax(0, 1fr); } }

/* Below 900px exactly one pane is on screen at a time. */
@media (max-width: 899px) {
  .panes[data-show="edit"] .pane--view,
  .panes[data-show="view"] .pane--edit { display: none; }
}

.pane {
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--r);
  background: var(--card);
  box-shadow: var(--shadow-m), var(--ring);
}
/* The source pane is inked in both schemes, like every code plate
   on this site: a dark card is what makes a file read as a file. */
.pane--edit { background: var(--plate); box-shadow: var(--shadow-m); }

.pane__bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .62rem .95rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .02em;
  color: var(--ink-3);
  border-bottom: 1px solid var(--rule-soft);
}
.pane__bar--ink { color: var(--plate-dim); border-bottom-color: var(--plate-rule); }
.pane__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--plate-acc); flex: none; }
.pane__name { font-size: .62rem; letter-spacing: .12em; text-transform: uppercase; font-weight: 500; }
.pane__meta,
.pane__tag {
  margin-left: auto;
  font-size: .6rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
}
.pane__tag {
  color: var(--ink-3);
  background: var(--paper-2);
  border-radius: 100px;
  padding: .18rem .58rem .14rem;
}

/* the editable file name, drawn as text until you touch it */
.fname {
  flex: 1 1 8rem;
  min-width: 0;
  font: inherit;
  font-weight: 500;
  color: var(--plate-fg);
  background: none;
  border: 0;
  border-radius: var(--r-xs);
  padding: .12rem .3rem;
  margin-left: -.3rem;
  transition: background .18s;
}
.fname:hover { background: var(--plate-2); }
.fname:focus { background: var(--plate-2); outline: 2px solid var(--plate-acc); outline-offset: 1px; }

/* A collection still has one source at the caret. The select says which
   workspace member the shared textarea is holding; Save and Cancel keep a
   raw draft explicit instead of writing a local folder on every keystroke. */
.workspace-file {
  flex: 1 1 8rem;
  min-width: 0;
  appearance: none;
  font: inherit;
  font-weight: 500;
  color: var(--plate-fg);
  background: var(--plate-2);
  border: 0;
  border-radius: var(--r-xs);
  padding: .26rem 1.45rem .26rem .42rem;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - .72rem) 50%,
    calc(100% - .48rem) 50%;
  background-size: .25rem .25rem, .25rem .25rem;
  background-repeat: no-repeat;
}
.workspace-file:focus { outline: 2px solid var(--plate-acc); outline-offset: 1px; }
.workspace-file:disabled { opacity: .55; }
.workspace-source-actions {
  align-items: center;
  gap: .25rem;
  margin-left: .1rem;
}
.workspace-source-actions button {
  cursor: pointer;
  font: inherit;
  font-size: .61rem;
  color: var(--plate-fg);
  padding: .26rem .48rem;
  border-radius: var(--r-xs);
  background: var(--plate-2);
  box-shadow: inset 0 0 0 1px var(--plate-rule);
}
.workspace-source-actions button:last-child { color: var(--plate-acc); }
.workspace-source-actions button:disabled { cursor: default; opacity: .38; }
.is-workspace .ed__area[readonly] { opacity: .62; cursor: wait; }

/* ---------- the editor ---------- */
.ed {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
}
/* The gutter is painted under the textarea and scrolled with it
   by app.js. It is aria-hidden: the line numbers are an aid to
   the eye, and a screen reader reading "1 2 3 4" over a document
   it is already reading is noise. */
.ed__gutter {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--ed-gutter);
  overflow: hidden;
  padding: var(--ed-pad-y) .7rem var(--ed-pad-y) 0;
  font-family: var(--font-mono);
  font-size: var(--ed-size);
  line-height: var(--ed-line);
  font-variant-numeric: lining-nums tabular-nums;
  text-align: right;
  color: var(--plate-dim);
  background: var(--plate-2);
  border-right: 1px solid var(--plate-rule);
  white-space: pre;
  pointer-events: none;
}
.ed__area {
  flex: 1;
  min-width: 0;
  display: block;
  resize: none;
  border: 0;
  background: none;
  color: var(--plate-fg);
  caret-color: var(--plate-acc);
  font-family: var(--font-mono);
  font-size: var(--ed-size);
  line-height: var(--ed-line);
  font-variant-numeric: lining-nums;
  tab-size: 2;
  padding: var(--ed-pad-y) 1.1rem var(--ed-pad-y) calc(var(--ed-gutter) + .8rem);
  overflow: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--plate-dim) transparent;
}
.ed__area:focus { outline: 0; }
.ed__area::selection { background: var(--plate-acc); color: #fff; }
.ed:focus-within { box-shadow: inset 0 0 0 2px var(--plate-acc); }

/* The one moment the whole page exists for: a card is dragged in
   the frame, the patch engine writes the file, and the text on
   this side changes. Without a cue it happens off the eye's beat. */
.pane--edit.is-patched .ed { animation: patched 1.05s cubic-bezier(.2,.7,.3,1); }
@keyframes patched {
  0%   { box-shadow: inset 0 0 0 2px var(--plate-acc); background: rgba(239, 113, 72, .11); }
  100% { box-shadow: inset 0 0 0 2px transparent; background: transparent; }
}

/* ---------- the rendered stage ---------- */
.stage {
  flex: 1;
  min-height: 0;
  width: 100%;
  border: 0;
  display: block;
  background: var(--paper);
  color-scheme: light dark;
}

/* ------------------------------------------------------------
   6. Present — the rendered view, and the window

   The meeting test: open the page, build a board, share the
   screen. Everything here except the frame is scaffolding for
   *writing* the file — the masthead, the lede, the rail, the
   status line, the gutter, the pane titles — and an audience
   needs none of it, so presenting takes all of it off and gives
   the frame the viewport. What is left is one pair of buttons in
   a corner at a third of full opacity.

   Nothing moves in the DOM and the frame is never re-mounted, so
   a board keeps its scroll and its selection across the switch.
   The editor is *parked*, not hidden: it becomes a drawer that
   starts off the left edge with its layout intact, because a
   `display: none` textarea loses the scrollTop and the selection
   that §6 of app.js exists to protect — and a card dragged while
   presenting still writes into it.

   Every rule below outranks §5's narrow-viewport pane switch on
   specificity, which is the point: presenting shows the document
   whichever pane the switch last chose, and leaves the switch
   set as it was for the way back.
   ------------------------------------------------------------ */
.pres { display: none; }

.is-present { overflow: hidden; }
.is-present .topbar,
.is-present .bench__head,
.is-present .rail,
.is-present .statusbar,
.is-present .swap,
.is-present .hint,
.is-present .foot { display: none; }
.is-present .bench { padding: 0; gap: 0; }

.is-present .panes {
  position: fixed;
  inset: 0;
  z-index: 90;
  height: 100dvh;
  gap: 0;
  grid-template-columns: minmax(0, 1fr);
}
.is-present .panes .pane--view {
  display: flex;
  border-radius: 0;
  box-shadow: none;
}
.is-present .panes .pane--view .pane__bar { display: none; }

.is-present .panes .pane--edit {
  display: flex;
  position: fixed;
  z-index: 95;
  top: clamp(.6rem, 1.4vw, 1rem);
  bottom: clamp(.6rem, 1.4vw, 1rem);
  left: clamp(.6rem, 1.4vw, 1rem);
  width: min(30rem, 86vw);
  border-radius: var(--r);
  box-shadow: var(--shadow-l);
  transform: translateX(calc(-100% - 1.6rem));
  transition: transform .34s cubic-bezier(.2, .8, .3, 1);
}
.is-present.is-drawer .panes .pane--edit { transform: none; }
/* On a phone the drawer is nearly the width of the screen, so it
   stops short of the bottom rather than burying the way out. */
@media (max-width: 899px) {
  .is-present .panes .pane--edit { bottom: 3.6rem; }
}

/* The corner cluster. Quiet, never invisible: .32 read as "gone"
   in the field — an audience can melt away controls the presenter
   still has to be able to FIND. A pointer over it, or a focus
   ring inside it, brings it all the way up. */
.is-present .pres {
  display: flex;
  gap: .22rem;
  position: fixed;
  z-index: 100;
  right: clamp(.7rem, 1.6vw, 1.15rem);
  bottom: clamp(.7rem, 1.6vw, 1.15rem);
  padding: .26rem;
  border-radius: 100px;
  /* It floats over a document it knows nothing about — a white
     card, an inked plate — so it carries its own ground. */
  background: color-mix(in srgb, var(--card) 86%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: var(--shadow-m), var(--ring);
  opacity: .62;
  transition: opacity .24s;
}
.is-present .pres:hover,
.is-present .pres:focus-within { opacity: 1; }

/* The way out, said once on the way in. A toast that names the
   key and fades; pointer-events none so it can never block the
   document it sits over — the audience's screen is the document.

   The three rules below are arranged the way they are because of
   what went wrong here, which was never the toast's timing. The
   showing state used to be `.is-present .pres-note.is-shown` —
   a conjunction across TWO elements, competing against a plain
   `.pres-note { opacity: 0 }` on the element itself. That shape
   fails silently and in both directions: the toast is invisible
   if the body class and the element class are ever a frame out of
   step, and any later rule that sets `opacity` on `.pres-note`
   at one class of specificity quietly outranks nothing and beats
   everything, with a transition to make the result read as a
   timing bug rather than a cascade one.

   Measured with CDP (CSS.getMatchedStylesForNode +
   getComputedStyleForNode) on this build, entered by a trusted
   click and by Cmd+Enter, light and dark, reduced motion on and
   off: the transition runs 0 -> 1 in 300ms, holds, and runs back.
   So the arrangement here is the guard, not the repair.

     · showing is ONE class on ONE element, at (0,2,0), which no
       single-class rule on `.pres-note` can outrank;
     · presenting is checked on the HIDING side, where a rule that
       can only ever hide can never be why the toast failed to
       appear;
     · `visibility` moves with `opacity`, so the hidden state is
       hidden to hit-testing and to assistive tech as well as to
       the eye, and never merely transparent. */
.pres-note {
  position: fixed;
  z-index: 100;
  left: 50%;
  bottom: clamp(1rem, 2.4vw, 1.6rem);
  transform: translateX(-50%) translateY(0);
  padding: .5rem 1.05rem;
  border-radius: 100px;
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .02em;
  color: var(--ink-2);
  background: color-mix(in srgb, var(--card) 92%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: var(--shadow-m), var(--ring);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .3s, transform .3s, visibility 0s linear .3s;
}
.pres-note b { color: var(--ink); font-weight: 500; }
.pres-note.is-shown {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(-.2rem);
  transition: opacity .3s, transform .3s, visibility 0s;
}
/* The second lock, and the only one allowed to fail closed. */
body:not(.is-present) .pres-note { opacity: 0; visibility: hidden; }
.pres__b {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .02em;
  color: var(--ink-2);
  padding: .42rem 1rem;
  border-radius: 100px;
  transition: color .18s, background .18s;
}
.pres__b:hover { color: var(--ink); background: var(--paper-2); }
.pres__b[aria-pressed="true"] { color: var(--ink); background: var(--paper-3); font-weight: 500; }
.pres__b--out { color: var(--acc); }
.pres__b--out:hover { color: var(--acc); background: var(--tint); }
.pres__b--pdf { color: var(--ink); background: var(--paper-2); }
.pres__b[hidden] { display: none; }

/* ------------------------------------------------------------
   7. The spec sheet

   A panel, not a dialog: it never takes the focus and never
   covers the editor's left edge, because it has to be usable
   *while writing* — read the marker set, type the marker. So it
   is a card on the right, the same near-white ground and 14px
   radius as every other lifted surface here, and it is closed
   until asked for.

   It is `display: none` when closed rather than parked
   off-screen. The editor drawer is parked because parking is
   what preserves a textarea's selection and scroll (§6); a
   panel of static text has no such state to lose, and a fixed
   card sitting outside the viewport is a horizontal scrollbar
   waiting for a stylesheet change. Opening animates instead.
   ------------------------------------------------------------ */
.sheet {
  display: none;
  position: fixed;
  /* Over the sticky masthead as well as the panes: the masthead
     is translucent and blurred, and a reference sheet read
     through it is a reference sheet nobody can read. Under the
     drop curtain (200), which outranks everything. */
  z-index: 101;
  top: clamp(.6rem, 1.4vw, 1rem);
  right: clamp(.6rem, 1.4vw, 1rem);
  bottom: clamp(.6rem, 1.4vw, 1rem);
  width: min(31rem, calc(100vw - 1.2rem));
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--r);
  background: var(--card);
  box-shadow: var(--shadow-l), var(--ring);
}
.is-sheet .sheet {
  display: flex;
  animation: sheet-in .26s cubic-bezier(.2, .8, .3, 1);
}
@keyframes sheet-in {
  from { opacity: 0; transform: translateX(1.2rem); }
  to   { opacity: 1; transform: none; }
}
/* Presenting keeps the sheet — a question about the format is
   exactly what gets asked while a board is on screen — but it
   stops above the corner cluster, so the way out is never under
   it. Escape closes the sheet first, then the drawer, then the
   mode. */
.is-present .sheet { bottom: 4.2rem; }

.sheet__bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .62rem .95rem;
  border-bottom: 1px solid var(--rule-soft);
}
.sheet__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--acc); flex: none; }
.sheet__id {
  font-family: var(--font-mono);
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: -.005em;
  color: var(--ink);
}
.sheet__x {
  margin-left: auto;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: .6rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: .26rem .68rem .22rem;
  border-radius: 100px;
  transition: color .18s, background .18s;
}
.sheet__x:hover { color: var(--acc); background: var(--tint); }

.sheet__body {
  flex: 1;
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  padding: .9rem clamp(.9rem, 2.2vw, 1.15rem) 1.5rem;
  scrollbar-width: thin;
  scrollbar-color: var(--ink-3) transparent;
}
.sheet__body:focus-visible { outline-offset: -3px; }

/* the spec's own first sentence */
.sheet__lede {
  font-size: .86rem;
  line-height: 1.5;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* One group per section of the spec, titled with that section's
   own heading. Open by default — a sheet of shut drawers is a
   worse reference than a long one — and collapsible for the way
   back up. The chevron is drawn from two borders; the subset
   fonts have no glyph for it. */
.sheet__g { margin-top: .55rem; border-top: 1px solid var(--rule-soft); }
.sheet__g > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .6rem 0 .35rem;
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
  transition: color .18s;
}
.sheet__g > summary:hover { color: var(--ink); }
.sheet__g > summary::-webkit-details-marker { display: none; }
.sheet__g > summary::after {
  content: "";
  margin-left: auto;
  flex: none;
  width: .38rem;
  height: .38rem;
  border-right: 1.4px solid currentColor;
  border-bottom: 1.4px solid currentColor;
  transform: translateY(-.1rem) rotate(45deg);
  transition: transform .2s;
}
.sheet__g[open] > summary::after { transform: translateY(.06rem) rotate(225deg); }
.sheet__gb { padding-bottom: .5rem; }

/* the shared base, one drawer holding the rest */
.sheet__g--shared { margin-top: 1rem; }
.sheet__g--shared > summary { color: var(--acc); }
.sheet__g--shared .sheet__g:first-of-type { border-top: 0; margin-top: 0; }

.sheet__lead,
.sheet__note {
  font-size: .8rem;
  line-height: 1.48;
  color: var(--ink-2);
  margin: .45rem 0 .1rem;
  text-wrap: pretty;
}
.sheet__note { color: var(--ink-3); }

.sheet__l { display: grid; gap: .34rem; margin: .45rem 0 .2rem; }
.sheet__l li {
  position: relative;
  padding-left: .85rem;
  font-size: .8rem;
  line-height: 1.48;
  color: var(--ink-2);
  text-wrap: pretty;
}
.sheet__l li::before {
  content: "";
  position: absolute;
  left: .12rem;
  top: .62em;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--acc-line);
}

.sheet__t {
  width: 100%;
  border-collapse: collapse;
  margin: .45rem 0 .25rem;
  font-size: .78rem;
}
.sheet__t th {
  text-align: left;
  font-family: var(--font-mono);
  font-size: .56rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--ink-3);
  padding: .28rem .55rem .28rem 0;
  border-bottom: 1px solid var(--rule);
}
.sheet__t td {
  vertical-align: top;
  padding: .36rem .55rem .36rem 0;
  border-bottom: 1px solid var(--rule-soft);
  color: var(--ink-2);
  line-height: 1.42;
}
.sheet__t td:first-child { color: var(--ink); }
.sheet__t th:last-child, .sheet__t td:last-child { padding-right: 0; }

/* Source is source: the same inked plate the rest of the site
   draws a file on. */
.sheet__pre {
  background: var(--plate);
  color: var(--plate-fg);
  border-radius: var(--r-sm);
  padding: .7rem .85rem .75rem;
  margin: .5rem 0 .3rem;
  font-size: .7rem;
  line-height: 1.66;
  white-space: pre;
  overflow-x: auto;
  tab-size: 2;
  font-variant-numeric: lining-nums;
  scrollbar-width: thin;
  scrollbar-color: var(--plate-dim) transparent;
}
/* `code` is a nowrap chip everywhere else on this site; inside a
   plate it is the file, and the plate's own wrapping rule wins. */
.sheet__pre code { background: none; padding: 0; font-size: 1em; white-space: inherit; }

/* one verb: what it is called, what it takes, what it edits */
.sheet__v { padding: .5rem 0 .55rem; border-bottom: 1px solid var(--rule-soft); }
.sheet__v:last-child { border-bottom: 0; }
.sheet__vn {
  font-family: var(--font-mono);
  font-size: .74rem;
  font-weight: 600;
  color: var(--ink);
}
.sheet__vs {
  margin: .3rem 0 .3rem;
  padding: .34rem .5rem;
  border-radius: var(--r-xs);
  background: var(--paper-2);
  font-family: var(--font-mono);
  font-size: .66rem;
  line-height: 1.55;
  color: var(--ink-2);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.sheet__vd { font-size: .78rem; line-height: 1.45; color: var(--ink-2); }

/* one spec, offered to a file that names none */
.sheet__pick { margin-top: .7rem; padding-top: .2rem; }
.sheet__pick .sheet__pre { margin-top: .35rem; }

.sheet__doc {
  margin-top: 1.1rem;
  padding-top: .75rem;
  border-top: 1px solid var(--rule-soft);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .3rem .7rem;
  font-family: var(--font-mono);
  font-size: .66rem;
  color: var(--ink-3);
}
.sheet__pick .sheet__doc { margin-top: .4rem; padding-top: 0; border-top: 0; }
.sheet__doc a { color: var(--acc); text-decoration-color: var(--acc-line); }
.sheet__doc code { font-size: 1em; }

@media (max-width: 560px) {
  .sheet__pre { font-size: .66rem; }
  .sheet__body { padding-inline: .8rem; }
}

/* ------------------------------------------------------------
   7b. Open from Hub — the file list

   The spec sheet's idiom, reused rather than re-invented: the same
   card, the same bar, the same body, the same way in. It is its
   own class rather than a second `.sheet` because showing is a
   body class (`.is-sheet .sheet`), and a list that appeared every
   time somebody opened the spec sheet would be a bug written in
   CSS.

   It sits one level ABOVE the sheet and in the same corner, which
   is the honest arrangement for what it is: a chooser you opened
   over whatever you were reading, gone again in one press, with
   the sheet still there underneath. Escape closes this first — the
   ladder is stated in app.js §10 and in index.html, and this rule
   is why it has to be in that order.

   Narrower than the sheet: a file name and a path need less width
   than a spec's tables, and the editor stays visible beside it.
   ------------------------------------------------------------ */
.browse {
  display: none;
  position: fixed;
  z-index: 102;
  top: clamp(.6rem, 1.4vw, 1rem);
  right: clamp(.6rem, 1.4vw, 1rem);
  bottom: clamp(.6rem, 1.4vw, 1rem);
  width: min(27rem, calc(100vw - 1.2rem));
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--r);
  background: var(--card);
  box-shadow: var(--shadow-l), var(--ring);
}
.is-browse .browse {
  display: flex;
  animation: sheet-in .26s cubic-bezier(.2, .8, .3, 1);
}
.is-present .browse { bottom: 4.2rem; }
.browse__body:focus-visible { outline-offset: -3px; }

.browse__lede,
.browse__note {
  font-size: .8rem;
  line-height: 1.5;
  color: var(--ink-3);
  text-wrap: pretty;
}
.browse__lede { margin-bottom: .3rem; }
.browse__note { margin: .5rem 0; }
.browse__note--err { color: var(--sev-err); }
.browse__note code { font-size: .92em; }
.browse__acts { display: flex; flex-wrap: wrap; gap: .3rem 1rem; margin: .5rem 0 .2rem; }

/* One instance, as a heading in the pane bars' idiom — this is the
   same kind of label as "rendered · live", and it is the only
   place an owner and an instance are named. */
.browse__grp {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  margin-top: 1rem;
  padding-bottom: .35rem;
  border-bottom: 1px solid var(--rule-soft);
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.browse__grp:first-child { margin-top: .2rem; }
.browse__ro { margin-left: auto; color: var(--sev-warn); letter-spacing: .08em; }

.browse__l { display: grid; gap: .1rem; margin-top: .25rem; }

/* One file. A whole row is the control, because the target for
   "open this one" is the line you are reading, not a word in it. */
.browse__f {
  cursor: pointer;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: .1rem .6rem;
  width: 100%;
  text-align: left;
  padding: .5rem .55rem;
  border-radius: var(--r-sm);
  transition: background .16s;
}
.browse__f:hover { background: var(--paper-2); }
.browse__f:focus-visible { outline: 2px solid var(--acc); outline-offset: -2px; }
.browse__fn {
  font-family: var(--font-mono);
  font-size: .76rem;
  font-weight: 500;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.browse__fs {
  justify-self: end;
  font-family: var(--font-mono);
  font-size: .58rem;
  letter-spacing: .06em;
  color: var(--ink-3);
  background: var(--paper-3);
  border-radius: 100px;
  padding: .18rem .5rem .14rem;
  white-space: nowrap;
}
.browse__fp,
.browse__ft {
  grid-column: 1 / -1;
  font-size: .7rem;
  line-height: 1.4;
  color: var(--ink-3);
  overflow-wrap: anywhere;
}
.browse__fp { font-family: var(--font-mono); font-size: .64rem; }
.browse__ft { color: var(--ink-2); }
/* The file this editor is already holding. Marked, because the
   list is also the answer to "where did this come from". */
.browse__f.is-here { background: var(--tint); }
.browse__f.is-here .browse__fn { color: var(--acc); }

/* The question before a replacement. It is drawn as a plate rather
   than a line of text because it is the one thing in this panel
   that must not be clicked past on the way to something else. */
.browse__ask {
  margin-bottom: .6rem;
  padding: .75rem .85rem .6rem;
  border-radius: var(--r-sm);
  background: var(--tint-warn);
}
.browse__askq {
  font-size: .8rem;
  line-height: 1.5;
  color: var(--ink-2);
  text-wrap: pretty;
}
.browse__askq b { color: var(--ink); font-weight: 500; overflow-wrap: anywhere; }

/* ------------------------------------------------------------
   8. Hint + drop curtain
   ------------------------------------------------------------ */
.hint {
  font-size: .88rem;
  line-height: 1.55;
  color: var(--ink-3);
  max-width: 58rem;
}
.hint b { color: var(--ink-2); }
.hint--warn {
  background: var(--tint-warn);
  border-radius: var(--r);
  padding: 1rem 1.2rem;
  color: var(--ink-2);
}

.drop {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  place-items: center;
  background: color-mix(in srgb, var(--paper) 82%, transparent);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.dropping .drop { display: grid; }
.drop span {
  font-family: var(--font-mono);
  font-size: .84rem;
  letter-spacing: .04em;
  color: var(--ink);
  background: var(--card);
  border-radius: var(--r);
  padding: 1.5rem 2.2rem;
  box-shadow: var(--shadow-l), inset 0 0 0 2px var(--acc-line);
}
.drop code { background: none; color: var(--acc); }

/* ------------------------------------------------------------
   9. Footer, trimmed for a tool page
   ------------------------------------------------------------ */
.app .foot__rule { border-top: 1px solid var(--rule-soft); }
.app .foot__rule a { color: inherit; text-decoration: none; }
.app .foot__rule a:hover { color: var(--acc); }

/* ------------------------------------------------------------
   10. Dark — derived from the light design above
   ------------------------------------------------------------ */
@media (prefers-color-scheme: dark) {
  :root {
    --sev-ok:    #8fbf9c;
    --sev-warn:  #d9b063;
    --tint-ok:   #16211a;
    --tint-warn: #241d10;
  }
  /* On near-black the inked pane needs its hairline back: a
     shadow separates nothing there. */
  .pane--edit { box-shadow: var(--shadow-m), inset 0 0 0 1px var(--plate-rule); }
  .is-present .panes .pane--edit { box-shadow: var(--shadow-l), inset 0 0 0 1px var(--plate-rule); }
  /* On near-black a third of an opacity is nearly nothing; the
     cluster has to stay findable without being lit. */
  .is-present .pres { opacity: .68; }
  .drop { background: color-mix(in srgb, var(--paper) 78%, transparent); }
}

/* ------------------------------------------------------------
   11. Reduced motion
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  /* The patch cue still has to land — it is information, not
     decoration — so it becomes a static hold rather than a fade. */
  .pane--edit.is-patched .ed { animation: none; box-shadow: inset 0 0 0 2px var(--plate-acc); }
}

.narration__controls[hidden] { display: none; }
