/* ═══════════════════════════════════════════════════════════════════════════
   PDF Player — presenter chrome in the WSE "Bauhaus Block" design language.
   Palette roles: red = problem, yellow = result, blue = method.
   --deck-laser-color is the laser's colour; presenter.js rewrites it whenever
   the presenter picks a colour, and the value here is only the default.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --ink:        #111111;
  --paper:      #FFFFFF;
  --gray:       #6B7280;
  --line:       #E5E7EB;
  --red:        #EB4134;
  --yellow:     #FDCC10;
  --blue:       #4186FF;
  --backdrop:   #0B0B0C;
  --deck-laser-color: #FF2D2D;

  --chrome-fade: .18;          /* opacity of resting chrome */
  /* the footer's size, + and − in the footer (2026-10-26; player.js sets it),
     and how much higher than at 1 its top then is: what sits just above
     the footer (the toast, a warning, the interactions button) moves by it */
  --foot-scale: 1;
  --foot-lift: calc(46px * (var(--foot-scale) - 1));
  --font: "Source Sans 3", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "Source Code Pro", ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* The UI faces, Source Sans 3 and Source Code Pro — vendored (variable weight
   200–900; Latin, and Latin Extended for the text face) instead of loaded
   from Google Fonts: the UI looks the same offline, and no visit tells a
   font service the visitor's address (UX review: UX-31). Licences in
   assets/fonts/OFL-Source-Sans-3.txt and OFL-Source-Code-Pro.txt. */
@font-face {
  font-family: "Source Sans 3"; font-style: normal; font-weight: 200 900; font-display: swap;
  src: url("fonts/source-sans-3-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Source Sans 3"; font-style: normal; font-weight: 200 900; font-display: swap;
  src: url("fonts/source-sans-3-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Source Code Pro"; font-style: normal; font-weight: 200 900; font-display: swap;
  src: url("fonts/source-code-pro-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* The title face — the same Fraunces as on the WSE Transcribe start page,
   vendored (latin subset, variable weight 300–600) so the title looks the
   same offline; licence in assets/fonts/OFL-Fraunces.txt. */
@font-face {
  font-family: "Fraunces"; font-style: normal; font-weight: 300 600; font-display: swap;
  src: url("fonts/fraunces-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Fraunces"; font-style: italic; font-weight: 300 600; font-display: swap;
  src: url("fonts/fraunces-italic-latin.woff2") format("woff2");
}

* { box-sizing: border-box; }

/* The overlays below are laid out with `display:flex` on an ID selector, which
   outranks the user-agent's `[hidden]{display:none}`. Without this they are all
   open on load. Overlay visibility is driven by the `hidden` property in JS. */
[hidden] { display: none !important; }

html, body {
  margin: 0; height: 100%; overflow: hidden;
  background: var(--backdrop); color: var(--paper);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
}

.fatal { color: var(--paper); font: 600 16px var(--font); padding: 2rem; }

/* ── stage ───────────────────────────────────────────────────────────────── */
#stage-wrap { position: fixed; inset: 0; overflow: hidden; }
#stage      { position: absolute; left: 0; top: 0; width: 0; height: 0; }

#page-canvas {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  background: var(--paper);
  box-shadow: 0 0 0 1px rgba(255,255,255,.06), 0 24px 60px rgba(0,0,0,.55);
}
#ink-canvas  { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
#text-layer  { position: absolute; inset: 0; pointer-events: none; }
/* Links in the PDF (#12): clickable with the cursor and the laser only, so a
   pen stroke that starts on a link is still a stroke. */
#link-layer  { position: absolute; inset: 0; pointer-events: none; }
#link-layer .pdf-link { position: absolute; display: block; border-radius: 3px; }
body.tool-cursor #link-layer .pdf-link,
body.tool-laser:not(.drawing) #link-layer .pdf-link { pointer-events: auto; }
body.tool-cursor #link-layer .pdf-link { cursor: pointer; }
/* the laser dot IS the pointer, and near the top edge nothing may show */
body.tool-laser #link-layer .pdf-link { cursor: none; }
/* near the top edge nothing shows, so nothing may be clicked unseen either */
body.pointer-parked #link-layer .pdf-link { pointer-events: none; }
body.tool-cursor #link-layer .pdf-link:hover {
  outline: 2px solid color-mix(in srgb, var(--deck-laser-color, #1f6feb) 55%, transparent);
  outline-offset: 1px; background: rgba(31,111,235,.06);
}

#laser-canvas { position: fixed; inset: 0; z-index: 60; pointer-events: none; }

/* cursors per tool */
body.tool-laser                   { cursor: none; }
/* Close to the top of the screen nothing is shown at all: no laser point (the
   presenter layer stops drawing) and no mouse cursor either. */
body.pointer-parked               { cursor: none !important; }
body.tool-pen, body.tool-marker   { cursor: crosshair; }
body.tool-text                    { cursor: text; }
body.tool-eraser                  { cursor: cell; }
body.drawing                      { user-select: none; -webkit-user-select: none; }
body.no-doc #stage-wrap,
body.no-doc #deck-footer,
body.no-doc #toolbar,
body.no-doc #progress,
body.no-doc #talk-line,
body.no-doc #talk-warn            { display: none; }

/* ── chrome: each bar appears only while the pointer is close to THAT bar ──
   Measured in JS from the element's border box, because CSS cannot express
   "how far away is the cursor". `.near` is the only thing that shows a bar;
   :focus-within keeps it up while a control in it is being used by keyboard
   (a pointer press leaves no focus in a bar: player.js, pointerup). */
.chrome {
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s ease;
}
.chrome.near,
.chrome:focus-within { opacity: 1; pointer-events: auto; }
/* K hides all of it. `!important` because the bars' own ID rules
   (#toolbar, #deck-footer: display flex) outrank this one — so since 0.1.0
   K had hidden nothing but the progress line (found with #81). The
   interactions button is part of the chrome too (review of #81). */
body.chrome-off .chrome,
body.chrome-off #progress,
body.chrome-off #talk-line,
body.chrome-off #talk-warn,
body.chrome-off #ia-fab { display: none !important; }

/* ── toolbar ──────────────────────────────────────────────────────────────
   A floating frosted panel rather than the hard Bauhaus block: this thing sits
   ON TOP of someone's slide, so it wants soft edges and depth that read as a
   layer above the page instead of a sticker glued to it. The palette is
   untouched — only the surface treatment is modern. */
#toolbar {
  position: fixed; right: 16px; top: 50%; transform: translateY(-50%); z-index: 45;
  display: flex; flex-direction: column; gap: 4px; align-items: center;
  padding: 9px 8px;
  color: var(--ink);
  background: rgba(255,255,255,.90);
  -webkit-backdrop-filter: blur(14px) saturate(1.5);
  backdrop-filter: blur(14px) saturate(1.5);
  border: 1px solid rgba(17,17,17,.09);
  border-radius: 16px;
  box-shadow:
    0 1px 2px rgba(0,0,0,.10),
    0 10px 30px rgba(0,0,0,.30),
    inset 0 1px 0 rgba(255,255,255,.7);
}
/* A short window — a laptop with the browser's bars, a phone on its side
   (UX review: UX-08): the column never runs off the screen; it gets tighter,
   and scrolls if it still does not fit. */
#toolbar { max-height: calc(100vh - 24px); overflow-y: auto; scrollbar-width: none; }
#toolbar .tool {
  width: 38px; height: 38px; padding: 8px; display: flex; align-items: center;
  justify-content: center; border: none; background: transparent;
  color: var(--ink); cursor: pointer; border-radius: 11px;
  transition: background-color .13s ease, color .13s ease, transform .13s ease;
}
#toolbar .tool svg { width: 100%; height: 100%; display: block; }
#toolbar .tool:hover  { background: rgba(17,17,17,.07); }
#toolbar .tool:active { transform: scale(.94); }
#toolbar .tool.active {
  background: var(--ink); color: var(--paper);
  box-shadow: 0 2px 6px rgba(0,0,0,.28);
}
#toolbar .tool:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
#toolbar .tool[disabled] { opacity: .25; cursor: default; }
#toolbar .tool[disabled]:hover { background: transparent; }
#toolbar .tool[disabled]:active { transform: none; }
#t-laser .dot  { fill: var(--deck-laser-color); }
#t-laser .ring { fill: none; stroke: var(--deck-laser-color); stroke-width: 1.6; opacity: .55; }
#t-laser.active .dot  { fill: var(--paper); }
#t-laser.active .ring { stroke: var(--paper); }

.tool-sep {
  width: 24px; height: 1px; background: rgba(17,17,17,.20);
  margin: 5px 0; border-radius: 1px;
}

/* One square per colour, stacked — a single column is a straight vertical
   flick to any of them, which is what makes it quick to pick during a talk. */
#swatches { display: flex; flex-direction: column; gap: 6px; padding: 2px 0; }
#swatches .sw {
  width: 24px; height: 24px; padding: 0; cursor: pointer;
  background: var(--sw); border: 1px solid rgba(17,17,17,.16);
  border-radius: 7px;
  box-shadow: inset 0 1px 1px rgba(255,255,255,.35);
  transition: transform .13s ease, box-shadow .13s ease;
}
#swatches .sw:hover { transform: scale(1.10); }
#swatches .sw:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
#swatches .sw.active {
  border-color: transparent;
  box-shadow: 0 0 0 2px var(--paper), 0 0 0 4px var(--ink);
}
@media (max-height: 700px) {
  #toolbar { gap: 2px; padding: 6px 6px; }
  #toolbar .tool { width: 32px; height: 32px; padding: 6px; }
  .tool-sep { margin: 2px 0; }
  #swatches { gap: 4px; }
  #swatches .sw { width: 20px; height: 20px; }
}

/* ── footer ──────────────────────────────────────────────────────────────── */
#deck-footer {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  display: flex; align-items: center; gap: calc(12px * var(--foot-scale));
  padding: calc(6px * var(--foot-scale)) calc(14px * var(--foot-scale)) calc(8px * var(--foot-scale));
  height: calc(46px * var(--foot-scale));
  color: var(--paper);
  /* A surface of its own (UX review: UX-02): a 16:9 slide on a 16:9
     projector, or a zoomed one, reaches the bottom edge, and a gradient that
     faded out behind the controls left white icons on a white slide (1.3:1).
     Dark enough for 4.5:1 on any slide, with a soft edge above. */
  background: rgba(0,0,0,.72);
  font: 600 13px var(--font);
}
#deck-footer::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: 18px;
  background: linear-gradient(to top, rgba(0,0,0,.72), rgba(0,0,0,0)); pointer-events: none;
}
/* larger or smaller (2026-10-26): every part of the bar is zoomed, but the
   close button in the corner, which keeps its size and its place */
#deck-footer > :not(#btn-close) { zoom: var(--foot-scale); }
#deck-footer .foot-size { display: flex; gap: 2px; }
#deck-footer #btn-home svg { width: 22px; height: 22px; }
#deck-footer .who {
  max-width: 32vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  opacity: .85; letter-spacing: .01em;
}
#deck-footer .spacer { flex: 1; display: flex; align-items: center; justify-content: center; }
#deck-footer .foot-right { display: flex; align-items: center; gap: 8px; }

#deck-footer button {
  border: none; background: transparent; color: var(--paper); cursor: pointer;
  padding: 4px; display: flex; align-items: center; justify-content: center;
}
#deck-footer button svg { width: 20px; height: 20px; display: block; }
#deck-footer button:hover { background: rgba(255,255,255,.16); }
#deck-footer button[disabled] { opacity: .3; cursor: default; }
#deck-footer button[disabled]:hover { background: transparent; }

/* The close button (#81) sits in the upper-right corner but is a CHILD of the
   footer bar, so it has no visibility of its own: the bar's opacity and
   pointer-events (.near, keyboard focus), its display (the start page, K) and
   its fade are the button's too — the two are shown exactly together. The
   footer has no transform, filter, backdrop-filter, perspective, contain or
   will-change — any of them would make it the containing block of `fixed`,
   and the button would sit at the bar's top instead of the screen's. A dark
   disc, like the footer's own gradient, keeps it legible on any slide. */
#deck-footer #btn-close {
  position: fixed; top: 16px; right: 16px;
  width: 40px; height: 40px; padding: 9px; border-radius: 50%;
  background: rgba(0,0,0,.62); color: #fff;
  box-shadow: 0 2px 10px rgba(0,0,0,.35);
}
#deck-footer #btn-close svg { width: 22px; height: 22px; }
#deck-footer #btn-close:hover { background: var(--red); }
#deck-footer #btn-close:focus-visible { outline: 3px solid var(--yellow); outline-offset: 2px; }
/* The toolbar is 663 px tall and centred: below about 800 px of height its
   top reaches the corner, so the button steps left of the tool column
   (which spans 16…72 px from the right edge) instead of covering its first
   tool (review of #81). */
@media (max-height: 800px) {
  #deck-footer #btn-close { right: 84px; }
}

/* A phone (UX review: UX-04): everything fits in two rows — home and the page
   turns above, the buttons, the clock and the counter below; the title goes. */
@media (max-width: 640px) {
  #deck-footer { flex-wrap: wrap; height: auto; row-gap: 2px; column-gap: 8px; padding: 4px 10px 6px; }
  #deck-footer .who { display: none; }
  #deck-footer .spacer { min-width: 0; }
  #deck-footer .foot-right { order: 3; flex: 1 0 100%; justify-content: space-between; gap: 2px; }
  #deck-footer .foot-right button { padding: 3px; }
}

.deck-nav { display: flex; gap: 8px; }
.deck-nav button { width: 44px; height: 44px; padding: 5px; }
.deck-nav button svg { width: 32px; height: 32px; }

#timer   { font: 600 13px var(--mono); opacity: .8; cursor: pointer; user-select: none; }
/* the page numbers are a button (2026-10-26): they open the slide finder */
#deck-footer #counter { font: 600 14px var(--mono); display: inline-flex; gap: 3px; align-items: baseline; padding: 4px 6px; }
#counter i { font-style: normal; opacity: .45; }
#counter span { opacity: .6; }
#deck-footer #counter[aria-expanded="true"] { background: rgba(255,255,255,.16); }

/* The slide finder (2026-10-26): above the page numbers, the slides shown
   last, or those whose title holds the words typed. Not a part of the bar:
   it stays while the pointer is elsewhere. Dark like the toast. */
