/* THE DEPTH SCALE COMES FIRST. Every z-index below is a band from `layers.css`; no rule
   in this file invents a number. `@import` must precede every other rule, which is why
   it is the first line. */
@import url('./layers.css');

/* kiosk.css — THE SCREEN ITSELF: the stage, the panels, the HUD overlays and the transport bar.
 *
 * *** THIS WAS INLINE IN `kiosk.html`, AND THAT IS WHY TWO DEFECTS SURVIVED. ***
 *
 * Every rule below governs how a bedside screen is laid out, and none of it could be reached by
 * any suite in `dev/` — a test page can import `kiosk.js` and mount a real kiosk, but the CSS
 * that decides where anything lands lived in a `<style>` block on one HTML file. So a suite
 * measuring the transport bar was measuring an UNSTYLED bar: `transport_test` reported all nine
 * buttons as unreachable and it meant nothing at all, because there were no styles to push them
 * anywhere.
 *
 * `panel_fit_test.html` had already hit this and worked around it by COPYING the cell rules into
 * its own page, with a comment admitting the copy would drift. That is the tell. One file, linked
 * by the product page and by the suites that measure it, is the fix.
 *
 * Nothing in here changed in the move. */

/* NOTE what is NOT in this file: the `html,body` and `#boot` rules. Those are PAGE rules — a
   full-bleed dark background, `overflow:hidden`, the boot message — and they belong to
   `kiosk.html` alone. Moved here they would reach every suite that links this stylesheet to
   measure a bar, and paint that suite's own page black with its results unscrollable. A
   component stylesheet must be safe to link from anywhere; that is the whole point of it. */

  /* *** A PANEL SITS ON A CARD, WHICH IS THE SURFACE ITS MODULE WAS DRAWN AGAINST. ***
   *
   * THE DEFECT THIS FIXES (measured 2026-09-02, re-measured 2026-09-04 before touching it):
   * `html,body` below hardcodes a near-black `#07120d` and pairs it with `color:var(--text)`.
   * `--text` is a DARK colour in four of the five themes, so the kiosk was putting dark text on
   * near-black. 19 of 77 text elements failed WCAG in `default` at worst 1.37:1, 20 in `warm`
   * at 1.31, 22 in `forge` at 1.34 — and **worst of all 19 in `contrast`, the accessibility
   * theme, at 1.10:1.** Somebody who turns on High Contrast because they cannot read the screen
   * made it unreadable. `dusk` was the only clean theme, because it is the only one whose text
   * vars are light.
   *
   * WHY THIS FIX AND NOT THE OTHER TWO. Three were on the table.
   *
   *   1. Theme the body (`background:var(--bg)`). Restores the pair, but the kiosk's own chrome
   *      — the clock HUD, the control bar — is translucent white-on-dark with near-white text,
   *      and on a light `--bg` all of it disappears. It fixes the panels by breaking the frame.
   *   2. THIS ONE. Give the panel a `--surface` surface. `--surface` and `--text` are defined as a
   *      matched pair in every theme, and every module was written to be read on a card — it is
   *      what the composer and `modules.html` already put them on. So each module renders
   *      exactly as designed, in all five themes, with no per-module colour changes anywhere.
   *   3. Move stage text to `--on-dark`. One line, but it only reaches text that INHERITS colour;
   *      `.clock .time` sets `var(--text-strong)` itself and would stay unreadable. It treats the
   *      symptom the measurement happened to catch rather than the cause.
   *
   * AND THE FRAME STAYS DARK, which is not incidental. The gaps between panels remain the near
   * black below, so a screen somebody sleeps next to does not become a lit rectangle — the
   * panels get legible without the room getting brighter.
   *
   * NOT APPLIED TO THE HUD. `.k-clock` and `.k-mirror` are overlays on the dark frame, not
   * panels on it, and they already set their own colours against it. Scoped to `.k-stage` so
   * they are untouched. */
  /* `isolation:isolate` -- the ambient layer (below) needs `.k-stage`'s panels to explicitly
     out-rank it in z-order, and without a stacking context rooted here a positioned, z-indexed
     sibling (band 100) would paint IN FRONT of `.k-stage` (z-index:auto) regardless of which
     comes first in the markup. Rooting it at `.kiosk` -- not just `.k-stage` -- keeps the
     mirror/clock HUD (already z-indexed against this same element) in the same one scale. */
  .kiosk{position:fixed;inset:0;isolation:isolate}
  /* BURN-IN PROTECTION (2.18), off by default — see the field's own comment in kiosk.js for
   * why there are only two modes. NEITHER moves one control relative to another: `dim` only
   * darkens (nothing's position changes, so motor memory is untouched); `drift` transforms
   * the WHOLE kiosk root as a single piece, so every control keeps its exact position
   * relative to every other control — only the entire picture nudges a few pixels. The
   * `scale(1.015)` gives a ~1.5% oversize buffer so the drift never exposes an edge outside
   * the kiosk (well past the few px of actual movement at any real screen size). */
  .kiosk.burn-dim{filter:brightness(.72);transition:filter 4s ease}
  .kiosk.burn-drift{animation:nimrod-burn-drift 240s ease-in-out infinite}
  @keyframes nimrod-burn-drift{
    0%{transform:scale(1.015) translate(0,0)}
    25%{transform:scale(1.015) translate(6px,-4px)}
    50%{transform:scale(1.015) translate(-5px,5px)}
    75%{transform:scale(1.015) translate(4px,6px)}
    100%{transform:scale(1.015) translate(0,0)}
  }
  /* `overflow` is NOT set here any more. `mountModule` adds `mod-host` to whatever element a
     module is mounted into, and that class carries `overflow:auto` — the scroll floor that
     keeps a Start button below the fold reachable instead of clipped. This rule outranked it
     (two classes to one) on the SINGLE-PANEL stage, which is the full-screen case, so a module
     too tall for a full-screen panel had nowhere to go. `auto` still clips to the rounded
     corner, which is all `hidden` was doing here. */
  /* `pointer-events:auto` on the PANEL, `none` on the STAGE that contains it (below) — see the
     ambient layer rule for why. Restored here rather than left implicit: a panel with no
     stated pointer-events is auto by inheritance today, so this looks like a no-op until
     `.k-stage` turns it off. */
  .k-stage .k-mod{background:var(--surface);color:var(--text);border-radius:var(--k-panel-radius,0);pointer-events:auto}
  /* *** SPACE BETWEEN PANELS, A SCREEN SETTING (kiosk.js `panelGap`; Mike, 2026-10-02 evening: "Why are there
     always gaps between the modules? Can't they each take up a quarter?"). *** `data-panel-gap` on `.kiosk`;
     these three variables are read by the stage's padding, the grid's gap and each panel's corners below, and
     they inherit, so a dashboard drawn by `view.js` inside the kiosk gets the same.
       none   (the default, and also what an element with no setting at all gets) -- the panels meet, each one
              exactly its share of the stage: four up is four quarters. Square corners (a rounded corner with
              nothing beside it is a notch cut out of the picture), and a HAIRLINE in the theme's own `--border`
              between them, so four solid panels on one `--surface` still read as four things.
       thin   a little air: .8vmin, 8px corners, no line (the gap is the line).
       roomy  the look before this setting: 2vmin between, 2.5vmin round the edge, 14px corners.
     AGAINST none, said: the near-black frame between panels was also what kept a screen somebody sleeps next to
     from being one lit rectangle (see the panel note above). Roomy is one press, per screen. */
  [data-panel-gap="thin"]{--k-panel-gap:.8vmin;--k-panel-pad:.8vmin;--k-panel-radius:8px;--k-panel-line:0;--k-ring-offset:-3px}
  [data-panel-gap="roomy"]{--k-panel-gap:2vmin;--k-panel-pad:2.5vmin;--k-panel-radius:14px;--k-panel-line:0;--k-ring-offset:2px}
  /* The hairline: on each cell's right and bottom edges, INSIDE its box (border-box), so a cell stays exactly
     its share and neighbours share one line between them. */
  .k-stage.k-grid > .k-cell{box-sizing:border-box;border-style:solid;border-color:var(--border);
    border-width:0 var(--k-panel-line,1px) var(--k-panel-line,1px) 0}
  /* PANEL BACKGROUNDS, A HOST SETTING (kiosk.js's `panelSurface`, screen settings menu). `solid`
     above is the only behaviour before this existed and stays the default. `veil`/`clear` reuse
     `--board-veil`/`--board-halo` -- the SAME per-theme tokens board.js's own veil/clear mode
     uses, calibrated by Design against "the brightest thing that can cross behind it" for the
     seven live themes (see modules.css's own `.aboard.ab-veil` comment) -- one calibration
     serves both, rather than a second panel-specific color nobody has picked yet. `clear`'s halo
     is the identical text-shadow fallback for when there is no surface left to read against. */
  .kiosk[data-panel-surface="veil"] .k-stage .k-mod{background:var(--board-veil,rgba(27,36,41,.72))}
  .kiosk[data-panel-surface="clear"] .k-stage .k-mod{background:transparent;
    text-shadow:var(--panel-halo,var(--board-halo,0 1px 2px rgba(0,0,0,.85),0 0 6px rgba(0,0,0,.6)))}
  /* (2026-10-07) `--panel-halo` is derived by theme.js `panelHalo`: a moving theme's own `--board-halo`, exactly;
     on a still theme a halo the opposite of its words (the old dark halo smudged Nimrod light's dark words, and
     clear is the default now).
     AND WHAT A CLEAR PANEL SHOWS ON A STILL THEME IS THE THEME'S OWN PAGE COLOUR. kiosk.html paints its document
     near-black (a full-bleed screen), so a clear panel over a theme with no scene showed dark green words on black.
     The screen now wears `--bg` behind its panels while they are clear; a moving scene (drawn inside `.kiosk`, the
     scene host) and a room still cover it, so they look as before. Not on an embed: there the page around it shows. */
  .kiosk:not(.k-embed)[data-panel-surface="clear"]{background:var(--bg)}
  /* THE SAME SETTING, ONE PANEL AT A TIME (Mike, 2026-09-23: "change it at different levels...
     if you only want it for certain modules"). `data-panel-surface` on the INDIVIDUAL `.k-mod`
     (kiosk.js's `mountInstance`, only ever written for an explicit solid/veil/clear choice, never
     for 'default') rather than on `.kiosk`. Same four simple selectors as the two screen-level
     rules above -- tied specificity, so being LATER in the file is what makes an instance's own
     choice win over the screen default rather than the reverse; do not reorder these above the
     screen-level pair. A `solid` override needs its own rule too, for a panel opting OUT of a
     screen that has picked veil/clear for everything else. */
  .kiosk .k-stage .k-mod[data-panel-surface="solid"]{background:var(--surface);text-shadow:none}
  .kiosk .k-stage .k-mod[data-panel-surface="veil"]{background:var(--board-veil,rgba(27,36,41,.72))}
  .kiosk .k-stage .k-mod[data-panel-surface="clear"]{background:transparent;
    text-shadow:var(--panel-halo,var(--board-halo,0 1px 2px rgba(0,0,0,.85),0 0 6px rgba(0,0,0,.6)))}
  /* WHICH PANEL THE NEXT PRESS WILL ACT ON. Drawn on the CELL, outside the panel's own box, so
     it never covers the content — a ring over somebody's photograph would be the wrong trade.
     `outline` rather than `border` because a border would resize the cell and shift the grid
     every time focus moved, which on a bedside screen is the panels twitching under a hand.
     Only ever visible when there is more than one panel: on a single-panel screen "which one"
     is not a question anybody has. (fullscreen border, 2026-10-08: that sentence was not true -- nothing
     enforced it, and Mike saw the ring round a panel filling the screen. Now `data-ring-alone`, set by
     arrangement.js `syncRingAlone`, takes it off; the rule that says when is argued there.) */
  /* `--focus`, not `--accent` (2026-10-02, MIKE_LIST_20260930): the accent ring measured 2.83:1 in
     the default theme. theme.js derives --focus from the accent, a shade deeper only where needed. */
  /* With no space between panels (`panelGap` none or thin) there is no outside to draw on -- the cell clips
     at its own edge -- so the ring is drawn just INSIDE the panel (`--k-ring-offset`, -3px): 3px of the
     panel's edge under a ring, against no ring at all. Roomy keeps it outside, as it always was. */
  .k-stage.k-grid .k-cell[data-focused] .k-mod{
    outline:3px solid var(--focus,var(--accent,#839958));outline-offset:var(--k-ring-offset,-3px)}
  /* fullscreen border: the only panel a press could go to gets no "which panel" ring (its own controls keep theirs). */
  .k-stage.k-grid > .k-cell[data-focused][data-ring-alone] > .k-mod{outline:none}
  /* panel ring (2026-10-09; panel_ring.js argues the setting and its default): "Show which panel is selected" --
     Never, or gone a while after the last press. The ring's own selector with the screen's mark in front, so only
     the panel's ring goes and a control inside keeps its focus ring. A placed box's ring is inline (arrangement.js
     `syncRingAlone`), hence `!important`; its box-shadow is only ever the ring's band. */
  [data-panel-ring="never"] .k-stage.k-grid .k-cell[data-focused] .k-mod,
  [data-panel-ring-idle] .k-stage.k-grid .k-cell[data-focused] .k-mod{outline:none}
  [data-panel-ring="never"] [data-placed][data-focused],
  [data-panel-ring-idle] [data-placed][data-focused]{outline:none !important;box-shadow:none !important}
  /* NO TRANSITION ON THE RING, and it is not a style preference. The first version faded
     `outline-color` in over 150ms, and the ring then rendered in the element's own text colour
     instead of the moss — because a transition sits at its START value until the page
     composites, and it had not. A focus indicator that is only correct once an animation has
     run is a focus indicator that is wrong at the moment it is needed most: the frame it
     appears. It is also the wrong thing to animate — "which panel will the next press act on"
     should be true immediately or not shown. */
  /* `z-index:var(--z-panels)`, made EXPLICIT rather than left to accident: this used to work
     only because nothing else in `.kiosk` carried a z-index at all, so plain document order
     put every panel above nothing. The ambient layer (below) is the first sibling that DOES
     carry one (band 100) -- without this, a positioned z-indexed element out-ranks a
     positioned auto-z one regardless of markup order, and the scenery would paint over the
     panels it is meant to sit behind. */
  /* `pointer-events:none` -- WITHOUT THIS, THE AMBIENT LAYER IS UNREACHABLE. `.k-stage` is a
     full-bleed, `position:absolute;inset:0` box with no background, so it is easy to assume a
     click "in the gutter" (the grid gap, or this padding) falls through to whatever is behind
     it -- it does not. An element with no visible background still captures every pointer
     event across its entire box unless told otherwise; a transparent stage still shadows
     everything under it. Turned off HERE and restored on `.k-mod` (below) so a panel is exactly
     as clickable as before, and only the space that is NOT a panel -- this padding, and the
     grid gap between cells -- passes a press through to `.k-ambient` underneath. */
  .k-stage{position:absolute;inset:0;padding:var(--k-panel-pad,0);display:flex;z-index:var(--z-panels);pointer-events:none}
  /* SUBTITLES THAT HAVE NOWHERE TO GO (2026-09-30, row 2.42). When a game's answers sit at both the
     bottom and the top, subtitles.js asks the page for room by setting --subtitles-reserve on the
     root; the panels shrink up by that much, so the lines never cover an answer. 0 (unset) is today's
     layout exactly. The dashboard host (.k-dash, below) takes the stage's place and gets the same. */
  .kiosk > .k-stage{bottom:var(--subtitles-reserve,0px)}
  /* THE AMBIENT LAYER (band 100) -- see kiosk.js's own header comment on `data-ambient` for
     what mounts here. `pointer-events:auto`, DELIBERATELY differing from the board's own
     `.ab-surface` (which is `none`, because it sits UNDER cards that are somebody's voice):
     this surface sits under ordinary dashboard panels, so a press on a panel already reaches
     the panel first via normal stacking, and a press in the GAP BETWEEN panels can reach the
     scenery instead of falling through to nothing. Chat's own reasoning, recorded rather than
     silently assumed: *"the mechanism for... 'move the cursor over and catch one without
     leaving what you were doing.'"* */
  .k-ambient{position:absolute;inset:0;z-index:var(--z-ambient);pointer-events:auto}
  /* *** THE OCCUPANT NEEDS REAL PIXELS, AND NOTHING WAS GIVING IT ANY. *** `.k-mod{position:
     relative}` (modules.css) has no explicit height, so as a plain child of `.k-ambient` it sizes
     to its own CONTENT in normal flow -- zero, before anything has drawn into it. `.k-stage`'s own
     children get `flex:1` from `.k-stage.k-grid .k-cell .k-mod` below; `.k-ambient` never gave its
     one child the equivalent. Found building `comet_ambient.js` (2026-09-27): its canvas measured
     its own host via `getBoundingClientRect()`, same as every other canvas module, and got a real
     `0px` height back -- confirmed directly, not assumed, before writing this rule. A CSS-only
     occupant like `ambient_drift.js` partly hid the same bug: its dots are `position:absolute`
     against this same zero-height box and would be clipped by `.amb-drift{overflow:hidden}`
     rather than erroring, which is a quieter failure, not a different one. */
  .k-ambient > .k-mod{position:absolute;inset:0}
  .k-stage.k-grid{display:grid;gap:var(--k-panel-gap,0)}
  .k-stage.k-grid .k-cell{min-width:0;min-height:0;display:flex;overflow:hidden}
  /* `overflow:auto` was here and is now on `mod-host`, for every host rather than this one. */
  .k-stage.k-grid .k-cell .k-mod{flex:1;min-width:0;display:flex}
  .k-stage.k-grid .k-cell .k-mod > *{flex:1;min-width:0}
  .k-stage .k-mod{flex:1;min-width:0;display:flex}
  .k-stage .k-mod > *{flex:1;min-width:0}
  /* the camera "mirror" — pinned corner, always on top, never covered */
  /* the camera "mirror" — a HUD overlay; size + corner are per-profile settings */
  .k-mirror{position:absolute;aspect-ratio:4/3;z-index:var(--z-floating);border-radius:12px;overflow:hidden;
    box-shadow:0 6px 24px rgba(0,0,0,.5);border:2px solid rgba(255,255,255,.18)}
  .k-mirror .k-mod{width:100%;height:100%}
  .kiosk[data-mirror-size="sm"] .k-mirror{width:18vw}
  .kiosk[data-mirror-size="md"] .k-mirror{width:24vw}
  .kiosk[data-mirror-size="lg"] .k-mirror{width:32vw}
  .kiosk[data-mirror-corner="tr"] .k-mirror{top:2.5vmin;right:2.5vmin}
  .kiosk[data-mirror-corner="tl"] .k-mirror{top:2.5vmin;left:2.5vmin}
  .kiosk[data-mirror-corner="br"] .k-mirror{bottom:2.5vmin;right:2.5vmin}
  .kiosk[data-mirror-corner="bl"] .k-mirror{bottom:2.5vmin;left:2.5vmin}
  /* translucent clock HUD — corner is a per-profile setting (default bottom-left)
     *** ITS OWN BACKING, DARK ENOUGH TO READ OVER ANYTHING (Stage 4 bench soak, 2026-10-01). ***
     This was `rgba(255,255,255,.14)` under near-white text: fine over the dark frame it was drawn
     for, and nearly invisible the moment it sat over a panel instead — on High Contrast the photos
     panel's white letterbox put pale text on white. A HUD floats over whatever is under its
     corner, so the backing has to carry the contrast by itself: the theme's own `--letterbox`,
     at most of its strength, under the theme's own `--on-dark` (the role defined as "text over
     the letterbox"). Measured by dev/clock_hud_contrast_test.html over pure white AND pure black,
     the two extremes everything else lies between, in every theme. */
  .k-clock{position:absolute;z-index:calc(var(--z-floating) + 1);padding:9px 15px;border-radius:12px;
    background:color-mix(in srgb, var(--letterbox) 82%, transparent);color:var(--on-dark);max-width:34vw}
  .kiosk[data-clock-corner="bl"] .k-clock{bottom:2.5vmin;left:2.5vmin}
  .kiosk[data-clock-corner="br"] .k-clock{bottom:2.5vmin;right:2.5vmin}
  .kiosk[data-clock-corner="tl"] .k-clock{top:2.5vmin;left:2.5vmin}
  .kiosk[data-clock-corner="tr"] .k-clock{top:2.5vmin;right:2.5vmin}
  .k-clock .k-mod{width:100%}
  .k-clock .clock{align-items:flex-start;gap:2px}
  .k-clock .clock .time{color:var(--on-dark);font-size:2.6rem}
  .k-clock .clock .when{display:none}
  .k-clock .clock .date{color:var(--on-dark);font-size:.95rem}
  /* A countdown in the corner too: clock.js colours these for a PANEL (`--text-strong`, dark in
     every light theme), which on this dark backing would be dark on dark. */
  .k-clock .clock .cd-label,.k-clock .clock .cd-value,.k-clock .clock .cd-status{color:var(--on-dark)}
  /* "Show a small clock: Off" (arrangement.js SMALL_CLOCK_FIELD): the corner clock is hidden, its module kept, so
     turning it back on is instant and its own settings are as they were. On either root (`.view` carries the
     corners on the dashboard path). */
  .kiosk[data-clock-corner="off"] .k-clock,.view[data-clock-corner="off"] .k-clock{display:none}
  /* *** AN OVERLAY'S BACKDROP (2026-10-03, "Over the dashboard"; home_profile.js addAsOverlay). *** A module
     placed OVER the dashboard sits on whatever is under it -- a photo, a video, a moving scene -- and a placed
     box has no panel background of its own (that rule is `.k-stage .k-mod`, above). Every module draws its words
     in the theme's panel colours, made to be read on `--surface`. So an overlay gets an OPAQUE `--surface`, the
     theme's own `--text`, and a `--border` edge. Argued against see-through (the scoreboard's float argued it
     first, scoreboard.css): any see-through hands the contrast to the picture underneath, which nobody chose and
     which changes every few seconds on a slideshow -- a dark photo under a translucent cream box puts dark words
     on a muddy grey. Opaque costs the corner of the picture the overlay covers, and an overlay is small.
     Not the "Panel backgrounds" setting either: see-through panels were calibrated against a live theme behind
     them (`--board-veil`), not against a photograph directly under a small box. The corner clock is not a placed
     overlay and keeps its own darker backing (`.k-clock`, above), which carries `--on-dark` words. */
  .k-placed-overlay > .k-pcell > .k-mod{background:var(--surface);color:var(--text);border:1px solid var(--border);
    border-radius:12px;overflow:hidden;box-sizing:border-box}
  /* MIRROR MODE (M): the camera fills the whole screen */
  .kiosk.mirror-full .k-mirror{position:fixed;inset:0;width:auto;aspect-ratio:auto;
    border:0;border-radius:0;box-shadow:none;z-index:calc(var(--z-panels) + 50)}
  .kiosk.mirror-full .k-stage,.kiosk.mirror-full .k-clock,.kiosk.mirror-full .k-ambient{visibility:hidden}
  /* *** EMBEDDED: THE KIOSK AS A BOX ON SOMEBODY ELSE'S PAGE. ***
   * `mountKiosk({ embedded: true })` adds `k-embed` to `.kiosk`; nothing else sets it, so every
   * rule here is unreachable from the product screen and the normal kiosk is unchanged. It is
   * for `modules.html`, which mounts the real kiosk inside its stage so the transport bar and
   * the settings menu exist once. The host box must be positioned (`.trystage` is).
   *
   * Everything in the kiosk that was pinned to the VIEWPORT is re-pinned to the box: the kiosk
   * itself, full-screen mirror mode, and the settings scrim (`settings.css`'s `.st-scrim` is
   * `position:fixed;inset:0`, which is right for a kiosk that IS the screen and would cover a
   * whole public page from inside a 560px box). `.kiosk` is positioned, so an absolute scrim
   * resolves against it. The menu panel is sized in `vh`/`vw` for the same viewport reason, so it
   * gets the measure-against-your-box rule `settings.css` already gives an inline menu.
   * `overflow:hidden` because a box on a page must not let its HUD or drift bleed onto the text
   * around it; the bedside kiosk never needed that, the viewport did it. `.cur` (the drawn
   * cursor) stays fixed on purpose: it is placed from viewport coordinates. */
  .kiosk.k-embed{position:absolute;inset:0;overflow:hidden}
  .kiosk.k-embed.mirror-full .k-mirror{position:absolute}
  .kiosk.k-embed .st-scrim{position:absolute}
  .kiosk.k-embed .st-scrim .st-panel{max-height:100%;width:min(560px,100%)}
  /* THE BAR IS A TOOLBAR UNDER THE STAGE HERE, NOT AN OVERLAY ON IT, AND IT DOES NOT HIDE. On a
     bedside screen the bar floats over the panels and puts itself away, because nobody is meant
     to be operating it. On a page a visitor is USING, an invisible bar is an undiscoverable
     settings menu (nothing tells you to hover the bottom edge), and one floating over the module
     covers whatever is at the bottom of it. So the stage takes the room the bar leaves. */
  .kiosk.k-embed{display:flex;flex-direction:column}
  .kiosk.k-embed .k-stage{position:relative;inset:auto;flex:1;min-height:0}
  .kiosk.k-embed .k-controls{position:relative;left:auto;bottom:auto;transform:none;flex:none;
    margin:0 auto 8px}
  /* "Home" leaves for the list of your screens; a preview has no other screens to go to, and the
     site's own navigation is the way out of this page. The menu's own Home row is not touched. */
  .kiosk.k-embed [data-act="home"]{display:none}
  /* "Mirror" toggles the camera full-screen. An embed is only ever handed a panel (never the
     camera, which the kiosk draws as an overlay), so it would be a button that does nothing --
     the one thing the bar's own comments say it must never have. */
  .kiosk.k-embed [data-act="mirror"]{display:none}
  /* *** THE DASHBOARD AS A MODULE (step 6 Stage 3, `dashboardModule`, embedded only). *** The kiosk
     shell mounts ONE `view` module into `.k-dash`, which takes the stage's place (the kiosk's own
     `.k-stage` is hidden on that path). `.kiosk >` because `mountModule` also gives the host
     `.mod-host{position:relative}`, and this must win wherever the two files load. The view's own
     root is positioned so its `.k-stage` / `.k-mirror` / `.k-clock` / `.k-ambient` resolve against it
     exactly as the kiosk's do against `.kiosk`; `isolation` so a view standing on its own keeps its
     HUD and its ambient layer in one scale, as `.kiosk` does. */
  .kiosk > .k-dash{position:absolute;inset:0;bottom:var(--subtitles-reserve,0px)}
  .kiosk.k-embed > .k-dash{position:relative;inset:auto;flex:1;min-height:0}
  .view{position:absolute;inset:0;isolation:isolate}
  /* The corner settings, on the VIEW'S root too. Inside a kiosk the `.kiosk[...]` rules above already
     reach a view's HUD (descendant selectors) and both roots carry the same values, from the same
     settings doc; these are for a view that stands anywhere else (a slot, a page). */
  .view[data-mirror-size="sm"] .k-mirror{width:18vw}
  .view[data-mirror-size="md"] .k-mirror{width:24vw}
  .view[data-mirror-size="lg"] .k-mirror{width:32vw}
  .view[data-mirror-corner="tr"] .k-mirror{top:2.5vmin;right:2.5vmin}
  .view[data-mirror-corner="tl"] .k-mirror{top:2.5vmin;left:2.5vmin}
  .view[data-mirror-corner="br"] .k-mirror{bottom:2.5vmin;right:2.5vmin}
  .view[data-mirror-corner="bl"] .k-mirror{bottom:2.5vmin;left:2.5vmin}
  .view[data-clock-corner="bl"] .k-clock{bottom:2.5vmin;left:2.5vmin}
  .view[data-clock-corner="br"] .k-clock{bottom:2.5vmin;right:2.5vmin}
  .view[data-clock-corner="tl"] .k-clock{top:2.5vmin;left:2.5vmin}
  .view[data-clock-corner="tr"] .k-clock{top:2.5vmin;right:2.5vmin}
  /* *** STAGE 3b: THE CHROME A DASHBOARD PLACES, AND THE PLAIN BAR. ***
     A dashboard docks its placed chrome (the transport bar, the settings menu) along its edges. The
     bottom dock is a ROW of the dashboard, not an overlay on it: the stage takes the room the bar
     leaves, as the embed's own bar always did, so nothing at the bottom of a panel is covered. The
     side docks are drawers over the stage that only take the pointer where something is showing. */
  .view.v-docked{display:grid;grid-template-rows:auto 1fr auto}
  .view.v-docked > .k-stage{position:relative;inset:auto;grid-row:2;min-height:0}
  .view > .v-dock-top{grid-row:1;position:relative}
  .view > .v-dock-bottom{grid-row:3;position:relative;display:flex;justify-content:center;
    padding:0 1vmin 1vmin;z-index:var(--z-transport)}
  /* IN FULL SCREEN, A MODULE IS A DASHBOARD (2026-10-14, Mike on the Modules page: "There is still a little bar all the
     way across the bottom going up to the top of the transport bar ... The fullscreen module should behave like a
     dashboard"). The bottom dock floats over the stage instead of keeping a row, so a tucked bar leaves no strip; its
     empty box takes no presses, only the bar does (view.js's reason). The same three rules Home uses when it fills the
     window (modules.html `data-bar-over`). */
  :fullscreen .view > .v-dock-bottom{position:absolute;left:0;right:0;bottom:0;grid-row:auto;pointer-events:none}
  :fullscreen .view > .v-dock-bottom > .v-chrome{pointer-events:none;height:auto}
  :fullscreen .view > .v-dock-bottom > .v-chrome > .tb-bar{pointer-events:auto}
  .view > .v-dock-left,.view > .v-dock-right{position:absolute;top:0;bottom:0;width:min(420px,60%);
    z-index:var(--z-transport);pointer-events:none}
  .view > .v-dock-left{left:0}
  .view > .v-dock-right{right:0}
  .view > .v-dock-left .st-scrim:not([hidden]),.view > .v-dock-right .st-scrim:not([hidden]){pointer-events:auto}
  .v-chrome,.sm-dock{position:relative;height:100%}
  /* The placed transport bar: the plain bar's own look, as a flat row in its dock. */
  .tb-bar{display:flex;flex-wrap:wrap;justify-content:center;gap:12px;align-items:center;
    background:rgba(7,18,13,.82);border:1px solid rgba(255,255,255,.14);border-radius:14px;padding:8px 12px}
  .tb-mods{display:flex;flex-wrap:wrap;justify-content:center;gap:6px;min-width:0}
  .tb-actions{display:flex;flex-wrap:wrap;justify-content:center;gap:8px}
  .tb-mods:not(:empty) + .tb-actions{border-left:1px solid rgba(255,255,255,.15);padding-left:12px}
  .tb-actions button{font-size:.82rem;color:#cfe0d6;background:transparent;
    border:1px solid rgba(255,255,255,.22);border-radius:9px;padding:6px 12px;cursor:pointer;min-height:36px}
  .tb-actions button:hover{background:rgba(255,255,255,.10)}
  .tb-actions button[data-on="1"]{background:var(--highlight);border-color:var(--highlight);color:#1a1408;font-weight:700}
  /* THE PLAIN BAR -- the shell's own bar on the dashboard path. SOLID and flat on purpose, whatever the
     theme or the panel backgrounds say (Design: "solid, flat, and it can't be restyled or removed"):
     it is the way back when a dashboard has gone wrong, so nothing a dashboard sets may make it hard
     to see. Hidden (`k-plain-off`) only while a placed bar carries the bar and nobody summoned it. */
  .kiosk > .k-controls.k-plain{background:#07120d;border:2px solid #cfe0d6;opacity:1;backdrop-filter:none}
  .kiosk > .k-controls.k-plain-off{display:none}
  /* THE RING while a switch is held for the plain bar: words and a fill, never colour alone. */
  .k-ring{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:var(--z-transport);
    display:flex;align-items:center;gap:12px;padding:12px 18px;border-radius:14px;
    background:#07120d;color:#f3f7f4;border:2px solid #cfe0d6;font:600 1rem/1.3 system-ui,sans-serif;
    pointer-events:none}
  .k-ring[hidden]{display:none}
  .k-ring-fill{width:34px;height:34px;border-radius:50%;flex:none;
    background:conic-gradient(#cfe0d6 var(--k-ring-p,0%),rgba(255,255,255,.18) 0)}
  @property --k-ring-p{syntax:'<percentage>';inherits:false;initial-value:0%}
  @media (prefers-reduced-motion:no-preference){
    .k-ring.k-ring-go .k-ring-fill{animation:k-ring-fill var(--k-ring-ms,1250ms) linear forwards}
  }
  /* Reduced motion: no animation -- the ring shows half full, and the words carry the meaning. */
  @media (prefers-reduced-motion:reduce){ .k-ring .k-ring-fill{--k-ring-p:50%} }
  @keyframes k-ring-fill{from{--k-ring-p:0%}to{--k-ring-p:100%}}
  /* auto-hiding control bar */
  /* *** THE BAR WRAPS. IT USED TO RUN OFF THE SCREEN. ***
   *
   * G9, Mike off the live site: *"Only three appear on the bar, and there is no overflow or
   * scroll. The rest are unreachable."* This was one un-wrapping flex row with no width limit,
   * so a screen with nine panels produced a bar wider than the screen and the ends of it — the
   * `Screens` button at one end, the last panels at the other — were simply outside the
   * display. Measured in `transport_test` at 720px: two of nine off the end.
   *
   * *** WRAPPING, NOT SCROLLING, AND THAT IS THE WHOLE DECISION. *** A horizontal scroll needs
   * a drag or a wheel. The person this screen is for cannot do either, and a caregiver reaching
   * past them to swipe a bar is worse than a bar that is two rows tall. Wrapping keeps every
   * button on screen and pressable by anything — a finger, a switch walking the row, a cursor.
   *
   * `max-height` plus `overflow:auto` is the floor under that, for a screen with so many panels
   * that even a wrapped bar cannot fit: it is better to be able to scroll to a button than to
   * have the bar cover the panels it is for. */
  .k-controls{position:absolute;left:50%;bottom:2.2vmin;transform:translateX(-50%);
    display:flex;flex-wrap:wrap;justify-content:center;gap:14px;align-items:center;
    max-width:calc(100% - 4.4vmin);max-height:40vh;overflow:auto;
    background:rgba(7,18,13,.82);
    border:1px solid rgba(255,255,255,.14);border-radius:14px;padding:8px 12px;z-index:var(--z-transport);
    transition:opacity .3s ease}
  .k-controls.hidden{opacity:0;pointer-events:none}
  /* bar toggle (2026-10-06, bar_toggle.js): put away by its key. Over the plain bar's solid look too (`.k-plain` keeps
     opacity 1 on purpose); `visibility`, not `display`, so the bar's own box still says where "near the bar" is. */
  .kiosk > .k-controls.k-bar-hidden{visibility:hidden;pointer-events:none}

  /* THE SCREEN PICKER — a strip above the bar, never a scrim over the panels. See the long
     note on `toggleScreens` in kiosk.js for why it is a strip: a modal over her photographs is
     a state only an input can leave, and she cannot give one. This leaves everything playing
     and visible, and it puts itself away with the bar. */
  .k-screens{position:absolute;left:50%;bottom:calc(2.2vmin + 58px);transform:translateX(-50%);
    display:flex;flex-wrap:wrap;justify-content:center;gap:8px;z-index:var(--z-transport);
    max-width:calc(100% - 4.4vmin);max-height:34vh;overflow:auto;
    background:rgba(7,18,13,.9);border:1px solid rgba(255,255,255,.14);
    border-radius:14px;padding:8px 12px}
  .k-scr{font-size:.82rem;color:#cfe0d6;background:transparent;
    border:1px solid rgba(255,255,255,.22);border-radius:9px;padding:8px 14px;cursor:pointer;
    min-height:44px}
  .k-scr:hover:not(:disabled){background:rgba(255,255,255,.10)}
  /* The one you are on, marked and not pressable — pressing it would do nothing, and a control
     that does nothing costs a switch user a press to find out. */
  .k-scr.on{background:var(--accent);border-color:var(--accent);color:var(--on-accent);font-weight:700;
    cursor:default}
  .k-scr-out{border-style:dashed;opacity:.85}
  .k-scr-note{color:#cfe0d6;font-size:.82rem;opacity:.8;align-self:center;padding:0 4px}
  .k-mods{display:flex;flex-wrap:wrap;justify-content:center;gap:6px;min-width:0}
  .k-dot{font-size:.82rem;text-transform:capitalize;color:#cfe0d6;background:transparent;
    border:1px solid rgba(255,255,255,.22);border-radius:9px;padding:6px 12px;cursor:pointer}
  .k-dot.on{background:var(--accent);border-color:var(--accent);color:var(--on-accent);font-weight:700}
  /* A PANEL THIS SCREEN IS NOT SHOWING. Quieter than a panel that is, and dashed rather than
     solid, so "on this screen but not in the arrangement" is legible without reading the
     tooltip. Pressing it brings it into the panel that has focus — see `showUnplaced`. */
  .k-dot.k-off{opacity:.62;border-style:dashed}
  .k-dot.k-off:hover{opacity:1}
  /* *** A PANEL WITH NOTHING TO PRESS STILL HAS A BUTTON — see D16 in kiosk.js. ***
     It used to be REMOVED from the bar the moment it was placed, so pressing a button deleted
     that button and a switch user could not get the panel back. It is drawn quieter instead:
     pressing it moves the outline there and the control set is honestly empty. Quieter, never
     hidden — an empty control area is a correct answer, a vanishing button is not. */
  .k-dot.k-nover{opacity:.7}
  .k-dot.k-nover:hover{opacity:1}
  .k-dot.k-nover.on{opacity:1}
  /* `border-left` only when the actions are on the SAME ROW as the panel buttons. Once the bar
     wraps, a left border on a row that starts at the left edge is a stray vertical line. */
  .k-actions{display:flex;flex-wrap:wrap;justify-content:center;gap:8px}
  .k-mods:not(:empty) + .k-actions{border-left:1px solid rgba(255,255,255,.15);padding-left:12px}
  .k-actions button{font-size:.82rem;color:#cfe0d6;background:transparent;
    border:1px solid rgba(255,255,255,.22);border-radius:9px;padding:6px 12px;cursor:pointer}
  .k-actions button:hover,.k-dot:hover{background:rgba(255,255,255,.10)}
  /* Hush, while it is on. LIT, not subtle: silence with no visible cause reads as a broken
     screen, and whoever finds it that way has to be able to see why and undo it. */
  .k-actions button[data-on="1"]{background:var(--highlight);border-color:var(--highlight);
    color:#1a1408;font-weight:700}
  /* sign-in screen (shown when not authenticated) */
  #login{position:fixed;inset:0;display:flex;flex-direction:column;align-items:center;
    justify-content:center;gap:18px;color:#e8f0ea;text-align:center;padding:24px}
  #login h1{font-size:1.5rem;font-weight:600;margin:0;letter-spacing:.02em}
  #login p{color:#9fb3a8;margin:0;max-width:34ch}
  #login .gbtn{display:inline-flex;align-items:center;gap:10px;background:#fff;color:#1f1f1f;
    border:none;border-radius:10px;padding:12px 22px;font-size:1rem;font-weight:600;cursor:pointer}
  #login .gbtn:hover{background:#f1f1f1}
  #login .err{color:#e79; font-size:.9rem}