#slide-finder {
  position: fixed; right: 14px; bottom: calc(54px + var(--foot-lift)); z-index: 47;
  width: min(400px, calc(100vw - 28px)); max-height: min(72vh, 600px); box-sizing: border-box;
  display: flex; flex-direction: column; gap: 8px; padding: 12px;
  background: var(--ink); color: var(--paper); border-left: 5px solid var(--yellow);
  box-shadow: 5px 5px 0 rgba(0,0,0,.4); font: 600 14px var(--font);
}
#slide-finder[hidden] { display: none; }
#finder-input {
  font: 400 15px var(--font); padding: 8px 10px; border: 2px solid transparent; border-radius: 0;
  background: var(--paper); color: var(--ink); min-width: 0;
}
#finder-input:focus-visible { outline: none; border-color: var(--yellow); }
.finder-head { margin: 2px 0 0; font: 700 12px var(--font); letter-spacing: .04em; color: #C9CBD1; }
.finder-list { display: flex; flex-direction: column; gap: 4px; overflow-y: auto; min-height: 0; }
.finder-row {
  display: grid; grid-template-columns: 88px auto minmax(0, 1fr); gap: 10px; align-items: center;
  padding: 4px; border: 2px solid transparent; background: transparent; color: inherit;
  font: inherit; text-align: left; cursor: pointer;
}
.finder-row:hover, .finder-row:focus-visible { border-color: var(--yellow); outline: none; }
.finder-row canvas { display: block; width: 88px; height: auto; background: var(--paper); }
.finder-row .fn { font: 700 13px var(--mono); color: #C9CBD1; min-width: 2ch; text-align: right; }
.finder-row .ft { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.finder-row .ft.none { font-weight: 400; font-style: italic; color: #9CA0A8; }
.finder-note { margin: 0; font: 400 13px var(--font); color: #C9CBD1; }
.finder-note[hidden] { display: none; }

#progress {
  position: fixed; left: 0; right: 0; bottom: 0; height: 3px; z-index: 46;
  background: rgba(255,255,255,.12); pointer-events: none;
}
/* yellow, or the colour picked in the live indicator's dialog (2026-10-21; talk.js sets --slide-line) */
#progress-bar { display: block; height: 100%; width: 0; background: var(--slide-line, var(--yellow)); transition: width .18s ease; }
/* The talk timer (#103): the time spent, full at the planned length — the
   same thin line, directly above the slide line (2026-10-21; below it since
   #108), so the two compare at a glance; the slide line stays on the bottom
   edge. Its colour is the pace (talk-time.js): green on schedule, through
   orange to red. It moves with the clock, once a second. */
#talk-line {
  position: fixed; left: 0; right: 0; bottom: 3px; height: 3px; z-index: 46;
  background: rgba(255,255,255,.12); pointer-events: none;
}
#talk-line[hidden] { display: none; }
#talk-bar { display: block; height: 100%; width: 0; background: rgb(22, 163, 74); transition: width 1s linear, background-color .6s ease; }
@media (prefers-reduced-motion: reduce) { #talk-bar { transition: none; } }
/* #110: a warning — the line blinks three times, and a notice stands near the
   footer's clock (in the lower-right corner, above the footer) until the next
   slide; 80 % opaque, so the slide shows through */
#talk-line.talk-blink { animation: talk-blink 1s ease-in-out 3; }
@keyframes talk-blink { 50% { opacity: .15; } }
#talk-warn {
  position: fixed; right: 14px; bottom: calc(56px + var(--foot-lift)); z-index: 92; max-width: min(420px, calc(100vw - 28px));
  animation: talk-warn-in .25s ease-out;
}
/* …framed in the warning's colour (2026-10-21; talk.js sets --warn-colour),
   the same over the slide as in the dialog's preview — so dark on light and
   dark cards alike */
.talk-notice {
  box-sizing: border-box; background: #111111; color: #FFFFFF;
  border: 3px solid var(--warn-colour, rgb(234, 138, 12)); border-left-width: 6px;
  padding: 7px 12px; font: 600 15px/1.35 var(--font); box-shadow: 5px 5px 0 rgba(0,0,0,.4);
  opacity: .8;
}
/* 2026-10-21: a dot for each warning the clock has passed, in its colour and
   at its share — for the presenter who missed the notice — on the slide
   line, so it can be held against the end of the slide line's bar. The slide
   line is the bottom edge, so the dot stands on it, whole, with the line
   running through its foot, and covers the time line above, which has no
   dot of its own (the time line comes first in the page, the slide line on top) */
:is(#progress, #talk-preview-slides) .talk-mark {
  position: absolute; bottom: 0; left: clamp(0px, calc(var(--at) - 5px), calc(100% - 10px));
  width: 10px; height: 10px; border-radius: 50%; background: var(--mark);
  box-shadow: 0 0 0 1.5px rgba(0,0,0,.6);
}
#talk-warn[hidden] { display: none; }
/* …left of the interactions button when a slide has one (UX review: UX-09) */
body:has(#ia-fab:not([hidden])) #talk-warn { right: 80px; }
@keyframes talk-warn-in { from { opacity: 0; transform: translateY(8px); } }
@media (prefers-reduced-motion: reduce) { #talk-line.talk-blink, #talk-warn { animation: none; } }

/* ── text notes ──────────────────────────────────────────────────────────── */
/* The editor wrapper carries the position, the font size and the 46% cap, so
   the editable inside it can stay a plain block and the ✕ can sit outside the
   text without being part of it. Notes themselves are painted on the canvas —
   this styling only ever shows while one is being typed. */
/* The wrapper paints the light-grey gradient frame: a 1px band of gradient
   showing around the white note inside it is the HTML counterpart of the
   stroked rectangle the canvas draws, so editing a note looks like the note. */
.note-editor {
  position: absolute; pointer-events: auto; max-width: 46%;
  padding: .035em;
  background: linear-gradient(135deg, #E2E5E9 0%, #CBD0D7 45%, #AEB4BD 100%);
  box-shadow: .12em .12em 0 rgba(0,0,0,.28);
}
.note {
  cursor: text; max-width: 100%;
  background: rgba(255,255,255,.94);
  color: var(--ink);
  border-left: .32em solid var(--note-color, var(--red));
  padding: .18em .42em .22em .38em;
  font-family: var(--font); font-weight: 600; line-height: 1.22;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.note:focus { outline: 2px solid var(--blue); outline-offset: 2px; }
.note-editor .kill {
  position: absolute; top: -.55em; right: -.55em; width: 1.3em; height: 1.3em;
  border: 2px solid var(--ink); background: var(--paper); color: var(--ink);
  font: 700 .7em/1 var(--font); cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
}
.note-editor .kill:hover { background: var(--red); color: var(--paper); }
#text-layer.armed { pointer-events: auto; }

/* ── opening screen ──────────────────────────────────────────────────────── */
#opener {
  position: fixed; inset: 0; z-index: 80; display: none;
  flex-direction: column;
  padding: 24px 24px 0;
  background: #08080A;
  overflow: hidden auto;
  /* a control reached with Tab is scrolled clear of the pinned row below
     (UX review: UX-01, WCAG 2.4.11); player.js keeps it at the row's height */
  scroll-padding-bottom: var(--opener-bottom-h, 0px);
}

/* A living mesh gradient: six colour points that overlap on a near-black
   ground and are blended with `screen`, so where two meet the field brightens
   the way light does rather than the way two stacked shapes do. That overlap
   is what separates a mesh from a handful of blobs.

   Each point moves on its own prime-numbered period (37/43/53/59/67/73s), so
   the composite never visibly repeats — there is no moment where the viewer
   recognises a loop. Motion is transform-only on a blurred parent, which
   makes the whole field one compositor job: a start page must cost nothing
   while a talk is being set up.

   Three changes are layered, all of them small, so the field is never still
   and never seen to move: the whole mesh TURNS once in under five minutes
   (colour trades places across the screen over a talk's setup, invisibly as
   motion), each point DRIFTS a few vw on its own path, and each point
   BREATHES in and out of brightness — a change of colour, not of place. No
   two of the thirteen periods share a factor, so they never line up and the
   field never reads as a loop.
   Under prefers-reduced-motion only the breathing stays: constant change
   with nothing in motion. */
.mesh {
  position: fixed; inset: -30%;
  z-index: 0; pointer-events: none;
  filter: blur(85px) saturate(1.5);
  will-change: transform;
  animation: mesh-turn 281s linear infinite;
}
.mesh span {
  position: absolute; display: block; border-radius: 50%;
  mix-blend-mode: screen;
  will-change: transform, opacity;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}
.mesh .m1 {
  width: 46vmax; height: 46vmax; left: 2%;  top: 4%;
  background: radial-gradient(circle at 50% 50%, rgba(235,65,52,.55), rgba(235,65,52,0) 66%);
  animation-name: mesh-a, mesh-breathe; animation-duration: 29s, 13s; animation-delay: 0s, -7s;
}
.mesh .m2 {
  width: 54vmax; height: 54vmax; right: 0%; bottom: 2%;
  background: radial-gradient(circle at 50% 50%, rgba(65,134,255,.52), rgba(65,134,255,0) 66%);
  animation-name: mesh-b, mesh-breathe; animation-duration: 37s, 17s; animation-delay: 0s, -19s;
}
.mesh .m3 {
  width: 40vmax; height: 40vmax; left: 34%; top: 30%;
  background: radial-gradient(circle at 50% 50%, rgba(253,204,16,.34), rgba(253,204,16,0) 64%);
  animation-name: mesh-c, mesh-breathe; animation-duration: 31s, 19s; animation-delay: 0s, -3s;
}
.mesh .m4 {
  width: 44vmax; height: 44vmax; right: 16%; top: 0%;
  background: radial-gradient(circle at 50% 50%, rgba(22,163,74,.30), rgba(22,163,74,0) 66%);
  animation-name: mesh-d, mesh-breathe; animation-duration: 41s, 23s; animation-delay: 0s, -29s;
}
.mesh .m5 {
  width: 50vmax; height: 50vmax; left: 6%;  bottom: 0%;
  background: radial-gradient(circle at 50% 50%, rgba(235,65,52,.34), rgba(120,40,90,0) 68%);
  animation-name: mesh-e, mesh-breathe; animation-duration: 43s, 25s; animation-delay: 0s, -11s;
}
.mesh .m6 {
  width: 38vmax; height: 38vmax; left: 58%; bottom: 22%;
  background: radial-gradient(circle at 50% 50%, rgba(65,134,255,.34), rgba(65,134,255,0) 66%);
  animation-name: mesh-f, mesh-breathe; animation-duration: 47s, 27s; animation-delay: 0s, -37s;
}

@keyframes mesh-turn { to { transform: rotate(360deg); } }
@keyframes mesh-breathe { from { opacity: .55; } to { opacity: 1; } }
@keyframes mesh-a { 0%{transform:translate3d(0,0,0) scale(1)}    100%{transform:translate3d(8vw,6vh,0) scale(1.1)} }
@keyframes mesh-b { 0%{transform:translate3d(0,0,0) scale(1.05)}  100%{transform:translate3d(-9vw,-5vh,0) scale(.94)} }
@keyframes mesh-c { 0%{transform:translate3d(0,0,0) scale(.96)}   100%{transform:translate3d(6vw,-8vh,0) scale(1.14)} }
@keyframes mesh-d { 0%{transform:translate3d(0,0,0) scale(1.03)}  100%{transform:translate3d(-7vw,9vh,0) scale(.95)} }
@keyframes mesh-e { 0%{transform:translate3d(0,0,0) scale(1)}     100%{transform:translate3d(10vw,-4vh,0) scale(1.09)} }
@keyframes mesh-f { 0%{transform:translate3d(0,0,0) scale(1.06)}  100%{transform:translate3d(-5vw,-10vh,0) scale(.97)} }

/* A whisper of grain. Blurred gradients on a dark ground band badly on 8-bit
   panels and on a projector; noise at 3% breaks the banding without being
   visible as texture. */
.mesh-grain {
  position: fixed; inset: 0; z-index: 1; pointer-events: none; opacity: .035;
  background-image: url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'>\
<filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/></filter>\
<rect width='140' height='140' filter='url(%23n)'/></svg>");
}

/* A dark vignette over the mesh keeps the type crisp and the mood blackish. */
#opener::after {
  content: ""; position: fixed; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(125% 90% at 50% 42%, transparent 0%, rgba(8,8,10,.30) 56%, rgba(8,8,10,.82) 100%);
}
.opener-card, #opener-bottom { position: relative; z-index: 2; }

/* Anyone who asked for less motion gets a still mesh, not a jittering one. */
@media (prefers-reduced-motion: reduce) {
  .pick span::after, .corner-cube:hover::after { animation: none; opacity: 0; }
  .mesh { animation: none; }
  .mesh span { animation-name: mesh-breathe; animation-duration: 21s; }
}

body.no-doc #opener { display: flex; }
/* `margin: auto` centres the card in the space above the bottom bar, but when
   the card is taller than that space the margins shrink to nothing and the
   opener scrolls, instead of clipping the top of the card out of reach. */
.opener-card { max-width: 880px; width: 100%; margin: auto; text-align: center; flex: none; }

/* ── the two corners ────────────────────────────────────────────────────── */
/* The cube signs the page from the top-right corner and leads to the group's
   site; the group's name is spelled out in the footer, since the mark alone
   tells a stranger nothing. Sized per the logo rule (6–8% of the short edge)
   with a quarter-cube of clear space around it. */
.corner-cube {
  position: fixed; top: 18px; right: 18px; z-index: 3;
  display: block; width: 42px; height: 42px;
  transition: transform .34s cubic-bezier(.34, 1.36, .5, 1);   /* a little overshoot */
}
.corner-cube img {
  display: block; width: 100%; height: 100%;
  filter: drop-shadow(0 6px 14px rgba(0,0,0,.45));
}
.corner-cube:hover { transform: scale(1.3); }

/* Then the light travels over it, the way the WSE zirkel buttons do it: one
   105° band swept across, once, after the resize has landed.

   The band is a BACKGROUND, not a transform: the layer is masked to the cube's
   own silhouette, and moving the layer would drag that mask along with it —
   the cube would appear to slide rather than to catch the light. Moving the
   background inside a layer that stays put is what makes the gleam sit on the
   mark. */
.corner-cube::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background-image: linear-gradient(105deg,
    transparent 38%, rgba(255,255,255,.85) 50%, transparent 62%);
  background-size: 240% 100%;
  background-repeat: no-repeat;
  background-position: 100% 0;
  -webkit-mask: url("wse-logo.png") center / contain no-repeat;
          mask: url("wse-logo.png") center / contain no-repeat;
}
.corner-cube:hover::after { animation: cube-shine .78s ease-in-out .3s; }
@keyframes cube-shine {
  0%   { background-position: 100% 0; opacity: 0; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { background-position: 0% 0; opacity: 0; }
}
.corner-cube:focus-visible { outline: 3px solid var(--yellow); outline-offset: 5px; }
@media (max-width: 760px) {
  .corner-cube { width: 32px; height: 32px; top: 14px; right: 14px; }
}

/* "Fork me on GitHub" ribbon, top-left. Vendored so that it is in the
   precache and the page looks the same offline. */
/*
 * "Fork me on GitHub" CSS ribbon v0.2.3 | MIT License
 * https://github.com/simonwhitaker/github-fork-ribbon-css
*/

.github-fork-ribbon {
  width: 12.1em;
  height: 12.1em;
  position: absolute;
  overflow: hidden;
  top: 0;
  right: 0;
  z-index: 9999;
  pointer-events: none;
  font-size: 13px;
  text-decoration: none;
  text-indent: -999999px;
}

.github-fork-ribbon.fixed {
  position: fixed;
}

.github-fork-ribbon:hover, .github-fork-ribbon:active {
  background-color: rgba(0, 0, 0, 0.0);
}

.github-fork-ribbon:before, .github-fork-ribbon:after {
  /* The right and left classes determine the side we attach our banner to */
  position: absolute;
  display: block;
  width: 15.38em;
  height: 1.54em;

  top: 3.23em;
  right: -3.23em;

  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;

  -webkit-transform: rotate(45deg);
  -moz-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  -o-transform: rotate(45deg);
  transform: rotate(45deg);
}

.github-fork-ribbon:before {
  content: "";

  /* Add a bit of padding to give some substance outside the "stitching" */
  padding: .38em 0;

  /* Set the base colour */
  background-color: #a00;

  /* Set a gradient: transparent black at the top to almost-transparent black at the bottom */
  background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.15)));
  background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
  background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
  background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
  background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
  background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));

  /* Add a drop shadow */
  -webkit-box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5);
  -moz-box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5);
  box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5);

  pointer-events: auto;
}

.github-fork-ribbon:after {
  /* Set the text from the data-ribbon attribute */
  content: attr(data-ribbon);

  /* Set the text properties */
  color: #fff;
  font: 700 1em "Helvetica Neue", Helvetica, Arial, sans-serif;
  line-height: 1.54em;
  text-decoration: none;
  text-shadow: 0 -.08em rgba(0, 0, 0, 0.5);
  text-align: center;
  text-indent: 0;

  /* Set the layout properties */
  padding: .15em 0;
  margin: .15em 0;

  /* Add "stitching" effect */
  border-width: .08em 0;
  border-style: dotted;
  border-color: #fff;
  border-color: rgba(255, 255, 255, 0.7);
}

.github-fork-ribbon.left-top, .github-fork-ribbon.left-bottom {
  right: auto;
  left: 0;
}

.github-fork-ribbon.left-bottom, .github-fork-ribbon.right-bottom {
  top: auto;
  bottom: 0;
}

.github-fork-ribbon.left-top:before, .github-fork-ribbon.left-top:after, .github-fork-ribbon.left-bottom:before, .github-fork-ribbon.left-bottom:after {
  right: auto;
  left: -3.23em;
}

.github-fork-ribbon.left-bottom:before, .github-fork-ribbon.left-bottom:after, .github-fork-ribbon.right-bottom:before, .github-fork-ribbon.right-bottom:after {
  top: auto;
  bottom: 3.23em;
}

.github-fork-ribbon.left-top:before, .github-fork-ribbon.left-top:after, .github-fork-ribbon.right-bottom:before, .github-fork-ribbon.right-bottom:after {
  -webkit-transform: rotate(-45deg);
  -moz-transform: rotate(-45deg);
  -ms-transform: rotate(-45deg);
  -o-transform: rotate(-45deg);
  transform: rotate(-45deg);
}
.github-fork-ribbon.left-top:before { background-color: #f80; }
.github-fork-ribbon:after { font-family: var(--font); }
@media (max-width: 760px) { .github-fork-ribbon { font-size: 10px; } }

#opener h1 {
  font: 300 56px/1.05 "Fraunces", Georgia, serif; margin: 0 0 14px;
  letter-spacing: -.025em; color: var(--paper);
}
#opener h1 em { font-style: italic; color: var(--yellow); }
/* The app icon in front of the name, the way a launcher shows the two
   together. Sized in `em` so it follows the title through the compact
   variant below, and lifted with a shadow because its own ground is nearly
   the colour of the page it sits on. */
#opener h1 .title-mark {
  height: .94em; width: .94em; margin-right: .26em; vertical-align: -.13em;
  filter: drop-shadow(0 5px 12px rgba(0,0,0,.55));
}
#opener .lede { font: 400 21px/1.5 var(--font); color: #C9CBD1; margin: 0 0 22px; }
/* an app installed under an old address says where it lives now (#98) */
#opener .moved-note { margin: 0 0 18px; padding: 10px 14px; border: 1px solid var(--yellow); border-radius: 10px; font: 400 15px/1.45 var(--font); color: #E9EAEE; }
#opener .moved-note a { color: var(--yellow); font-weight: 600; overflow-wrap: anywhere; }

/* The features as a row of tags under the lede — the same device as on the
   WSE Transcribe start page, in the Bauhaus register: square, mono, a small
   colour block in front of each in the cube's three colours. */
.feature-tags {
  list-style: none; margin: 0 0 32px; padding: 0;
  display: flex; flex-wrap: wrap; gap: 9px; justify-content: center;
}
.feature-tags li {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 5px 12px 5px 11px;
  border: 1px solid rgba(255,255,255,.22);
  background: rgba(255,255,255,.05);
  font: 500 15px/1.4 var(--mono); color: #C9CBD1;
  white-space: nowrap;
}
.feature-tags li::before { content: ""; width: 8px; height: 8px; flex: none; background: var(--tag); }
.feature-tags li:nth-child(3n+1) { --tag: var(--red); }
.feature-tags li:nth-child(3n+2) { --tag: var(--yellow); }
.feature-tags li:nth-child(3n)   { --tag: var(--blue); }
.pick { display: inline-block; cursor: pointer; }
.pick input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.pick span {
  display: inline-block; padding: 15px 32px; background: var(--yellow); color: var(--ink);
  border: 2px solid var(--ink); box-shadow: 6px 6px 0 rgba(0,0,0,.5);
  font: 700 20px var(--font);
}
.pick:hover span   { transform: translate(2px, 2px); box-shadow: 4px 4px 0 rgba(0,0,0,.5); }

/* A single sweep of light over the one button that matters, a beat after the
   start page arrives. The same gesture as the zirkel buttons, played once
   rather than on a loop: this is an invitation, not a beacon. Here the band
   is nothing but a rectangle clipped by the button, so it can travel on a
   transform — no mask to drag along. */
.pick span { position: relative; overflow: hidden; }
.pick span::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg,
    transparent 38%, rgba(255,255,255,.75) 50%, transparent 62%);
  transform: translateX(-130%);
  animation: pick-shine 1s ease-in-out .7s;
}
@keyframes pick-shine {
  from { transform: translateX(-130%); }
  to   { transform: translateX(130%); }
}
.pick input:focus-visible + span { outline: 3px solid var(--blue); outline-offset: 3px; }
#opener .hint { font: 400 17px var(--font); color: #9CA0A8; margin: 16px 0 28px; }   /* UX-16: 4.5:1 over the brightest mesh */
/* 2026-10-21: what can be added, right below the button — a square in each
   type's colour, as on the cards' labels */
#opener .pick-types {
  margin: 18px 0 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 6px 16px; font: 600 15px var(--font); color: #C9CBD1;
}
#opener .pick-types + .hint { margin-top: 8px; }
.pick-types .ptype { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
:is(.pick-types .ptype, .recent-item .rtype)::before { content: ""; width: 8px; height: 8px; flex: none; background: var(--kind); }
:is(.ptype, .rtype)[data-kind="pdf"]    { --kind: var(--red); }
:is(.ptype, .rtype)[data-kind="html"]   { --kind: var(--blue); }
:is(.ptype, .rtype)[data-kind="google"] { --kind: var(--yellow); }
.keys-preview {
  list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px 16px;
  justify-content: center; font: 400 13px var(--font); color: #9CA0A8;
}
kbd {
  font: 600 12px var(--mono); background: rgba(255,255,255,.1); color: #E8E9EC;
  border: 1px solid rgba(255,255,255,.2); padding: 1px 6px; margin-right: 3px;
}

.ghost-btn {
  background: transparent; color: #C9CBD1; border: 2px solid rgba(255,255,255,.22);
  font: 600 13px var(--font); padding: 7px 13px; cursor: pointer;
}
.ghost-btn:hover { border-color: var(--yellow); color: var(--yellow); }
.help-card .ghost-btn { color: #333; border-color: #CDD1D6; }
.help-card .ghost-btn:hover { border-color: var(--ink); color: var(--ink); }
/* the pairing card is white too: its buttons need the dark variant (#14) */
.pair-card .ghost-btn { color: #333; border-color: #CDD1D6; }
.pair-card .ghost-btn:hover { border-color: var(--ink); color: var(--ink); }
.pair-card #pair-warn-ok { background: var(--red); border-color: var(--red); color: #fff; }
.pair-card #pair-warn-ok:hover { filter: brightness(.94); color: #fff; }

/* ── recently opened: a row along the bottom end of the start page ───────── */
/* The bar is the last thing in the opener's flow and sticks to the bottom of
   the screen: on a tall screen it simply sits at the bottom, on a short one the
   card scrolls beneath it and, scrolled to the end, nothing is left covered.
   The negative side margins undo the opener's padding so it spans the width. */
#opener-bottom {
  position: sticky; bottom: 0; z-index: 2; flex: none;
  margin: 24px -24px 0;
}

/* A laptop at 768 px of height, with the recent row showing, must still fit
   the whole card without scrolling: same content, tighter type and spacing. */
@media (max-height: 860px) {
  #opener h1 { font-size: 46px; margin-bottom: 8px; }
  #opener .lede { font-size: 18px; line-height: 1.45; margin-bottom: 14px; }
  .feature-tags { margin-bottom: 18px; gap: 6px; }
  .feature-tags li { font-size: 14px; padding: 4px 10px 4px 9px; }
  .pick span { padding: 12px 26px; font-size: 18px; }
  #opener .hint { margin: 10px 0 14px; }
  .opener-actions { margin-top: 14px; gap: 8px; }
  .opener-actions .ghost-btn { font-size: 15px; padding: 8px 14px; }
}
/* Semi-transparent: the mesh shows through the row, a touch of blur keeps
   the type legible over whatever colour is drifting past underneath. */
#recent {
  padding: 16px 24px 12px;
  background: linear-gradient(to top, rgba(8,8,10,.42), rgba(8,8,10,.20));
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  border-top: 2px solid rgba(255,255,255,.10);
}
#recent header {
  display: flex; align-items: baseline; gap: 14px; margin-bottom: 12px;
}
#recent h2 {
  font: 700 15px var(--font); text-transform: uppercase; letter-spacing: .1em;
  color: #9CA0A8; margin: 0;
}
#recent .ghost-btn { padding: 4px 11px; font-size: 14px; border-width: 1px; }
#recent .drop-hint { display: none; font: 600 15px var(--font); color: var(--yellow); }
/* the space this browser keeps for the site (feature options, risk 3) */
#recent .storage-use { margin-left: auto; font: 400 13px var(--font); color: #9CA0A8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
#recent .storage-use.low { color: #FF8A80; font-weight: 600; }
@media (max-width: 640px) {
  /* a row of its own on a phone, below the title and Forget all */
  #recent header { flex-wrap: wrap; row-gap: 4px; }
  #recent #recent-clear { margin-left: auto; }
  #recent .storage-use { order: 3; flex: 1 0 100%; margin-left: 0; white-space: normal; }
}

/* While a file is dragged over the window the row shows itself — even an
   empty one — and frames itself as the place to let go. */
body.dragging #recent[hidden] { display: block !important; }
body.dragging #recent { outline: 3px dashed var(--yellow); outline-offset: -10px; }
body.dragging #recent .drop-hint { display: inline; }
body.dragging #recent-row { min-height: 60px; }

/* The row scrolls sideways, and a scroller clips: the 8px around the cards
   (taken back by the negative margin, so nothing moves; the header keeps at
   least 8px below it) leave room for the glow of the last add (#79). */
#recent-row {
  display: flex; gap: 14px; overflow-x: auto; padding: 8px 8px 8px; margin: -8px -8px 0;
  scrollbar-width: thin;
}
.recent-item { position: relative; flex: 0 0 auto; width: 200px; }
.recent-item .ropen {
  display: block; width: 100%; padding: 0; background: transparent; border: none;
  cursor: pointer; text-align: left; color: inherit; font: inherit;
}
/* `contain`, not `cover`: a preview that crops the page is worse than a
   letterboxed one — a 16:9 deck loses its first and last words to the crop. */
.recent-item img, .recent-item .noshot {
  display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: contain;
  background: var(--paper);
  border: 3px solid transparent; box-shadow: 0 6px 16px rgba(0,0,0,.5);
}
.recent-item .noshot { display: grid; place-items: center; color: var(--gray); font-size: 22px; }
.recent-item .ropen:hover img, .recent-item .ropen:hover .noshot,
.recent-item .ropen:focus-visible img { border-color: var(--yellow); }
.recent-item .rshot { display: block; position: relative; }
/* 2026-10-21: the presentation's type, on the preview's lower-left corner;
   a long one ("Google Präsentationen") wraps on a short screen's small
   preview rather than being cut */
.recent-item .rtype {
  position: absolute; left: 7px; bottom: 7px; z-index: 1; max-width: calc(100% - 14px); box-sizing: border-box;
  display: block; width: max-content; padding: 2px 7px 2px 6px;
  background: var(--ink); color: var(--paper); font: 600 12px/1.35 var(--font);
  overflow-wrap: anywhere; pointer-events: none;
}
.recent-item .rtype::before { display: inline-block; margin-right: 6px; vertical-align: 1px; }

/* The last add (#79): its cards glow yellow, and a band of light crosses each
   preview every few seconds — the start button's shine, played on a loop
   rather than once, because this one has to be found again after the file
   dialog closed or the drop landed. It lasts until the next add. The band
   moves as a BACKGROUND inside a layer that stays put (as on the corner
   cube), so it stays on the preview without clipping the preview's shadow;
   `inset: 3px` keeps it inside the 3px border. It is gold with a white core:
   most slides are white, and a white gleam alone would cross them unseen. */
.recent-item.shine .rshot img, .recent-item.shine .rshot .noshot {
  box-shadow: 0 0 0 3px var(--yellow), 0 0 9px 1px rgba(253,204,16,.6), 0 6px 16px rgba(0,0,0,.5);
}
.recent-item.shine .rshot::after {
  content: ""; position: absolute; inset: 3px; pointer-events: none; opacity: 0;
  background-image: linear-gradient(105deg, transparent 41%, rgba(253,204,16,.38) 46.5%,
    rgba(255,250,225,.9) 50%, rgba(253,204,16,.38) 53.5%, transparent 59%);
  background-size: 240% 100%;
  background-repeat: no-repeat;
  background-position: 100% 0;
  animation: recent-shine 4.2s ease-in-out .5s infinite;
}
@keyframes recent-shine {
  0%   { background-position: 100% 0; opacity: 0; }
  4%   { opacity: 1; }
  27%  { opacity: 1; }
  31%  { background-position: 0% 0; opacity: 0; }
  100% { background-position: 0% 0; opacity: 0; }
}
/* the replace question of an add says "add", of a start "open" (#79 review) */
#html-trust:not(.adding) .trust-to-add, #html-trust.adding .trust-to-open { display: none; }
/* constant motion is what reduced motion asks to leave out: the glow stays */
@media (prefers-reduced-motion: reduce) {
  .recent-item.shine .rshot::after { animation: none; }
}
/* …and a label "New" on its preview's upper-left corner (2026-10-26), in the
   shine's yellow, clear of the ✕ in the other corner */
.recent-item .rbadge {
  position: absolute; left: 7px; top: 7px; z-index: 1;
  padding: 2px 8px; background: var(--yellow); color: var(--ink);
  font: 700 12px/1.35 var(--font); letter-spacing: .02em;
  box-shadow: 0 1px 4px rgba(0,0,0,.35); pointer-events: none;
}
/* "last added", for a screen reader: the shine alone would not say it */
.recent-item .rnew {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.recent-item .rname {
  display: block; margin-top: 7px; font: 600 15.5px var(--font); color: #E8E9EC;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.recent-item .rmeta {
  display: block; margin-top: 2px; font: 400 14px var(--mono); color: #9CA0A8;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.recent-item .rwhen {
  display: block; margin-top: 1px; font: 400 14px var(--mono); color: #9CA0A8;
}
.recent-item .rkill {
  position: absolute; top: 5px; right: 5px; width: 28px; height: 28px;
  border: 2px solid var(--ink); background: var(--paper); color: var(--ink);
  font: 700 11px/1 var(--font); cursor: pointer; display: none;
  align-items: center; justify-content: center; padding: 0;
}
/* …shown on hover, to the keyboard, and always on a touch screen (UX-14) */
.recent-item:is(:hover, :focus-within) .rkill { display: flex; }
@media (hover: none) { .recent-item .rkill { display: flex; } }
.recent-item .rkill:hover { background: var(--red); color: var(--paper); border-color: var(--red); }

/* Short screens (see the card's compact rules above): the recent row turns
   sideways — preview left, its three lines right — which halves the bar's
   height and is what lets the whole card sit above it. Placed after the
   base rules on purpose: same specificity, so order decides. */
@media (max-height: 860px) {
  #recent { padding-top: 12px; }
  #recent header { margin-bottom: 8px; }
  .recent-item { width: 290px; }
  .recent-item .ropen {
    display: grid; grid-template-columns: 116px minmax(0, 1fr);
    grid-template-rows: 1fr auto auto auto 1fr; column-gap: 10px;
  }
  .recent-item .ropen .rshot { grid-column: 1; grid-row: 1 / 6; align-self: start; }
  .recent-item .rname { grid-column: 2; grid-row: 2; margin-top: 0; }
  .recent-item .rmeta { grid-column: 2; grid-row: 3; }
  .recent-item .rwhen { grid-column: 2; grid-row: 4; }
}


.help-remote { padding: 0 22px 4px; }
/* what went wrong (feature options, risk 13) */
.help-diag { padding: 0 22px 4px; }
.help-diag h3 { font: 700 13px var(--font); text-transform: uppercase; letter-spacing: .08em; color: var(--gray); margin: 8px 0 8px; }
.help-diag p { font: 400 13.5px/1.5 var(--font); color: #333; margin: 0 0 10px; }
.diag-list { margin: 0 0 10px; padding: 0; list-style: none; max-height: 9.5em; overflow-y: auto; font: 400 12.5px/1.5 var(--mono); color: #333; }
.diag-list li[data-kind="error"], .diag-list li[data-kind="uncaught"] { color: #B3261E; }
.annotation-actions { display: flex; gap: 10px; padding: 0 22px 10px; margin: 0; }
.help-remote h3 {
  font: 700 13px var(--font); text-transform: uppercase; letter-spacing: .08em;
  color: var(--gray); margin: 6px 0 8px;
}
.help-remote p { font: 400 13.5px/1.5 var(--font); color: #333; margin: 0 0 10px; }
.help-remote p:last-child { display: flex; gap: 10px; flex-wrap: wrap; }

/* ── overlays ────────────────────────────────────────────────────────────── */
#blank { position: fixed; inset: 0; z-index: 90; background: #000; }
#blank.white { background: #fff; }

#overview {
  position: fixed; inset: 0; z-index: 85; background: var(--backdrop);
  display: flex; flex-direction: column;
}
#overview header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 22px; border-bottom: 2px solid rgba(255,255,255,.12);
}
#overview h2 { font: 700 20px var(--font); margin: 0; }
/* F-05: find a slide by its words */
#overview header { gap: 14px; }
#ov-search { flex: 1; max-width: 420px; margin-left: auto; font: 400 16px var(--font); padding: 7px 12px; border: 2px solid rgba(255,255,255,.3); border-radius: 6px; background: rgba(255,255,255,.08); color: inherit; }
#ov-search:focus { outline: none; border-color: var(--yellow); }
#ov-found { font: 600 14px var(--font); color: #C9CBD1; min-width: 6em; }
.ov-item.ov-miss { opacity: .22; }
.ov-item.ov-hit canvas { outline: 4px solid var(--yellow); outline-offset: 2px; }
#overview header button, #help header button {
  background: transparent; border: none; color: var(--paper); font-size: 22px; cursor: pointer;
  line-height: 1; padding: 4px 8px;
}
/* The columns are set from JS (layoutOverview) once the page shape and the
   space available are both known; this is only what the grid looks like in the
   instant before that, and the fallback if the measurement ever comes back
   empty. `justify-content` keeps a grid that no longer fills the width centred
   rather than piled against the left edge. */
#ov-grid {
  flex: 1; overflow-y: auto; padding: 20px 22px 40px;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 18px;
  justify-content: center; align-content: start;
}
.ov-item { cursor: pointer; border: none; background: transparent; padding: 0; text-align: center; }
.ov-item canvas {
  width: 100%; height: auto; display: block; background: var(--paper);
  border: 3px solid transparent; box-shadow: 0 8px 20px rgba(0,0,0,.5);
}
.ov-item:hover canvas    { border-color: var(--yellow); }
.ov-item.current canvas  { border-color: var(--blue); }
.ov-item .n { display: block; font: 600 12px var(--mono); color: #9CA0A8; padding-top: 7px; }
.ov-item .marked { color: var(--yellow); }

#help {
  position: fixed; inset: 0; z-index: 88; background: rgba(11,11,12,.9);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.help-card {
  background: var(--paper); color: var(--ink); border: 2px solid var(--ink);
  box-shadow: 10px 10px 0 rgba(0,0,0,.5);
  max-width: 760px; width: 100%; max-height: 86vh; overflow-y: auto;
}
.help-card header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 20px; border-bottom: 2px solid var(--ink);
}
.help-card h2 { margin: 0; font: 700 19px var(--font); }
.help-card header button { color: var(--ink); }
.help-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 4px 34px; padding: 20px 22px 8px; }
.help-cols h3 { font: 700 13px var(--font); text-transform: uppercase; letter-spacing: .08em; color: var(--gray); margin: 0 0 10px; }
.help-cols dl { display: grid; grid-template-columns: auto 1fr; gap: 7px 14px; margin: 0 0 18px; align-items: baseline; }
.help-cols dt { white-space: nowrap; }
.help-cols dd { margin: 0; font: 400 14px var(--font); color: #333; }
.help-card kbd { background: var(--line); color: var(--ink); border: 1px solid #CDD1D6; }
.help-foot { margin: 0; padding: 6px 22px 18px; font: 400 13px var(--font); color: var(--gray); }

#toast {
  position: fixed; left: 50%; bottom: calc(68px + var(--foot-lift)); transform: translateX(-50%); z-index: 92;
  background: var(--ink); color: var(--paper); border-left: 5px solid var(--yellow);
  padding: 10px 16px; font: 600 14px var(--font); box-shadow: 5px 5px 0 rgba(0,0,0,.4);
  max-width: 70vw;
}
/* above a phone's footer of two rows (UX-04) */
@media (max-width: 640px) { #toast:not(.top) { bottom: calc(104px + var(--foot-lift)); } }
/* a failure (UX-24): a red edge; and above an open dialog, not over it */
#toast.error { border-left-color: var(--red); }
#toast.top { top: 16px; bottom: auto; }
/* an earlier error, above the message that followed it (feature options, risk 13) */
#toast-held {
  position: fixed; left: 50%; bottom: calc(124px + var(--foot-lift)); transform: translateX(-50%); z-index: 92;
  background: var(--ink); color: var(--paper); border-left: 5px solid var(--red);
  padding: 10px 16px; font: 600 14px var(--font); box-shadow: 5px 5px 0 rgba(0,0,0,.4);
  max-width: 70vw;
  pointer-events: none;            /* a notice: what lies under it stays clickable */
}
#toast-held.top { top: 72px; bottom: auto; }
@media (max-width: 640px) { #toast-held:not(.top) { bottom: calc(160px + var(--foot-lift)); } }

/* A device asks to be the remote (feature options, risk 5): top right, over
   the chrome, not modal — the talk goes on, and the focus stays where it is. */
#pair-request {
  position: fixed; top: 16px; right: 16px; z-index: 93; max-width: min(360px, calc(100vw - 32px));
  background: var(--ink); color: var(--paper); border-left: 5px solid var(--yellow);
  padding: 12px 16px; font: 600 14px var(--font); box-shadow: 5px 5px 0 rgba(0,0,0,.4);
}
#pair-request p { margin: 0 0 10px; }
#pair-request .pair-request-more { font-weight: 400; color: #C9CBD1; }
#pair-request .pair-request-more:empty { display: none; }
#pair-request .pair-request-actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }
#pair-request button { font: 600 14px var(--font); padding: 7px 14px; min-height: 40px; border: 2px solid var(--paper); background: transparent; color: var(--paper); cursor: pointer; }
#pair-request #pair-allow { background: var(--yellow); border-color: var(--yellow); color: var(--ink); }
#pair-request button:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }
/* read by a screen reader, not shown */
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
#jump {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%,-50%); z-index: 92;
  background: rgba(17,17,17,.92); color: var(--paper); border: 2px solid var(--yellow);
  padding: 14px 26px; font: 700 42px var(--mono);
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

/* ═══ start-page footer, features overlay, guided tour ═════════════════════ */

/* The WSE attribution bar, the same idea as the one on the RoboRoyale app. */
/* One line at the bottom of the screen carrying all three standing statements:
   who built it, what happens to your files, and which version this is. They
   are the same KIND of thing — small print you read once — so they belong on
   one baseline rather than stacked into a block that competes with the page.
   Three columns with equal outer tracks put the privacy statement in the
   middle of the SCREEN, not merely between its neighbours. */
.attribution {
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center; gap: 16px;
  padding: 9px 24px 11px;
  border-top: 1px solid rgba(255,255,255,.10);
  background: rgba(8,8,10,.72);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  font: 400 15.5px/1.4 var(--font); color: #9CA0A8;
}
.att-who { min-width: 0; }
.att-who .wse-cube {
  height: 1em; width: auto; vertical-align: -.12em; margin-right: .3em;
}                     /* wraps to a second line before it truncates */
.att-privacy { text-align: center; white-space: nowrap; }
.att-privacy strong { color: #C9CBD1; font-weight: 600; }

/* Narrow screens: the privacy statement is the one that must survive, so the
   attribution drops first rather than truncating both into uselessness. */
@media (max-width: 760px) {
  .attribution { gap: 8px; padding: 8px 14px 10px; font-size: 14px; }
  .att-who { visibility: hidden; }             /* keeps its track, so the centre stays centred */
}
.attribution a { color: #C9CBD1; text-decoration: none; border-bottom: 1px solid rgba(255,255,255,.28); }
.attribution a:hover { color: var(--yellow); border-bottom-color: var(--yellow); }
.version-chip {
  justify-self: end;
  font: 600 15px var(--mono); color: #9CA0A8 !important;
  border: 1px solid rgba(255,255,255,.20) !important;
  padding: 2px 9px; letter-spacing: .02em; white-space: nowrap;
}
.version-chip:hover { color: var(--yellow) !important; border-color: var(--yellow) !important; }

/* The four things you can do before opening a file, on one line. Each has a
   line that says what will happen, shown on hover or keyboard focus — a bare
   label ("Take the tour") made people guess, a permanent description made
   the page long. The tip opens UPWARDS: below the buttons sits the row of
   recent files, which would cover it. */
.opener-actions {
  margin: 28px 0 0; display: flex; gap: 10px;
  justify-content: center; flex-wrap: wrap;
}
.opener-actions .ghost-btn { font-size: 16px; padding: 9px 16px; }
.act { position: relative; display: inline-block; }
.act .tip {
  position: absolute; left: 50%; bottom: calc(100% + 10px); transform: translateX(-50%);
  width: max-content; max-width: min(320px, 80vw);
  padding: 9px 13px; background: var(--paper); color: var(--ink);
  border: 2px solid var(--ink); box-shadow: 5px 5px 0 rgba(0,0,0,.5);
  font: 400 15px/1.45 var(--font); text-align: left;
  opacity: 0; visibility: hidden; transition: opacity .12s, visibility .12s;
  pointer-events: none; z-index: 5;
}
.act:hover .tip, .act:focus-within .tip { opacity: 1; visibility: visible; }
.act.tip-off .tip { opacity: 0; visibility: hidden; }          /* put away with Escape (UX-33) */

/* ── features overlay ────────────────────────────────────────────────────── */
#features {
  position: fixed; inset: 0; z-index: 88; background: rgba(8,8,10,.92);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.feat-card {
  background: var(--paper); color: var(--ink);
  border: 1px solid rgba(17,17,17,.10); border-radius: 18px;
  box-shadow: 0 20px 60px rgba(0,0,0,.55);
  max-width: 940px; width: 100%; max-height: 88vh; overflow-y: auto;
}
.feat-card header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 24px 14px; border-bottom: 1px solid var(--line);
  position: sticky; top: 0; background: var(--paper); border-radius: 18px 18px 0 0;
}
.feat-card h2 { margin: 0; font: 700 20px var(--font); }
.feat-card header button {
  background: transparent; border: none; color: var(--ink); font-size: 20px;
  cursor: pointer; line-height: 1; padding: 4px 8px; border-radius: 8px;
}
.feat-card header button:hover { background: var(--line); }
.feat-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 22px 30px; padding: 22px 24px 8px;
}
.feat-grid h3 {
  margin: 0 0 6px; font: 700 15px var(--font);
  display: flex; align-items: center; gap: 9px;
}
.feat-grid .fi {
  width: 12px; height: 12px; background: var(--fi, var(--red));
  display: block; flex: 0 0 auto; border-radius: 3px;
}
.feat-grid p { margin: 0; font: 400 13.5px/1.55 var(--font); color: #4A4E55; }
.feat-foot { margin: 0; padding: 6px 24px 22px; font: 400 13px var(--font); color: var(--gray); }
.feat-card kbd { background: var(--line); color: var(--ink); border: 1px solid #CDD1D6; }

/* ── guided tour: a spotlight on the real element, plus a card ───────────── */
#tutorial { position: fixed; inset: 0; z-index: 95; }
/* The dimming is the spotlight's own giant shadow, so the hole is genuinely
   transparent — no clip-path, no second element to keep in sync. */
#tut-spotlight {
  position: absolute; border-radius: 12px;
  box-shadow: 0 0 0 9999px rgba(8,8,10,.80), 0 0 0 2px var(--yellow);
  transition: left .22s ease, top .22s ease, width .22s ease, height .22s ease;
  pointer-events: none;
}
#tut-card {
  position: absolute; width: min(340px, calc(100vw - 32px));
  max-height: calc(100vh - 16px); overflow-y: auto; box-sizing: border-box;
  background: var(--paper); color: var(--ink);
  border-radius: 14px; padding: 16px 18px 14px;
  box-shadow: 0 16px 40px rgba(0,0,0,.55);
}
#tut-card h2 { margin: 4px 0 6px; font: 700 16px var(--font); }
#tut-card p { margin: 0 0 14px; font: 400 13.5px/1.5 var(--font); color: #4A4E55; }
#tut-count { font: 600 11px var(--mono); color: var(--gray); letter-spacing: .06em; }
.tut-actions { display: flex; align-items: center; gap: 8px; }
.tut-actions .spacer { flex: 1; }
.tut-actions button {
  font: 600 13px var(--font); padding: 7px 13px; border-radius: 9px;
  border: 1px solid #CDD1D6; background: var(--paper); color: var(--ink); cursor: pointer;
}
.tut-actions button:hover { background: var(--line); }
.tut-actions button[disabled] { opacity: .4; cursor: default; }
.tut-actions button.primary {
  background: var(--yellow); border-color: var(--yellow); color: var(--ink); font-weight: 700;
}
.tut-actions button.linkish {
  border-color: transparent; background: transparent; color: var(--gray); padding-left: 0;
}
.tut-actions button.linkish:hover { color: var(--ink); background: transparent; text-decoration: underline; }
@media (prefers-reduced-motion: reduce) { #tut-spotlight { transition: none; } }

/* ═══ paired devices: pairing panel, remote, mirror ════════════════════════ */

#pair {
  position: fixed; inset: 0; z-index: 90; background: rgba(8,8,10,.92);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.pair-card {
  background: var(--paper); color: var(--ink);
  border-radius: 18px; box-shadow: 0 20px 60px rgba(0,0,0,.55);
  max-width: 780px; width: 100%; max-height: 88vh; overflow-y: auto;
}
.pair-card header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 24px 14px; border-bottom: 1px solid var(--line);
}
.pair-card h2 { margin: 0; font: 700 20px var(--font); }
.pair-card header button {
  background: transparent; border: none; color: var(--ink); font-size: 20px;
  cursor: pointer; line-height: 1; padding: 4px 8px; border-radius: 8px;
}
.pair-card header button:hover { background: var(--line); }
.pair-cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 8px 32px; padding: 20px 24px 4px;
}
.pair-cols h3 { margin: 0 0 8px; font: 700 15px var(--font); }
.pair-cols p { margin: 0 0 12px; font: 400 13.5px/1.5 var(--font); color: #4A4E55; }
#pair-pin {
  font: 700 34px/1.1 var(--mono); letter-spacing: .06em; color: var(--ink);
  background: var(--yellow); border-radius: 10px; padding: 12px 8px;
  text-align: center; margin: 4px 0 10px;
}
.pair-peers { font: 600 12.5px var(--mono) !important; color: var(--gray) !important; }
#pin-input {
  font: 700 26px var(--mono); letter-spacing: .16em; text-align: center;
  width: 100%; padding: 10px 8px; border-radius: 10px;
  border: 2px solid var(--line); background: #FAFBFC; color: var(--ink);
}
#pin-input:focus { outline: none; border-color: var(--blue); }
.pair-roles { display: flex; gap: 10px; flex-wrap: wrap; }
.pair-status { margin: 4px 24px 0; font: 600 13px var(--font); color: var(--gray); min-height: 1.2em; }
.pair-status[data-tone="ok"]   { color: #15803D; }
.pair-status[data-tone="warn"] { color: #B7920A; }
.pair-status[data-tone="bad"]  { color: var(--red); }
.pair-note { margin: 10px 0 0; padding: 10px 24px 22px; font: 400 12.5px/1.6 var(--font); color: var(--gray); }
.pair-note strong { color: var(--ink); }

/* ── the remote: built for a thumb, not a mouse ──────────────────────────── */
#control-view, #mirror-view {
  position: fixed; inset: 0; z-index: 92; background: var(--backdrop);
  display: flex; flex-direction: column;
}
.ctl-head {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  font: 600 13px var(--font); color: #C9CBD1;
  border-bottom: 1px solid rgba(255,255,255,.10);
}
.ctl-head .spacer { flex: 1; }
#ctl-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 45vw; }
#ctl-page { font: 700 14px var(--mono); color: var(--yellow); }
#ctl-pad {
  flex: 1; margin: 12px 14px; border-radius: 16px;
  border: 2px dashed rgba(255,255,255,.18);
  background: rgba(255,255,255,.03);
  display: grid; place-items: center;
  touch-action: none;               /* the pad IS the gesture; never scroll */
  -webkit-user-select: none; user-select: none;
  cursor: crosshair;
}
#ctl-pad-hint { font: 400 13px var(--font); color: #6B7280; pointer-events: none; }
#ctl-tools, #ctl-colors { display: flex; gap: 8px; padding: 0 14px 10px; justify-content: center; flex-wrap: wrap; }
#ctl-tools button {
  flex: 1 1 0; min-width: 74px; padding: 11px 8px; border-radius: 11px;
  border: 1px solid rgba(255,255,255,.22); background: transparent;
  color: #C9CBD1; font: 600 13px var(--font); cursor: pointer;
}
#ctl-tools button.active { background: var(--paper); color: var(--ink); border-color: var(--paper); }
#ctl-colors button {
  width: 34px; height: 34px; border-radius: 9px; background: var(--sw);
  border: 2px solid rgba(255,255,255,.22); cursor: pointer; padding: 0;
}
#ctl-colors button.active { border-color: var(--paper); box-shadow: 0 0 0 2px var(--ink), 0 0 0 4px var(--paper); }
#ctl-nav { display: flex; gap: 10px; padding: 0 14px calc(14px + env(safe-area-inset-bottom)); }
#ctl-nav button {
  flex: 1; padding: 20px 0; border-radius: 14px; border: none;
  background: var(--yellow); color: var(--ink);
  font: 700 30px/1 var(--font); cursor: pointer;
}
#ctl-nav button:active { transform: translateY(1px); filter: brightness(.94); }

/* ── the mirror: the slide, and nothing else ─────────────────────────────── */
#mirror-view { background: #0B0B0C; }
#mirror-canvas { position: absolute; inset: 0; display: block; }
.mirror-bar {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  display: flex; align-items: center; gap: 12px; padding: 8px 14px;
  background: linear-gradient(to top, rgba(0,0,0,.7), transparent);
  font: 600 12.5px var(--font); color: #9CA0A8;
  opacity: 0; transition: opacity .2s ease;
}
#mirror-view:hover .mirror-bar, .mirror-bar:focus-within, #mirror-view.show-bar .mirror-bar { opacity: 1; }
/* the bar is dark in both themes, so its button is light in both (UX-17) */
.mirror-bar .ghost-btn, html[data-theme="light"] .mirror-bar .ghost-btn { color: #C9CBD1; border-color: rgba(255,255,255,.3); }
#mirror-info { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* while a device is acting as a remote or a screen, the player itself is not
   what this browser is for */
body.mode-control #opener, body.mode-mirror #opener,
body.mode-control #stage-wrap, body.mode-mirror #stage-wrap,
body.mode-control .chrome, body.mode-mirror .chrome,
body.mode-control #progress, body.mode-mirror #progress,
body.mode-control #talk-line, body.mode-mirror #talk-line,
body.mode-control #talk-warn, body.mode-mirror #talk-warn { display: none !important; }

/* The zoom factor and its reset, in the upper-right corner exactly while
   the page is zoomed (2026-10-26; in the footer since #14): left of the
   close button's place, so that the two never cover each other, and a dark
   pill like that button, legible on any slide. Not a part of the footer —
   it stays while the pointer is away — but K hides it with the chrome. */
#zoom-box {
  position: fixed; top: 16px; right: 66px; z-index: 45;
  display: flex; align-items: center; gap: 2px; height: 40px; padding: 0 4px 0 6px;
  border-radius: 20px; background: rgba(0,0,0,.62); color: #fff;
  box-shadow: 0 2px 10px rgba(0,0,0,.35);
  font: 700 14px var(--mono); white-space: nowrap;
  cursor: default;                 /* in the top strip, where the pointer is hidden, it shows one */
}
#zoom-box[hidden] { display: none; }
/* the factor is a list of set levels (2026-10-26): it looks like the factor,
   with a small caret, and opens the browser's own list */
#zoom-select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  height: 32px; padding: 0 22px 0 8px; border: none; border-radius: 16px;
  color: #fff; font: inherit; cursor: pointer;
  background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='white' stroke-width='1.6'/%3E%3C/svg%3E") no-repeat right 8px center / 10px 6px;
}
#zoom-select:hover { background-color: rgba(255,255,255,.2); }
#zoom-select:focus-visible { outline: 3px solid var(--yellow); outline-offset: 2px; }
#zoom-select option { color: #111; background: #fff; font: 600 15px var(--mono); }
#zoom-box button {
  width: 32px; height: 32px; padding: 6px; border: none; border-radius: 50%;
  background: transparent; color: #fff; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
#zoom-box button svg { width: 20px; height: 20px; display: block; }
#zoom-box button:hover { background: rgba(255,255,255,.2); }
#zoom-box button:focus-visible { outline: 3px solid var(--yellow); outline-offset: 2px; }
/* the close button steps left of the tool column below 800 px of height */
@media (max-height: 800px) { #zoom-box { right: 134px; } }
body.no-doc #zoom-box, body.chrome-off #zoom-box,
body.mode-control #zoom-box, body.mode-mirror #zoom-box, body.mode-audience #zoom-box { display: none !important; }
/* ── #14: the warning before the PIN, the QR code, the live remote ─────────── */
.pair-warn {
  border: 2px solid var(--red); border-radius: 12px; padding: 12px 14px 4px;
  background: #FEF2F1; margin: 0 0 12px;
}
.pair-warn p { color: var(--ink); }
.pair-warn-actions { display: flex; gap: 8px; flex-wrap: wrap; }
#pair-qr { display: flex; justify-content: center; margin: 0 0 10px; }
#pair-qr svg { width: 190px; height: 190px; display: block; border-radius: 8px; }
#ctl-pad { position: relative; overflow: hidden; }
#ctl-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none; }
#ctl-pad.has-slide { border-style: solid; background: #0B0B0C; }
#ctl-pad.has-slide #ctl-pad-hint {
  position: absolute; left: 50%; bottom: 8px; transform: translateX(-50%);
  background: rgba(0,0,0,.6); color: #C9CBD1; padding: 3px 10px; border-radius: 999px; white-space: nowrap;
}
#ctl-tools button.has-icon { min-width: 44px; padding: 9px 6px; display: grid; place-items: center; }
/* a phone (UX review: UX-18, UX-28): the name and the brand on a row of their
   own rather than cut to a letter; the hint wraps; theme buttons a thumb hits */
@media (max-width: 420px) {
  .ctl-head, .aud-head { flex-wrap: wrap; row-gap: 6px; }
  #ctl-name { flex: 1 0 100%; max-width: none; order: -1; }
  .aud-brand { flex: 1 0 100%; }
  /* five equal columns: Redo and Clear no longer stretch into the largest
     targets of the remote (UX-28); Clear stays last */
  #ctl-tools { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); }
  #ctl-tools button, #ctl-tools button.has-icon { min-width: 0; }
}
#ctl-pad.has-slide #ctl-pad-hint { white-space: normal; max-width: calc(100% - 24px); text-align: center; }
#ctl-tools button.has-icon svg { width: 22px; height: 22px; display: block; }
#ctl-tools button.has-icon .dot { fill: var(--deck-laser-color, #EB4134); }
#ctl-tools button.has-icon .ring { fill: none; stroke: currentColor; stroke-width: 1.6; }
#ctl-note {
  position: absolute; z-index: 2; display: flex; gap: 6px; width: 212px;
  background: var(--paper); border-radius: 10px; padding: 6px; box-shadow: 0 8px 24px rgba(0,0,0,.5);
}
#ctl-note[hidden] { display: none; }
#ctl-note input { flex: 1; min-width: 0; font: 400 15px var(--font); border: 1px solid var(--line); border-radius: 7px; padding: 6px 8px; }
#ctl-note button { font: 700 13px var(--font); border: none; border-radius: 7px; background: var(--yellow); color: var(--ink); padding: 0 10px; }

/* ═══ audience interactions (#16) ══════════════════════════════════════════ */
#ia-fab {
  position: fixed; right: 18px; bottom: calc(76px + var(--foot-lift)); z-index: 46;
  width: 48px; height: 48px; border-radius: 14px; border: none; cursor: pointer;
  background: var(--blue); color: #fff; display: grid; place-items: center;
  box-shadow: 0 8px 24px rgba(0,0,0,.45);
}
#ia-fab svg { width: 26px; height: 26px; }
#ia-fab.live::after {
  content: ""; position: absolute; top: 6px; right: 6px; width: 9px; height: 9px; border-radius: 50%;
  background: #16A34A; box-shadow: 0 0 0 2px #fff;      /* live: green, as in the panel (UX-25) */
}
#ia-fab[hidden], #ia-panel[hidden], #audience-view[hidden] { display: none; }
body.no-doc #ia-fab, body.mode-control #ia-fab, body.mode-mirror #ia-fab, body.mode-audience #ia-fab { display: none; }
#ia-panel {
  position: fixed; inset: 0; z-index: 89; background: rgba(8,8,10,.94);
  display: flex; align-items: stretch; justify-content: center; padding: 18px;
}
/* a file dragged over the panel (2026-10-27): it says what a drop does,
   over the whole card, without taking the drag from what lies below */
.ia-drop-hint {
  position: absolute; inset: 18px; z-index: 10; display: none; place-items: center;
  border: 4px dashed var(--yellow); border-radius: 18px; background: rgba(17,17,17,.84);
  color: #fff; font: 700 22px/1.35 var(--font); text-align: center; padding: 24px; pointer-events: none;
}
#ia-panel.ia-drop-ready .ia-drop-hint { display: grid; }
.ia-card {
  background: var(--paper); color: var(--ink); border-radius: 18px; width: 100%; max-width: 1400px;
  display: flex; flex-direction: column; overflow: hidden; box-shadow: 0 20px 60px rgba(0,0,0,.55);
}
.ia-card header { display: flex; align-items: center; gap: 14px; padding: 14px 22px; border-bottom: 1px solid var(--line); }
.ia-card h2 { margin: 0; font: 700 20px var(--font); }
.ia-config-name { flex: 1; font: 600 13px var(--mono); color: var(--gray); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#ia-close { background: transparent; border: none; font-size: 20px; cursor: pointer; padding: 4px 8px; border-radius: 8px; color: var(--ink); }
#ia-close:hover { background: var(--line); }
.ia-body { flex: 1; display: grid; grid-template-columns: minmax(250px, 320px) 1fr; min-height: 0; }
.ia-side { border-right: 1px solid var(--line); padding: 16px 18px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
.ia-side h3 { margin: 4px 0 0; font: 700 14px var(--font); }
.ia-btn {
  font: 600 13px var(--font); padding: 8px 12px; border-radius: 9px; cursor: pointer;
  border: 1px solid #CDD1D6; background: #fff; color: #222;
}
.ia-btn:hover { border-color: var(--ink); }
/* the icons of the overlay (#53): beside the text, in the text's colour */
.ia-icon { width: 1.2em; height: 1.2em; flex: none; display: inline-block; vertical-align: -.22em; }
.ia-card .ia-has-icon:not(.ia-row-main) { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.ia-row-title { display: flex; align-items: center; gap: 8px; min-width: 0; }
#ia-close .ia-icon { width: 22px; height: 22px; }
.ia-row-main .ia-row-icon { width: 20px; height: 20px; color: #2563EB; }
.ia-row.ia-off .ia-row-icon { color: var(--gray); }
.ia-del .ia-icon { width: 14px; height: 14px; }
.ia-btn:disabled { opacity: .4; cursor: default; }
.ia-btn.ia-primary { background: var(--blue); border-color: var(--blue); color: #fff; }
.ia-btn.ia-danger { background: var(--red); border-color: var(--red); color: #fff; }
.ia-files { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.ia-reset-confirm { font: 600 13px var(--font); display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.ia-list { display: flex; flex-direction: column; gap: 6px; }
.ia-audience { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; }
.ia-qr svg { width: 180px; height: 180px; display: block; }
.ia-pin { font: 700 34px/1.1 var(--mono); letter-spacing: .06em; background: var(--yellow); border-radius: 10px; padding: 8px 16px; }
.ia-count { margin: 0; font: 700 14px var(--mono); color: #15803D; }
.ia-how { margin: 0; font: 400 12px/1.4 var(--font); color: var(--gray); }
.ia-check-result { font: 400 12.5px/1.45 var(--font); border-radius: 10px; padding: 8px 10px; }
.ia-check-result[data-tone="ok"] { background: #ECFDF3; color: #14532D; }
.ia-check-result[data-tone="bad"] { background: #FEF2F1; color: #7F1D1D; }
.ia-check-result ul { margin: 6px 0 0; padding-left: 18px; max-height: 220px; overflow-y: auto; }
.ia-check-head { margin: 0; font-weight: 700; }
.ia-stage { padding: 20px 28px; overflow-y: auto; display: flex; flex-direction: column; gap: 14px; }
.ia-empty { margin: auto; font: 400 16px var(--font); color: var(--gray); max-width: 40ch; text-align: center; }
.ia-stage-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.ia-stage-head h3 { margin: 0; font: 700 26px var(--font); }
.ia-step { font: 600 13px var(--mono); color: var(--gray); }
.ia-desc { font: 400 22px/1.4 var(--font); }
.ia-desc p { margin: 0 0 .4em; }
.ia-caption { font-size: 16px; color: #4A4E55; }
.ia-media { max-width: 100%; max-height: 60vh; overflow: auto; }
.ia-media img, .ia-media video { max-width: 100%; max-height: 60vh; display: block; }
.ia-media audio { width: 100%; }
.ia-counter { margin: 0; font: 700 16px var(--mono); color: #15803D; }
.ia-hidden { font: 400 16px var(--font); color: var(--gray); }
.ia-controls { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: auto; padding-top: 8px; border-top: 1px solid var(--line); }
.ia-controls #ia-next { margin-left: auto; }
#ia-vis { font: 600 13px var(--font); padding: 7px 8px; border-radius: 9px; border: 1px solid #CDD1D6; }
/* select results: bars, or big numbers */
.ia-select { display: flex; flex-direction: column; gap: 10px; }
.ia-opt { display: grid; grid-template-columns: minmax(120px, 28%) 1fr auto; gap: 12px; align-items: center; font: 600 20px var(--font); }
.ia-bar { height: 30px; background: #EEF0F3; border-radius: 8px; overflow: hidden; }
.ia-bar > span { display: block; height: 100%; width: 0; background: var(--blue); border-radius: 8px; transition: width .7s cubic-bezier(.2,.8,.2,1); }
.ia-num { font: 400 18px var(--mono); white-space: nowrap; }
.ia-num b { font-size: 22px; }
.ia-numbers_and_percentage .ia-opt { grid-template-columns: 1fr auto; }
.ia-numbers_and_percentage .ia-bar { display: none; }
.ia-numbers_and_percentage .ia-num b { font-size: 40px; }
/* texts */
.ia-text { margin: 0; padding: 0; list-style: none; column-gap: 28px; }
.ia-text .ia-word { break-inside: avoid; display: flex; align-items: baseline; gap: 8px; padding: 4px 0; font: 600 20px var(--font); animation: ia-in .45s ease-out both; }
.ia-text small { font: 400 15px var(--mono); color: var(--gray); }
.ia-tag_cloud { display: flex; flex-wrap: wrap; gap: 6px 18px; align-items: baseline; justify-content: center; }
.ia-tag_cloud .ia-word { display: inline-flex; font-size: 18px; color: var(--blue); }
.ia-tag_cloud .ia-word small { display: none; }
.ia-del { opacity: 0; border: none; background: transparent; color: var(--red); cursor: pointer; font-size: 14px; padding: 0 4px; }
.ia-word:hover .ia-del, .ia-del:focus-visible { opacity: 1; }
@keyframes ia-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .ia-text .ia-word { animation: none; } .ia-bar > span { transition: none; } }
/* ranges */
.ia-range { display: flex; align-items: flex-end; gap: 3px; height: 220px; border-bottom: 2px solid var(--ink); }
.ia-col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; height: 100%; }
.ia-col span { width: 100%; background: var(--yellow); border-radius: 4px 4px 0 0; min-height: 0; }   /* no transition: the engine draws every frame (#51) */
.ia-col small { font: 400 12px var(--mono); color: var(--gray); }
.ia-scale { display: flex; justify-content: space-between; font: 600 14px var(--mono); }
.ia-scale.ia-scale-all { gap: 3px; }
.ia-scale.ia-scale-all span { flex: 1; text-align: center; }
.ia-part { border-top: 1px dashed var(--line); padding-top: 10px; }
.ia-part-head .ia-desc { font-size: 17px; }

/* ── the audience's phone ──────────────────────────────────────────────── */
#audience-view {
  position: fixed; inset: 0; z-index: 92; background: var(--backdrop); color: #fff;
  display: flex; flex-direction: column; overflow-y: auto;
}
.aud-head { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-bottom: 1px solid rgba(255,255,255,.10); font: 600 13px var(--font); color: #C9CBD1; }
.aud-brand { flex: 1; }
#aud-main { flex: 1; display: flex; flex-direction: column; padding: 16px; }
/* audience.html (feature options, risk 8): the PIN form when no code brought one */
body.audience-page { background: var(--backdrop); color: #fff; }
.aud-join { max-width: 26rem; margin: 18vh auto 0; padding: 0 18px; display: flex; flex-direction: column; gap: 12px; font: 400 16px var(--font); }
.aud-join h1 { margin: 0 0 6px; font: 700 26px var(--font); }
.aud-join input { font: 600 28px var(--mono); letter-spacing: .15em; padding: 10px 12px; border: 2px solid #9CA0A8; background: transparent; color: inherit; }
.aud-join .ghost-btn { align-self: flex-start; font-size: 17px; padding: 10px 20px; }
body.mode-audience .aud-join { display: none; }
.aud-wait { margin: auto; font: 600 20px var(--font); color: #C9CBD1; text-align: center; animation: aud-pulse 2.4s ease-in-out infinite; }
@keyframes aud-pulse { 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) { .aud-wait { animation: none; } }
.aud-card { background: var(--paper); color: var(--ink); border-radius: 16px; padding: 18px; display: flex; flex-direction: column; gap: 14px; }
.aud-card h2 { margin: 0; font: 700 14px var(--font); color: var(--gray); text-transform: uppercase; letter-spacing: .04em; }
.aud-card .ia-desc { font-size: 20px; }
.aud-options { display: flex; flex-direction: column; gap: 8px; }
.aud-option {
  text-align: left; font: 600 18px var(--font); padding: 14px 16px; border-radius: 12px; cursor: pointer;
  border: 2px solid #CDD1D6; background: #fff; color: var(--ink);
}
.aud-option[aria-checked="true"] { border-color: var(--blue); background: #EAF1FF; }
.aud-option:disabled { opacity: .6; }
.aud-hint { margin: 0; font: 400 13px var(--font); color: var(--gray); }
.aud-text { font: 400 18px var(--font); padding: 12px; border-radius: 12px; border: 2px solid #CDD1D6; width: 100%; min-height: 3em; }
.aud-range { display: flex; flex-direction: column; gap: 6px; }
.aud-range input { width: 100%; accent-color: var(--blue); }
.aud-range output { font: 700 28px var(--mono); text-align: center; }
.aud-scale { display: flex; justify-content: space-between; font: 600 13px var(--mono); color: var(--gray); }
.aud-part { border-top: 1px dashed var(--line); padding-top: 12px; display: flex; flex-direction: column; gap: 10px; }
.aud-actions { display: flex; gap: 8px; }
.aud-send { flex: 1; font: 700 18px var(--font); padding: 14px; border-radius: 12px; border: none; background: var(--yellow); color: var(--ink); cursor: pointer; }
.aud-send:disabled { opacity: .45; cursor: default; }
.aud-change { font: 600 15px var(--font); padding: 0 16px; border-radius: 12px; border: 1px solid #CDD1D6; background: #fff; cursor: pointer; }
.aud-sent { margin: 0; font: 600 14px var(--font); color: #15803D; min-height: 1.2em; }
body.mode-audience #opener, body.mode-audience #stage-wrap, body.mode-audience .chrome,
body.mode-audience #progress, body.mode-audience #talk-line, body.mode-audience #talk-warn { display: none !important; }
/* review round (#16) */
.ia-text .ia-word.ia-old { animation: none; }
.ia-del { opacity: .35; }
@media (hover: none) { .ia-del { opacity: 1; } }
.ia-part-head { display: flex; gap: 12px; align-items: baseline; justify-content: space-between; }
.ia-part-vis { font: 600 12px var(--font); padding: 4px 6px; border-radius: 7px; border: 1px solid #CDD1D6; }
.aud-live { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/* ── #26: a fixed counter, and the preview ─────────────────────────────── */
.ia-stage { overflow: hidden; }
.ia-stage-body { flex: 1; min-height: 120px; overflow-y: auto; display: flex; flex-direction: column; gap: 14px; }
/* the counter sits centred at the bottom of the element, whatever grows above */
.ia-stage > .ia-counter { flex: none; text-align: center; padding: 8px 0 0; border-top: 1px solid var(--line); }
.ia-controls { margin-top: 0; }
.ia-preview-btn { font-size: 12px; padding: 6px 9px; }
.ia-card { position: relative; }
.ia-phone {
  background: var(--backdrop); border-radius: 28px; padding: 16px 12px; border: 6px solid #2A2D33;
  min-height: 420px;
}
/* short screens: the stage scrolls as a whole rather than squeezing the
   results to nothing; narrow ones stack the preview's two columns */
@media (max-height: 620px) { .ia-stage { overflow-y: auto; } .ia-stage-body { flex: none; } }
.ia-preview-mode { margin: 0; font: 400 13px var(--font); color: var(--gray); }
.ia-preview-results { display: flex; flex-direction: column; gap: 12px; }
.ia-preview-results .ia-counter { text-align: center; }
/* #34: long words wrap, bidi text stays inside its own entry, and the tally */
.ia-text .ia-word { min-width: 0; overflow-wrap: anywhere; unicode-bidi: isolate; }
.ia-text .ia-word > span:first-child { min-width: 0; overflow-wrap: anywhere; }
.ia-counter #ia-counter, .ia-counter .ia-tally { display: block; }
.ia-tally { color: var(--gray); font: 400 12.5px var(--mono); }
.ia-tally:empty { display: none; }

/* ── #39: three views — the overview, one interaction to play, its preview ── */
.ia-view { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.ia-view[hidden] { display: none; }
.ia-card > header { min-height: 58px; }
.ia-back { font: 700 14px var(--font); padding: 7px 12px 7px 9px; border-radius: 9px; border: 1px solid var(--line); background: transparent; color: var(--ink); cursor: pointer; white-space: nowrap; }
.ia-back:hover { border-color: var(--ink); }
.ia-back[hidden] { display: none; }
.ia-card h2#ia-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ia-aud-status { font: 600 13px var(--mono); color: var(--gray); white-space: nowrap; }
.ia-aud-status[hidden] { display: none; }
#ia-play .ia-body { flex: 1; min-height: 0; }
/* the overview: one row per interaction */
#ia-overview .ia-list { flex: 1; overflow-y: auto; padding: 16px 22px; gap: 8px; }
/* #102: Create or Change, for the slide on screen */
/* this presentation's interactions on or off (feature options, risk 4) */
#ia-overview .ia-on-row { padding: 14px 22px 0; }
#ia-overview .ia-switch { display: flex; align-items: center; gap: 10px; font: 700 15px var(--font); cursor: pointer; }
#ia-overview .ia-switch input { width: 20px; height: 20px; margin: 0; accent-color: var(--blue); cursor: pointer; flex: none; }
#ia-overview .ia-switch input:disabled + span { opacity: .55; }
#ia-overview .ia-on-hint { margin: 6px 0 0 30px; font: 400 14px/1.45 var(--font); color: var(--gray); }
#ia-overview .ia-on-hint:empty { display: none; }
#ia-overview .ia-edit-bar { padding: 14px 22px 0; }
#ia-overview .ia-edit-bar .ia-btn { font-size: 15px; padding: 9px 16px; }

/* #102: the editor of the interactions of a slide */
#ia-edit .ia-edit-form { flex: 1; min-height: 0; overflow-y: auto; padding: 16px 22px; display: flex; flex-direction: column; gap: 14px; }
#ia-edit > .ia-check-result { margin: 0 22px 10px; max-height: 30vh; overflow-y: auto; }
#ia-edit > .ia-controls { padding: 10px 22px 14px; }
.ia-edit-note { flex: 1 1 220px; font: 400 12.5px/1.4 var(--font); color: var(--gray); }
.ia-ed-card { border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; }
.ia-ed-el { border: 1px solid var(--line); border-left: 4px solid var(--blue); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; }
.ia-ed-part { border-left-color: var(--gray); }
.ia-ed-els, .ia-ed-parts { display: flex; flex-direction: column; gap: 10px; }
.ia-ed-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ia-ed-head h3 { margin: 0; flex: 1; min-width: 0; font: 700 16px var(--font); overflow-wrap: anywhere; }
.ia-ed-head h4 { margin: 0; flex: 1 0 auto; font: 700 14px var(--font); white-space: nowrap; }
@media (max-width: 520px) { .ia-ed-head h3 { flex-basis: 100%; } }
.ia-ed-head .ia-ed-type { font: 600 13px var(--font); padding: 5px 8px; border-radius: 8px; border: 1px solid #CDD1D6; background: transparent; color: inherit; }
.ia-btn.ia-ed-icon { padding: 5px 7px; }
.ia-ed-body { display: flex; flex-direction: column; gap: 8px; }
.ia-ed-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 8px 12px; align-items: start; }
.ia-ed-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; font: 600 12.5px var(--font); }
.ia-ed-field :is(input:not([type="checkbox"]), select, textarea) { font: 400 14px var(--font); padding: 6px 8px; border: 1px solid #CDD1D6; border-radius: 8px; background: transparent; color: inherit; min-width: 0; }
.ia-ed-field textarea { resize: vertical; line-height: 1.4; }
/* an example, not a value: lighter and slanted (UX review: UX-29) */
.ia-ed-field :is(input, textarea)::placeholder { color: #8A8F98; font-style: italic; opacity: 1; }
.ia-ed-field :is(input, select, textarea):focus-visible, .ia-ed-head .ia-ed-type:focus-visible { outline: 3px solid var(--blue); outline-offset: 1px; }
.ia-ed-field [aria-invalid="true"] { border-color: var(--red); box-shadow: 0 0 0 1px var(--red); }
.ia-ed-field input:disabled { opacity: .45; }
@media (min-width: 640px) { .ia-ed-span { grid-column: span 2; } }
.ia-ed-check { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px 8px; font-weight: 600; }
.ia-ed-check small { flex-basis: 100%; }
.ia-ed-any { display: inline-flex; align-items: center; gap: 6px; font-weight: 400; }
.ia-ed-hint { font: 400 12px var(--font); color: var(--gray); }
.ia-ed-msg { margin: 0; font: 600 12px/1.35 var(--font); color: #B42318; }
.ia-ed-add { display: flex; }
.ia-ed-add-it { justify-content: center; }
.ia-ed-none { margin: 8px auto; }
#ia-overview > .ia-check-result { margin: 0 22px 10px; }
#ia-overview > .ia-controls { padding: 10px 22px 14px; }
.ia-row { display: grid; grid-template-columns: 1fr auto auto auto auto; gap: 10px; align-items: center; padding: 10px 14px; border: 1px solid var(--line); border-radius: 12px; }
.ia-row.here { border-color: var(--blue); }
.ia-row.active { box-shadow: inset 4px 0 0 var(--ink); }
.ia-row.live { box-shadow: inset 4px 0 0 #16A34A; }
.ia-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* the block starts the interaction (#52): a button that looks like the row */
.ia-row-main { min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; text-align: left; font: inherit; color: inherit; background: transparent; border: 0; border-radius: 8px; padding: 6px 8px; margin: -6px -8px; cursor: pointer; }
.ia-row-main:hover { background: rgba(37, 99, 235, .07); }
.ia-row-main:focus-visible { outline: 3px solid #2563EB; outline-offset: 2px; }
.ia-row.ia-off { border-style: dashed; }
.ia-row.ia-off .ia-row-main strong { color: var(--gray); }
.ia-hide-btn, .ia-jump-btn, .ia-row-edit-btn { font-size: 12px; padding: 6px 9px; }
.ia-aud-count { margin: 0; padding: 4px 22px 0; text-align: center; font: 600 14px var(--font); color: var(--gray); }
.ia-aud-count.on { color: var(--ink); }
.ia-url { margin: 0; font: 600 14px/1.3 var(--mono); overflow-wrap: anywhere; text-align: center; }
.ia-row-main strong { font: 700 17px var(--font); overflow-wrap: anywhere; }
.ia-row-meta { flex-basis: 100%; font: 400 13px var(--font); color: var(--gray); }
/* live: a green dot (the row, and the controls of the running interaction) */
.ia-live-dot { display: inline-block; width: 11px; height: 11px; border-radius: 50%; background: #16A34A; box-shadow: 0 0 0 0 rgba(22,163,74,.55); animation: ia-pulse 1.8s ease-out infinite; }
.ia-live-dot[hidden] { display: none; }
.ia-live { display: inline-flex; align-items: center; gap: 7px; font: 700 13px var(--font); color: #15803D; padding: 0 6px; }
.ia-live[hidden] { display: none; }
@keyframes ia-pulse { 70% { box-shadow: 0 0 0 7px rgba(22,163,74,0); } 100% { box-shadow: 0 0 0 0 rgba(22,163,74,0); } }
@media (prefers-reduced-motion: reduce) { .ia-live-dot { animation: none; } }
.ia-idle-note { margin: 0; font: 400 15px/1.45 var(--font); color: var(--gray); }
/* the preview: now a view of its own, in two tabs */
.ia-preview-head { display: flex; align-items: center; gap: 16px; padding: 12px 22px 0; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.ia-tabs { display: flex; gap: 4px; }
.ia-tabs [role="tab"] { font: 700 14px var(--font); padding: 10px 16px; border: 1px solid transparent; border-bottom: none; border-radius: 10px 10px 0 0; background: transparent; color: var(--gray); cursor: pointer; margin-bottom: -1px; }
.ia-tabs [role="tab"][aria-selected="true"] { color: var(--ink); border-color: var(--line); background: var(--paper); }
.ia-tabpanel { flex: 1; min-height: 0; overflow-y: auto; padding: 16px 22px; display: flex; flex-direction: column; gap: 12px; }
.ia-tabpanel[hidden] { display: none; }
/* the preview's phone is a screen of its own: it fills the panel up to a
   phone's height, and what does not fit scrolls inside it, as on a phone */
#ia-preview-phone-panel .ia-phone {
  width: min(400px, 100%); align-self: center;
  flex: 1 1 0; min-height: 360px; max-height: 780px;
  overflow-y: auto; overscroll-behavior: contain;
}
.ia-preview-note { margin: 0; font: 400 13px var(--font); color: var(--gray); }
#ia-preview > .ia-controls { padding: 10px 22px 14px; justify-content: center; }
/* white on the brand blue is 3.4:1 — too little for button text: a darker blue */
.ia-btn.ia-primary { background: #2563EB; border-color: #2563EB; }
/* narrow screens: the play view stacks the audience above the stage */
@media (max-width: 760px) {
  .ia-row { grid-template-columns: auto auto auto auto 1fr; }
  .ia-row .ia-row-main { grid-column: 1 / -1; }
  .ia-card > header { flex-wrap: wrap; gap: 8px 12px; padding: 10px 14px; }
  .ia-aud-status { order: 5; flex-basis: 100%; white-space: normal; }
  #ia-play .ia-body { grid-template-columns: 1fr; grid-template-rows: auto 1fr; overflow-y: auto; }
  #ia-play .ia-side { border-right: 0; border-bottom: 1px solid var(--line); overflow: visible; }
  #ia-play .ia-qr svg { width: 128px; height: 128px; }
  #ia-play .ia-stage { padding: 14px 16px; overflow: visible; }
  #ia-overview .ia-list, .ia-tabpanel { padding: 12px 14px; }
  #ia-overview > .ia-controls, #ia-preview > .ia-controls { padding: 10px 14px 12px; }
}

/* ── #40: the version overlay ───────────────────────────────────────────── */
#version-info {
  position: fixed; inset: 0; z-index: 88; background: rgba(8,8,10,.92);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
#version-info[hidden] { display: none; }
.ver-card { max-width: 680px; }
.ver-card h2 { font: 700 26px var(--font); }
.ver-body { padding: 16px 24px 22px; display: flex; flex-direction: column; gap: 12px; }
.ver-sub { margin: 0; font: 600 13.5px var(--font); color: var(--gray); }
.ver-notes { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 7px; font: 400 15px/1.5 var(--font); }
.ver-earlier summary { cursor: pointer; font: 700 14px var(--font); padding: 6px 0; }
.ver-earlier section { border-top: 1px solid var(--line); padding: 12px 0 4px; display: flex; flex-direction: column; gap: 6px; }
.ver-earlier h3 { margin: 0; font: 700 16px var(--font); }
.ver-earlier .ver-notes { font-size: 14px; }
.ver-foot { margin: 4px 0 0; font: 400 13px var(--font); }
.ver-foot a { color: #1F5FD1; }                  /* 4.5:1 on the light card */
html[data-theme="dark"] .ver-foot a { color: #8DB6FF; }

/* ── #42: the language of the phones, in the play view ─────────────────── */
.ia-aud-lang { display: flex; flex-direction: column; align-items: center; gap: 4px; font: 600 12px var(--font); color: var(--gray); }
.ia-aud-lang select { font: 600 13px var(--font); padding: 5px 8px; border-radius: 8px; border: 1px solid #CDD1D6; background: #fff; color: #222; }
html[data-theme="dark"] .ia-aud-lang select { background: #22262C; color: #E9EAEE; border-color: #3A3F47; }

/* ── #46: results that hold still while they animate ────────────────────── */
/* the count and the percentage have fixed widths (set from the widest final
   value), so a bar keeps its length and the numbers their x-position */
.ia-num { display: inline-flex; align-items: baseline; justify-content: flex-end; font-variant-numeric: tabular-nums; white-space: pre; }
.ia-num .ia-n { display: inline-block; min-width: var(--ia-n-w, 2ch); text-align: right; }
.ia-num .ia-pct { display: inline-block; min-width: 5ch; text-align: right; }
/* a hidden select result keeps the place of its chart (drawn empty, unseen) */
.ia-results { position: relative; }
.ia-reserve { visibility: hidden; }
.ia-results > .ia-hidden:has(+ .ia-reserve) { position: absolute; inset: 0 0 auto 0; margin: 0; }

/* ── #47: the select charts ─────────────────────────────────────────────── */
/* the engine animates the bars frame by frame: no CSS transition on top */
.ia-select .ia-bar > span { transition: none; }
.ia-chart { display: grid; grid-template-columns: minmax(260px, 520px) minmax(180px, 1fr); gap: 18px 28px; align-items: center; }
.ia-chart-svg { width: 100%; height: auto; aspect-ratio: 520 / 320; display: block; overflow: visible; }
.ia-chart-svg text { font: 700 14px var(--mono); fill: var(--ink); }
.ia-chart-in text { font-size: 13px; }          /* its colour is chosen per slice: dark on light fills */
.ia-chart-ticks text { font: 700 13px var(--font); fill: var(--gray); }
.ia-chart-grid, .ia-chart-grid path, .ia-chart-grid line { fill: none; stroke: var(--line); stroke-width: 1; }
.ia-chart-axis { stroke: var(--ink); stroke-width: 2; }
.ia-chart-line { stroke: var(--ink); stroke-width: 2.5; }
.ia-chart-area { fill: rgba(65,134,255,.22); stroke: #4186FF; stroke-width: 2.5; }
.ia-chart-point { cursor: help; stroke: var(--paper); stroke-width: 2; }
.ia-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.ia-legend-item { display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center; font: 600 17px var(--font); }
.ia-swatch { width: 22px; height: 22px; border-radius: 5px; display: grid; place-items: center; font: 700 12px var(--font); }
.ia-legend .ia-num { font: 400 16px var(--mono); white-space: nowrap; }
.ia-preview-anim { display: inline-flex; align-items: center; gap: 6px; font: 600 13px var(--font); }
.ia-preview-anim[hidden] { display: none; }
.ia-preview-anim select { font: 600 13px var(--font); padding: 6px 8px; border-radius: 9px; border: 1px solid #CDD1D6; background: #fff; color: #222; }
html[data-theme="dark"] .ia-preview-anim select { background: #22262C; color: #E9EAEE; border-color: #3A3F47; }
@media (max-width: 760px) { .ia-chart { grid-template-columns: 1fr; } }
.ia-legend { max-width: 460px; }

/* ── #51: texts appear one by one — a waiting word keeps its place, unseen;
   when it is its turn it fades in (the ia-in animation plays then) ─────── */
.ia-text .ia-word.ia-wait { opacity: 0; animation: none; }

/* ── #65: the poll's controls, its dialogs, and the audience column's width ── */
/* End: orange while elements of the poll are still to come (white on
   #C2410C is 5.2:1), the brand yellow at its last element (ink on it). */
.ia-btn.ia-warn { background: #C2410C; border-color: #C2410C; color: #fff; }
.ia-btn.ia-warn:hover { border-color: #7C2D12; }
.ia-btn.ia-highlight { background: var(--yellow); border-color: #D9A800; color: #111; }
.ia-btn.ia-highlight:hover { border-color: #111; }
/* a dialog over the card, never a browser dialog (a projected screen would freeze) */
.ia-dialog-shade {
  position: absolute; inset: 0; z-index: 5; border-radius: 18px; padding: 18px;
  background: rgba(8,8,10,.55); display: flex; align-items: center; justify-content: center;
}
.ia-dialog {
  background: var(--paper); color: var(--ink); border-radius: 14px; padding: 18px 20px;
  width: min(580px, 100%); max-height: 100%; overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0,0,0,.45); display: flex; flex-direction: column; gap: 8px;
}
.ia-dialog h3 { margin: 0 0 6px; font: 700 18px var(--font); }
.ia-choice {
  display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 3px 10px; text-align: left;
  font: 600 15px var(--font); padding: 10px 14px; border-radius: 10px; cursor: pointer;
  border: 1px solid #CDD1D6; background: #fff; color: #222;
}
.ia-choice:hover { border-color: var(--ink); }
.ia-choice.ia-danger-choice:hover { border-color: var(--red); }
.ia-choice:focus-visible { outline: 3px solid #2563EB; outline-offset: 2px; }
.ia-choice-detail { grid-column: 2; font: 400 13px/1.35 var(--font); color: var(--gray); overflow-wrap: anywhere; }
/* the third row stands apart: keeping everything is not one of the resets */
.ia-choice.ia-keep-choice { margin-top: 14px; }
.ia-help { width: min(720px, 100%); }
.ia-help-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.ia-help-head h3 { margin: 0; }
.ia-help-list { display: grid; grid-template-columns: auto 1fr; gap: 10px 16px; margin: 6px 0 0; }
.ia-help-list dt { display: flex; align-items: center; gap: 8px; font: 700 14px var(--font); }
.ia-help-list dd { margin: 0; font: 400 14px/1.45 var(--font); color: var(--ink); }
/* the column's three widths, at its foot like the stage's controls. The
   audience box never shrinks below its content: on a short screen the
   column scrolls, and the bar stays at the foot over what scrolls under it */
/* scroll-padding: what the keyboard or a script scrolls to lands above the bar, not under it */
.ia-side { container-type: inline-size; padding-bottom: 0; scroll-padding-bottom: 80px; }
.ia-side .ia-audience { flex: 1 0 auto; }
.ia-side-size {
  display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; flex: none;
  position: sticky; bottom: 0; z-index: 1; margin: auto -18px 0; padding: 8px 18px 20px;
  border-top: 1px solid var(--line); background: var(--paper);
}
.ia-side-size .ia-btn { padding: 6px 9px; font-size: 12px; }
.ia-side-size .ia-btn[aria-checked="true"] { background: var(--ink); border-color: var(--ink); color: var(--paper); }
/* reset: the code takes 90 % of the column's width */
#ia-play .ia-body[data-size="reset"] .ia-qr { width: 90%; }
#ia-play .ia-body[data-size="reset"] .ia-qr svg { width: 100%; height: auto; aspect-ratio: 1; }
/* large: half of the panel; full: all of it, without the stage */
#ia-play .ia-body[data-size="large"] { grid-template-columns: 1fr 1fr; }
#ia-play .ia-body[data-size="full"] { grid-template-columns: 1fr; }
#ia-play .ia-body[data-size="full"] .ia-stage { display: none; }
#ia-play .ia-body[data-size="full"] .ia-side { border-right: 0; }
/* …and the content stretched to the column, keeping its proportions: the
   code is a square as large as the space left over (an SVG with a viewBox
   keeps its aspect ratio inside any box), the PIN and the address grow with
   the column's width */
#ia-play .ia-body:is([data-size="large"], [data-size="full"]) .ia-audience { justify-content: center; }
#ia-play .ia-body:is([data-size="large"], [data-size="full"]) .ia-qr { flex: 1 1 0; min-height: 140px; width: 100%; display: flex; justify-content: center; }
#ia-play .ia-body:is([data-size="large"], [data-size="full"]) .ia-qr svg { width: 100%; height: 100%; }
#ia-play .ia-body:is([data-size="large"], [data-size="full"]) .ia-pin { font-size: clamp(34px, 6cqi, 120px); }
#ia-play .ia-body:is([data-size="large"], [data-size="full"]) .ia-url { font-size: clamp(14px, 2.6cqi, 44px); }
#ia-play .ia-body:is([data-size="large"], [data-size="full"]) .ia-count { font-size: clamp(14px, 2cqi, 30px); }
/* narrow screens stack the column above the stage: one width only */
@media (max-width: 760px) {
  .ia-side-size { display: none; }
  .ia-help-list { grid-template-columns: 1fr; gap: 2px; }
  .ia-help-list dd { margin-bottom: 8px; }
  #ia-play .ia-body[data-size] { grid-template-columns: 1fr; }
  #ia-play .ia-body[data-size="full"] .ia-stage { display: flex; }
  #ia-play .ia-body[data-size] .ia-qr { width: auto; flex: none; min-height: 0; }
  #ia-play .ia-body[data-size] .ia-qr svg { width: 128px; height: 128px; }
  #ia-play .ia-body[data-size] .ia-side { overflow: visible; }
}

/* ── #67: HTML presentations ─────────────────────────────────────────────── */
/* The deck's frame takes the page canvas's place on the stage; ink, notes,
   links and the laser stay above it. */
/* its own stacking context: the frame's z-index must not lift it over the ink */
#html-layer { position: absolute; inset: 0; display: none; overflow: hidden; z-index: 0; }
body.kind-html #html-layer { display: block; }
body.kind-html #page-canvas { visibility: hidden; }
.html-box { position: absolute; inset: 0; z-index: 1; }
.html-box.loading { visibility: hidden; }
/* laid out at the fitted size and scaled for a zoom, from its top-left corner */
.html-frame { position: absolute; left: 0; top: 0; border: 0; display: block; background: #fff; transform-origin: 0 0; }
/* Over the frame, the presenter's tools take the pointer — a frame keeps its
   events to itself. With the cursor the deck is used directly: links, videos,
   anything interactive, and a page scrolls. */
#html-shield { position: absolute; inset: 0; z-index: 2; }
body.tool-cursor #html-shield { pointer-events: none; }
/* the start page: open an HTML presentation */
.html-pick { margin: -10px 0 26px; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px 10px; font: 400 15px var(--font); color: #C9CBD1; }
.html-pick .ghost-btn { cursor: pointer; position: relative; }
/* visually hidden, as .pick input: still focusable, so the keyboard reaches the pickers */
.html-pick input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.html-pick .ghost-btn:focus-within { outline: 3px solid var(--blue); outline-offset: 2px; }

/* #86: a Google Slides presentation in Google's player. The frame never
   takes the pointer, also with the cursor tool: a click into it would turn
   Google's player without ActiveStage knowing. The finished slide (its
   on-click animations revealed) is drawn on a canvas laid over the player —
   from the deck's PDF, or Google's picture until then (#89); letterboxed
   like Google's player if its shape differs. */
.gs-frame { pointer-events: none; background: #000; }
body.kind-google.tool-cursor #html-shield { pointer-events: auto; }
.gs-finished { position: absolute; left: 0; top: 0; display: block; transform-origin: 0 0; object-fit: contain; background: #fff; pointer-events: none; }
.gs-finished[hidden] { display: none; }
.gs-pick { margin-top: -18px; }
#gs-add {
  position: fixed; inset: 0; z-index: 95; background: rgba(8,8,10,.92);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
#gs-add[hidden] { display: none; }
#gs-add .trust-body { margin: 0; font: 400 15px/1.5 var(--font); }
#gs-add .gs-add-note { color: var(--gray); font-size: 14px; }
#gs-add .gs-add-error { font-weight: 700; color: #B42318; }
#gs-add input {
  width: 100%; box-sizing: border-box; padding: 10px 12px; border-radius: 8px;
  border: 1.5px solid #CDD1D6; font: 400 16px var(--font); color: inherit; background: transparent;
}
#gs-add input:focus-visible { outline: 3px solid var(--blue); outline-offset: 1px; }
#gs-add .trust-actions { margin: 6px 0 0; display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }

/* #103, #108: the length of the talk and its start, end and appendix slides */
#talk-ask {
  position: fixed; inset: 0; z-index: 95; background: rgba(8,8,10,.92);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
#talk-ask[hidden] { display: none; }
#talk-ask .trust-body { margin: 0; font: 400 15px/1.5 var(--font); }
/* each colour the text names is underlined in the line's colour (talk.js sets them) */
#talk-ask .talk-c {
  text-decoration-line: underline; text-decoration-thickness: 3px;
  text-underline-offset: 3px; text-decoration-skip-ink: none;
}
#talk-ask .talk-green { text-decoration-color: var(--talk-green); }
#talk-ask .talk-orange { text-decoration-color: var(--talk-orange); }
#talk-ask .talk-red { text-decoration-color: var(--talk-red); }
/* a row per field: its label, the field, and for a slide the button that takes the one on screen */
#talk-ask .talk-fields { display: grid; grid-template-columns: auto 9em 1fr; gap: 10px 12px; align-items: center; }
#talk-ask .talk-fields label { font: 600 14px var(--font); }
#talk-ask .talk-take { justify-self: start; }
#talk-ask input {
  width: 100%; box-sizing: border-box; padding: 10px 12px; border-radius: 8px;
  border: 1.5px solid #CDD1D6; font: 400 16px var(--font); color: inherit; background: transparent;
}
#talk-ask input:focus-visible { outline: 3px solid var(--blue); outline-offset: 1px; }
#talk-ask input[aria-invalid="true"] { border-color: #B42318; }
/* the lengths to choose from, under the length field */
#talk-ask .talk-combo { position: relative; }
#talk-minutes-list {
  position: absolute; left: 0; top: calc(100% + 4px); z-index: 2;
  width: min(330px, calc(100vw - 104px)); max-height: 264px; overflow-y: auto; box-sizing: border-box;
  padding: 8px 10px 10px; border-radius: 10px; border: 1px solid #CDD1D6;
  background: var(--paper); color: var(--ink); box-shadow: 0 10px 30px rgba(0,0,0,.35);
}
#talk-minutes-list[hidden] { display: none; }
#talk-minutes-list .talk-choice-group { display: flex; flex-wrap: wrap; gap: 6px; }
#talk-minutes-list .talk-choice-group + .talk-choice-group { margin-top: 8px; }
#talk-minutes-list .talk-choice-head { flex: 0 0 100%; font: 700 12px var(--font); letter-spacing: .04em; text-transform: uppercase; opacity: .7; }
#talk-minutes-list .talk-choice {
  min-width: 4.4em; box-sizing: border-box; padding: 7px 8px; border-radius: 7px; text-align: center;
  border: 1px solid #CDD1D6; font: 600 14px var(--font); cursor: pointer; user-select: none;
}
#talk-minutes-list .talk-choice:hover { background: var(--line); }
#talk-minutes-list .talk-choice.active { background: var(--blue); border-color: var(--blue); color: #fff; }
#talk-ask .talk-error { margin: 0; font: 700 14px/1.4 var(--font); color: #B42318; }
#talk-ask .talk-error[hidden] { display: none; }
#talk-ask .trust-actions { margin: 6px 0 0; display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }
/* …and in view, at the card's foot, however long it is (UX review: UX-13) */
#talk-ask .trust-actions { position: sticky; bottom: 0; z-index: 1; padding: 10px 0; background: var(--paper); border-top: 1px solid var(--line); }
/* #110: on or off for this presentation; off, what is set below is kept and greyed */
#talk-ask .talk-switch { display: flex; align-items: center; gap: 10px; font: 700 15px var(--font); cursor: pointer; }
#talk-ask .talk-switch input { width: 20px; height: 20px; margin: 0; padding: 0; accent-color: var(--blue); cursor: pointer; flex: none; }
#talk-settings { margin: 0; padding: 0; border: 0; min-width: 0; display: flex; flex-direction: column; gap: 14px; }
#talk-settings:disabled { opacity: .5; }
/* #110: the warnings — a slider each, what it means in minutes beside it, and its ✕ */
#talk-ask .talk-warnings h3 { margin: 0 0 4px; font: 700 14px var(--font); }
#talk-ask .talk-warnings p { margin: 0 0 8px; font: 400 14px/1.45 var(--font); }
#talk-warn-list { list-style: none; margin: 0 0 8px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
#talk-warn-list:empty { display: none; }
#talk-ask .talk-warn-row { display: grid; grid-template-columns: minmax(120px, 1fr) minmax(0, 1.4fr) auto auto; gap: 8px 12px; align-items: center; }
#talk-ask .talk-warn-row input[type="range"] { width: 100%; padding: 0; margin: 0; border: 0; accent-color: rgb(234, 138, 12); }
#talk-ask .talk-warn-at { font: 600 14px var(--font); font-variant-numeric: tabular-nums; }
#talk-ask .talk-warn-remove { padding: 4px 10px; }
#talk-ask p.talk-warn-actions { margin: 0; display: flex; gap: 10px; flex-wrap: wrap; }
/* 2026-10-21: a warning's colour — its button shows it; below the row, the
   colours used before, the palette, and any other colour */
#talk-ask .talk-warn-colour { padding: 5px 8px; display: inline-flex; align-items: center; }
#talk-ask .talk-swatch { display: block; width: 20px; height: 20px; border-radius: 4px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.35); }
#talk-ask .talk-colours {
  grid-column: 1 / -1; grid-row: 2; display: flex; flex-direction: column; gap: 6px;
  padding: 8px 10px 10px; border-radius: 10px; border: 1px solid #CDD1D6; background: var(--paper);
}
#talk-ask .talk-colours .talk-choice-head { font: 700 12px var(--font); letter-spacing: .04em; text-transform: uppercase; opacity: .7; }
#talk-ask .talk-swatches { display: flex; flex-wrap: wrap; gap: 8px; }
#talk-ask .talk-colour {
  width: 32px; height: 32px; padding: 0; border: 0; border-radius: 6px; cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.35);
}
#talk-ask .talk-colour[aria-pressed="true"] { outline: 3px solid var(--ink); outline-offset: 2px; }
#talk-ask .talk-colour:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }
#talk-ask .talk-colour-other { align-self: flex-start; display: inline-flex; align-items: center; gap: 8px; font: 600 14px var(--font); cursor: pointer; }
#talk-ask .talk-colour-other input[type="color"] { width: 44px; height: 32px; padding: 2px; border-radius: 6px; cursor: pointer; }
/* 2026-10-21: how the messages will look — on a ruled white "slide", the
   notices stacked in the lower-right corner, the line with its dots below */
#talk-preview { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
#talk-preview[hidden] { display: none; }
#talk-ask .talk-preview-stage {
  position: relative; min-height: 110px; padding: 14px 14px 26px; border-radius: 6px; overflow: hidden;
  border: 1px solid #CDD1D6; background: repeating-linear-gradient(180deg, #FFFFFF 0 22px, #E3E6EA 22px 24px);
  display: flex; align-items: flex-end; justify-content: flex-end;
}
#talk-preview-notices { display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }
#talk-ask #talk-preview-none { position: absolute; inset: 0; margin: 0; display: grid; place-items: center; font: 600 14px var(--font); color: #4A4E55; }
#talk-ask #talk-preview-none[hidden] { display: none; }
#talk-preview-line { position: absolute; left: 0; right: 0; bottom: 3px; height: 3px; background: rgba(0,0,0,.15); }
#talk-preview-bar { display: block; height: 100%; width: 0; background: rgb(22, 163, 74); }
/* …and the slide line below it, on the edge, in the colour picked below */
#talk-preview-slides { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: rgba(0,0,0,.08); }
#talk-preview-slide-bar { display: block; height: 100%; width: 0; background: var(--slide-line, var(--yellow)); }
/* 2026-10-21: the slide ("page") line's colour — outside the switched part,
   as it is the browser's, not the presentation's */
#talk-ask .talk-slide-line h3 { margin: 0 0 4px; font: 700 14px var(--font); }
#talk-ask .talk-slide-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px 12px; align-items: center; }
#talk-ask .talk-slide-row p { margin: 0; font: 400 14px/1.45 var(--font); }
#talk-ask p.talk-preview-note { margin: 0; font: 400 13px/1.45 var(--font); }
@media (max-width: 520px) {
  #talk-ask .talk-fields { grid-template-columns: 9em 1fr; gap: 6px 10px; }
  #talk-ask .talk-fields label { grid-column: 1 / -1; margin-top: 6px; }
  #talk-ask .talk-warn-row { grid-template-columns: 1fr auto auto; gap: 2px 10px; }
  #talk-ask .talk-warn-at { grid-column: 1; grid-row: 2; }
  #talk-ask .talk-warn-colour { grid-column: 2; grid-row: 1 / 3; }
  #talk-ask .talk-warn-remove { grid-column: 3; grid-row: 1 / 3; }
  #talk-ask .talk-colours { grid-row: 3; margin-top: 6px; }
}

/* #67 review: the question before a deck runs for the first time */
#html-trust {
  position: fixed; inset: 0; z-index: 95; background: rgba(8,8,10,.92);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
#html-trust[hidden] { display: none; }
#html-trust .trust-body { margin: 0; font: 400 15px/1.5 var(--font); }
#html-trust .trust-actions { margin: 6px 0 0; display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }
#html-trust .trust-replace { font-weight: 700; }

/* #100: Forget all asks first */
#forget-ask {
  position: fixed; inset: 0; z-index: 95; background: rgba(8,8,10,.92);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
#forget-ask[hidden] { display: none; }
/* F-04: two screens */
#screens-ask { position: fixed; inset: 0; z-index: 95; background: rgba(8,8,10,.92); display: flex; align-items: center; justify-content: center; padding: 24px; }
#screens-ask[hidden] { display: none; }
#screens-ask .trust-body { margin: 0 0 10px; font: 400 15px/1.5 var(--font); }
#screens-ask .screens-pick { margin: 0 0 8px; display: flex; gap: 10px; align-items: center; font: 600 15px var(--font); }
#screens-ask .screens-pick label { min-width: 9em; }
#screens-ask select { font: 400 15px var(--font); padding: 4px 8px; }
#screens-ask .trust-actions { margin: 10px 0 0; display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }
#forget-ask .trust-body { margin: 0; font: 400 15px/1.5 var(--font); }
#forget-ask .trust-actions { margin: 6px 0 0; display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }

/* Ctrl + drag pans a zoomed slide (2026-10-26): a hand while Ctrl is held,
   a closed one while dragging; over an HTML deck the shield takes the press
   from the frame. */
body.pan-ready #stage-wrap, body.pan-ready #stage-wrap * { cursor: grab !important; }
body.panning, body.panning * { cursor: grabbing !important; }
body.pan-ready #html-shield { pointer-events: auto; }
/* A pinch zooms the slide, not the page (2026-10-26): over the stage the
   browser's own pinch zoom is off; a finger may still scroll a web page in
   an HTML deck. */
body:not(.no-doc) #stage-wrap { touch-action: pan-x pan-y; }
/* Under a drawing tool or the laser a finger or a pen draws or points on the
   slide (feature options, risk 10): the browser neither scrolls nor zooms
   the page under it. */
body:is(.tool-pen, .tool-marker, .tool-eraser, .tool-text, .tool-laser) #stage-wrap { touch-action: none; }

/* ── F-06: the pre-flight check ─────────────────────────────────────────── */
#preflight { position: fixed; inset: 0; z-index: 90; background: rgba(8,8,10,.92); display: flex; align-items: center; justify-content: center; padding: 24px; }
#preflight[hidden] { display: none; }
#preflight .feat-card { max-height: calc(100vh - 48px); overflow: auto; }
.pf-summary { margin: 0; font: 700 17px var(--font); }
.pf-summary.pf-ok { color: #15803D; }
.pf-summary.pf-warn { color: #B45309; }
.pf-summary.pf-bad { color: #C62828; }
html[data-theme="dark"] .pf-summary.pf-ok { color: #4ADE80; }
html[data-theme="dark"] .pf-summary.pf-warn { color: #FBBF24; }
html[data-theme="dark"] .pf-summary.pf-bad { color: #F87171; }
.pf-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.pf-row { display: grid; grid-template-columns: 12px 1fr; gap: 12px; align-items: start; }
.pf-row p { margin: 2px 0 0; font: 400 14.5px/1.45 var(--font); }
.pf-row p:empty { display: none; }
.pf-label { font: 700 15px var(--font); }
.pf-state { margin-left: 6px; font: 600 12px var(--font); letter-spacing: .04em; text-transform: uppercase; color: var(--gray); }
.pf-fix { color: var(--gray); }
.pf-fix::before { content: "→ "; }
.pf-dot { width: 12px; height: 12px; margin-top: 4px; border-radius: 50%; background: var(--gray); }
.pf-ok .pf-dot { background: #16A34A; }
.pf-warn .pf-dot { background: #F59E0B; }
.pf-bad .pf-dot { background: var(--red); }
.pf-info .pf-dot { background: var(--blue); }
.pf-run .pf-dot { animation: pf-pulse .8s ease-in-out infinite alternate; }
@keyframes pf-pulse { to { opacity: .25; } }
@media (prefers-reduced-motion: reduce) { .pf-run .pf-dot { animation: none; } }
.pf-note { margin: 0; font: 400 13px/1.45 var(--font); color: var(--gray); }
.pf-actions { margin: 0; display: flex; justify-content: flex-end; gap: 10px; }

/* ── F-08: the audience's questions ─────────────────────────────────────── */
#ia-overview .ia-edit-bar { display: flex; flex-wrap: wrap; gap: 8px; }
#ia-qa .ia-switch { display: flex; align-items: center; gap: 10px; font: 700 15px var(--font); cursor: pointer; }
#ia-qa .ia-switch input { width: 20px; height: 20px; margin: 0; accent-color: var(--blue); cursor: pointer; flex: none; }
.ia-qa-main { min-height: 0; overflow-y: auto; padding: 16px 20px; display: flex; flex-direction: column; gap: 12px; }
.ia-qa-switches { display: flex; flex-direction: column; gap: 8px; }
.ia-qa-waiting { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; }
.ia-qa-waiting:empty { display: none; }
.ia-qa-note { margin: 0; flex: 1 1 260px; font: 600 14px var(--font); color: #B45309; }
.ia-qa-waiting .ia-qa-list { flex-basis: 100%; }
.ia-qa-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.ia-qa-item { display: grid; grid-template-columns: auto 1fr auto; gap: 8px 12px; align-items: center; padding: 10px 14px; border: 1px solid var(--line); border-radius: 12px; }
.ia-qa-item.ia-qa-pending { border-color: #F59E0B; }
.ia-qa-item.ia-qa-onscreen { border-color: var(--blue); box-shadow: 0 0 0 2px var(--blue) inset; }
.ia-qa-item.ia-qa-answered { opacity: .7; }
.ia-qa-votes { font: 700 16px var(--mono); min-width: 3.2em; color: var(--gray); }
.ia-qa-text { margin: 0; font: 600 18px/1.35 var(--font); overflow-wrap: anywhere; }
.ia-qa-acts { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.ia-qa-empty { font: 400 15px/1.45 var(--font); color: var(--gray); padding: 6px 2px; }
.ia-qa-done summary { cursor: pointer; font: 700 14px var(--font); padding: 4px 0; }
.ia-qa-done[hidden] { display: none; }
@media (max-width: 700px) {
  .ia-qa-item { grid-template-columns: auto 1fr; }
  .ia-qa-acts { grid-column: 1 / -1; justify-content: flex-start; }
}

/* the question on the screen: over the slide, under the laser */
.qa-shown {
  position: fixed; left: 50%; top: 5vh; transform: translateX(-50%); z-index: 55;
  width: max-content; max-width: min(84vw, 1200px); padding: 18px 64px 20px 28px; border-radius: 16px;
  background: rgba(17,17,19,.94); color: #fff; border-left: 8px solid var(--yellow); box-shadow: 0 12px 40px rgba(0,0,0,.45);
}
.qa-shown[hidden], body.mode-audience .qa-shown { display: none; }
.qa-shown-label { margin: 0 0 6px; font: 700 13px var(--font); letter-spacing: .06em; text-transform: uppercase; color: var(--yellow); }
.qa-shown-text { margin: 0; font: 700 clamp(22px, 3.4vw, 44px)/1.25 var(--font); overflow-wrap: anywhere; }
.qa-shown-votes { margin: 8px 0 0; font: 600 16px var(--font); color: #C9CBD1; }
.qa-shown-votes:empty { display: none; }
#qa-shown-close { position: absolute; top: 10px; right: 10px; width: 40px; height: 40px; border-radius: 50%; border: 0; background: rgba(255,255,255,.12); color: #fff; font: 600 18px var(--font); cursor: pointer; }
#qa-shown-close:hover { background: rgba(255,255,255,.22); }
#qa-shown-close:focus-visible { outline: 3px solid #73B5FF; outline-offset: 2px; }

/* the phone: ask, and upvote the others' */
.aud-qa { margin: 0 16px 16px; background: var(--paper); color: var(--ink); border-radius: 16px; padding: 18px; display: flex; flex-direction: column; gap: 14px; }
.aud-qa[hidden] { display: none; }
.aud-qa h2 { margin: 0; font: 700 14px var(--font); color: var(--gray); text-transform: uppercase; letter-spacing: .04em; }
.aud-ask { display: flex; flex-direction: column; gap: 8px; }
#aud-ask-text { font: 400 18px var(--font); padding: 12px; border-radius: 12px; border: 2px solid #CDD1D6; width: 100%; min-height: 3em; }
#aud-ask-send { font: 700 18px var(--font); padding: 14px; border-radius: 12px; border: none; background: var(--yellow); color: var(--ink); cursor: pointer; }
#aud-ask-send:disabled { opacity: .45; cursor: default; }
#aud-ask-status { margin: 0; font: 600 14px var(--font); color: #15803D; min-height: 1.2em; }
.aud-qlist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.aud-qlist:empty { display: none; }
.aud-q { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; align-items: center; padding: 10px 12px; border: 2px solid #CDD1D6; border-radius: 12px; }
.aud-q-text { margin: 0; font: 600 16px/1.35 var(--font); overflow-wrap: anywhere; }
.aud-q-badge { grid-column: 1; font: 600 12px var(--font); color: var(--gray); }
.aud-q-badge[hidden], .aud-vote[hidden] { display: none; }
.aud-vote { grid-column: 2; grid-row: 1 / span 2; min-width: 64px; min-height: 48px; border-radius: 12px; border: 2px solid #CDD1D6; background: #fff; color: var(--ink); font: 700 16px var(--font); cursor: pointer; }
.aud-vote[aria-pressed="true"] { border-color: var(--blue); background: #EAF1FF; color: #1D4ED8; }
.aud-vote:disabled { opacity: .5; cursor: default; }
.aud-q.mine { border-style: dashed; }
.aud-q.off { opacity: .55; }
.aud-q.shown { border-color: var(--yellow); }

/* ── F-17: a live picture of a web presentation, in the pairing panel ─── */
.pair-live { border-top: 1px solid var(--line); padding-top: 10px; margin-top: 4px; }
.pair-live-text { margin: 0 0 8px; font: 400 14px/1.45 var(--font); }
.pair-live p:last-child { margin: 0; }
