/* ui.css — the control kit. Every interactive thing the sheet's terminals use, in the register of the page:
   a printed bureau form displayed on a tube. Keys are keycaps that stand off the panel and sit flush when
   pressed; switches are slide switches; selection is inverse video (the cursor of a terminal, not a hover
   glow); progress is block characters; a lamp is a lamp. Classes are ui-<part>; state lives in ARIA
   attributes (aria-pressed, aria-checked, aria-selected, aria-current, aria-invalid), never in extra classes,
   so the markup is honest to assistive tech and the CSS reads the same state the reader hears.
   Focus is a dashed phantom line (drafting's "not here yet"), never the browser's blue ring.
   Behaviour: js/ui.js. Tokens: css/base.css (--ink, --paper, --hair, --ink-2, --green, --mono, --sans). */

.ui{ --key-shadow: 2px 2px 0 var(--ink); }
.ui-row{ display:flex; flex-wrap:wrap; gap:10px 12px; align-items:center; margin-bottom:14px; }
.ui-grid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(190px, 1fr)); gap:14px 18px; margin-bottom:14px; }
.ui .kicker{ margin-top:18px; }
.ui section > .kicker:first-of-type{ margin-top:0; }

/* focus: one device for every control */
.ui :focus-visible, .ui-list:focus-visible{ outline:1px dashed var(--ink); outline-offset:3px; }
.ui-in:focus-within{ box-shadow:inset 0 0 0 1px var(--ink); }

/* ---- keys (buttons). A keycap: 1px ink border, a hard 2px shadow (it stands off the panel);
   pressed or latched (aria-pressed) it moves 2px and sits flush. primary = inverse video. */
.ui-key{ display:inline-block; font:500 11px/1 var(--mono); letter-spacing:.1em; text-transform:uppercase;
  padding:9px 13px 8px; border:1px solid var(--ink); background:var(--paper); color:var(--ink);
  box-shadow:var(--key-shadow); cursor:pointer; text-decoration:none; user-select:none; vertical-align:middle; }
.ui-key:hover{ background:rgba(30,42,56,.08); }
.ui-key:active, .ui-key[aria-pressed="true"]{ transform:translate(2px, 2px); box-shadow:none; }
.ui-key[aria-pressed="true"]{ background:rgba(30,42,56,.14); }
.ui-key.primary{ background:var(--ink); color:var(--paper); }
.ui-key.primary:hover{ background:var(--ink-2); border-color:var(--ink-2); }
.ui-key.quiet{ box-shadow:none; border-color:var(--hair); }
.ui-key.quiet:active{ transform:none; background:rgba(30,42,56,.14); }
.ui-key:disabled, .ui-key[aria-disabled="true"]{ border-color:var(--hair); color:var(--ink-2); background:transparent;
  box-shadow:none; transform:none; opacity:.6; cursor:not-allowed; }
.ui-key.primary:disabled{ background:var(--hair); color:var(--paper); }

/* function keys: the terminal's soft-key strip — the key's cap above, its meaning (set by the sheet) below */
.ui-fkeys{ display:flex; flex-wrap:wrap; border:1px solid var(--ink); margin-bottom:14px; }
.ui-fkey{ flex:1 1 0; min-width:96px; display:flex; flex-direction:column; align-items:flex-start; gap:6px;
  padding:8px 10px 9px; border:0; border-right:1px solid var(--hair); background:transparent; color:var(--ink);
  font-family:var(--mono); cursor:pointer; text-align:left; }
.ui-fkey:last-child{ border-right:0; }
.ui-fkey .k{ font-size:10px; font-weight:500; letter-spacing:.08em; border:1px solid var(--ink); padding:2px 5px 1px; }
.ui-fkey .f{ font-size:11px; letter-spacing:.06em; text-transform:uppercase; color:var(--ink-2); }
.ui-fkey:hover .f{ color:var(--ink); }
.ui-fkey[aria-current="true"]{ background:var(--ink); color:var(--paper); }
.ui-fkey[aria-current="true"] .k{ border-color:var(--paper); }
.ui-fkey[aria-current="true"] .f{ color:var(--paper); }
.ui-fkey:disabled{ cursor:not-allowed; opacity:.5; }
.ui-fkey:focus-visible{ outline-offset:-4px; }

kbd{ font:500 10px/1 var(--mono); letter-spacing:.04em; border:1px solid var(--ink); padding:2px 5px 1px;
  box-shadow:1px 1px 0 var(--ink); vertical-align:1px; margin:0 1px; }

/* ---- switches: a slide switch. The knob is an ink block that steps across the track (a mechanism,
   not a tween); the state word beside it is decorative — the switch carries aria-checked. */
.ui-switch-row{ display:inline-flex; align-items:center; gap:10px; margin-right:18px; }
.ui-switch{ width:46px; height:20px; padding:0; border:1px solid var(--ink); background:var(--paper);
  position:relative; cursor:pointer; vertical-align:middle;
  background-image:repeating-linear-gradient(90deg, transparent 0 21px, var(--hair) 21px 22px, transparent 22px 44px); background-clip:content-box; }
.ui-switch .knob{ position:absolute; top:2px; left:2px; width:16px; height:14px; background:var(--ink); transition:left .12s steps(3, end); }
.ui-switch[aria-checked="true"] .knob{ left:26px; }
.ui-switch[aria-checked="true"]{ background-color:rgba(30,42,56,.1); }
.ui-switch:disabled{ border-color:var(--hair); cursor:not-allowed; opacity:.55; }
.ui-switch-st{ font:500 11px/1 var(--mono); letter-spacing:.1em; min-width:3ch; color:var(--ink-2); }
.ui-switch[aria-checked="true"] ~ .ui-switch-st{ color:var(--ink); }

/* ---- checks and radios: a drawn box with an ink centre; the native input does the work, hidden */
.ui-check, .ui-radio{ display:inline-flex; align-items:center; gap:8px; font:13px/1.3 var(--sans); cursor:pointer; margin-right:18px; position:relative; }
.ui-check input, .ui-radio input{ position:absolute; opacity:0; width:1px; height:1px; margin:0; pointer-events:none; }
.ui-check::before, .ui-radio::before{ content:""; flex:none; width:13px; height:13px; border:1px solid var(--ink);
  background:transparent; box-shadow:inset 0 0 0 2px var(--paper); }
.ui-radio::before{ border-radius:50%; }
.ui-check:has(input:checked)::before, .ui-radio:has(input:checked)::before{ background:var(--ink); }
.ui-check:has(input:focus-visible)::before, .ui-radio:has(input:focus-visible)::before{ outline:1px dashed var(--ink); outline-offset:2px; }
.ui-check:has(input:disabled), .ui-radio:has(input:disabled){ color:var(--ink-2); cursor:not-allowed; }
.ui-check:has(input:disabled)::before, .ui-radio:has(input:disabled)::before{ border-color:var(--hair); }
.ui-check:has(input:disabled:checked)::before{ background:var(--hair); }

/* ---- tabs: a row of keys sharing one border; the selected one is inverse */
.ui-tabs{ border:1px solid var(--ink); margin-bottom:14px; max-width:64ch; }
.ui-tablist{ display:flex; flex-wrap:wrap; border-bottom:1px solid var(--ink); }
.ui-tab{ font:500 11px/1 var(--mono); letter-spacing:.1em; text-transform:uppercase; padding:9px 14px 8px;
  border:0; border-right:1px solid var(--ink); background:transparent; color:var(--ink); cursor:pointer; }
.ui-tab:hover{ background:rgba(30,42,56,.08); }
.ui-tab[aria-selected="true"]{ background:var(--ink); color:var(--paper); }
.ui-tab:focus-visible{ outline-offset:-4px; }
.ui-tabpanel{ padding:11px 13px; font-size:13px; }
.ui-tabpanel[hidden]{ display:none; }

/* ---- fields: a labelled line on the form. The prompt glyph is the terminal's; the caret is the browser's. */
.ui-field{ min-width:0; }
.ui-lbl{ display:block; font:500 10px/1.4 var(--mono); letter-spacing:.12em; text-transform:uppercase; color:var(--ink-2); margin-bottom:6px; }
.ui-lbl .ui-pct{ float:right; color:var(--ink); letter-spacing:.04em; }
.ui-in{ display:flex; align-items:center; border:1px solid var(--ink); background:rgba(221,227,232,.6); font:13px/1 var(--mono); }
.ui-in::before{ content:">"; padding-left:8px; color:var(--ink-2); }
.ui-in input, .ui-in select{ flex:1; min-width:0; border:0; background:transparent; font:inherit; color:var(--ink);
  padding:8px 8px 7px; outline:none; caret-color:var(--ink); border-radius:0; }
.ui-in input::placeholder{ color:var(--hair); }
.ui-in input:read-only{ color:var(--ink-2); }
.ui-in:has(input:read-only){ border-color:var(--hair); }
.ui-in:has(input:read-only)::before{ content:"="; }
.ui-in.sel select{ appearance:none; -webkit-appearance:none; padding-right:28px; cursor:pointer; }
.ui-in.sel{ position:relative; }
.ui-in.sel::after{ content:"▾"; position:absolute; right:9px; pointer-events:none; color:var(--ink); }
.ui-hint{ display:block; font:11px/1.4 var(--mono); color:var(--ink-2); margin-top:5px; }
.ui-tag{ display:inline-block; font:500 10px/1 var(--mono); letter-spacing:.1em; text-transform:uppercase;
  border:1px solid var(--ink); padding:3px 5px 2px; color:var(--ink); vertical-align:1px; margin-right:4px; }
.ui-field.err .ui-in{ border-style:dashed; }
.ui-field.err .ui-tag{ background:var(--ink); color:var(--paper); }
.ui-field.err .ui-hint{ color:var(--ink); }

/* ---- list: the terminal's selection list. The cursor is inverse video; arrow keys move it. */
.ui-list{ list-style:none; margin:0; padding:0; border:1px solid var(--ink); font:12.5px/1.3 var(--mono); max-width:36ch; background:rgba(221,227,232,.6); }
.ui-opt{ display:flex; gap:12px; padding:7px 10px; border-bottom:1px solid var(--hair); cursor:default; }
.ui-opt:last-child{ border-bottom:0; }
.ui-opt .c{ flex:none; width:5ch; color:var(--ink-2); }
.ui-opt:hover{ background:rgba(30,42,56,.08); }
.ui-opt[aria-selected="true"]{ background:var(--ink); color:var(--paper); }
.ui-opt[aria-selected="true"] .c{ color:var(--paper); }

/* ---- lamps: a lamp is lit, unlit, or blinking; the page's green is the reporting/OK mark, as on the chart */
.ui-lamp-row{ display:inline-flex; align-items:center; gap:8px; font:500 11px/1 var(--mono); letter-spacing:.08em; text-transform:uppercase; margin-right:22px; }
.ui-lamp{ display:inline-block; width:10px; height:10px; border-radius:50%; border:1px solid var(--ink); background:transparent; }
.ui-lamp.lit{ background:var(--ink); }
.ui-lamp.ok{ background:var(--green); border-color:var(--green); }
.ui-lamp.busy{ background:var(--ink); animation:ui-blink 1s steps(2, end) infinite; }
@keyframes ui-blink{ 50%{ background:transparent; } }

/* ---- readouts: a labelled figure; with the led layer on it wears the dot-matrix face */
.ui-readout{ border:1px solid var(--hair); padding:10px 12px 11px; background:rgba(221,227,232,.55); }
.ui-readout .v{ font:700 26px/1 var(--sans); color:var(--ink); }
.fx-led .ui-readout .v.led{ font-size:28px; }
.ui-readout .u{ font:11px/1 var(--mono); color:var(--ink-2); margin-left:6px; letter-spacing:.04em; }

/* ---- progress: block characters. Determinate fills --v percent of the track in 6px cells;
   the scanning variant walks a block back and forth (reduced motion: a still hatch). */
.ui-bar{ height:16px; border:1px solid var(--ink); padding:2px; background:var(--paper);
  background-image:repeating-linear-gradient(90deg, rgba(30,42,56,.14) 0 6px, transparent 6px 8px); background-clip:content-box; }
.ui-bar i{ display:block; height:100%; width:calc(var(--v, 0) * 1%);
  background:repeating-linear-gradient(90deg, var(--ink) 0 6px, transparent 6px 8px); transition:width .3s steps(6, end); }
.ui-bar.scan i{ width:22%; animation:ui-scan 1.4s steps(14, end) infinite alternate; }
@keyframes ui-scan{ from{ margin-left:0; } to{ margin-left:78%; } }

/* ---- meter: --v of --n segments lit; --th is a threshold, drawn as a cut line */
.ui-meter{ height:18px; border:1px solid var(--ink); padding:2px; position:relative; background:var(--paper);
  background-image:repeating-linear-gradient(90deg, rgba(30,42,56,.14) 0 calc(100% / var(--n, 20) - 2px), transparent calc(100% / var(--n, 20) - 2px) calc(100% / var(--n, 20)));
  background-clip:content-box; }
.ui-meter i{ display:block; height:100%; width:calc(var(--v, 0) / var(--n, 20) * 100%);
  background:repeating-linear-gradient(90deg, var(--ink) 0 calc(100% / var(--v, 1) - 2px), transparent calc(100% / var(--v, 1) - 2px) calc(100% / var(--v, 1))); }
.ui-meter .th{ position:absolute; top:-5px; bottom:-5px; left:calc(2px + (100% - 4px) * var(--th, 0) / var(--n, 20)); width:0; border-left:1px dashed var(--ink); }

/* ---- notices: a box on the form with its tag; warn is the heavier rule */
.ui-notice{ border:1px solid var(--ink); padding:10px 12px; display:flex; gap:12px; align-items:flex-start; max-width:64ch; margin-bottom:12px; background:rgba(221,227,232,.5); }
.ui-notice p{ margin:0; font-size:13px; }
.ui-notice .ui-tag{ flex:none; margin-top:1px; }
.ui-notice.warn{ border-width:2px; }
.ui-notice.warn .ui-tag{ background:var(--ink); color:var(--paper); }

/* ---- dialog: a box over the screen, inside the tube (so it wears the same phosphor). The screen is its host. */
.screen{ position:relative; }   /* the dialog's host with the screens layer off; the layer makes screens absolute anyway */
.ui-dialog{ position:fixed; inset:0; z-index:9; display:grid; place-items:center; padding:20px; background:rgba(221,227,232,.72); }
.ui-dialog[hidden]{ display:none; }
.ui-dialog-box{ border:2px solid var(--ink); background:var(--paper); width:100%; max-width:440px; box-shadow:6px 6px 0 var(--ink); }
.ui-dialog-hd{ background:var(--ink); color:var(--paper); font:500 11px/1 var(--mono); letter-spacing:.12em; text-transform:uppercase; padding:9px 12px 8px; }
.ui-dialog-bd{ padding:12px 12px 14px; font-size:13px; }
.ui-dialog-bd p{ margin:0 0 14px; }
.ui-dialog-bd .ui-row{ margin:0; }

/* ---- navigation: a strip of sheets (every entry a real address; the current one inverse), a pager, and links */
.ui-strip{ display:flex; flex-wrap:wrap; border:1px solid var(--ink); font:500 11px/1 var(--mono); letter-spacing:.08em; text-transform:uppercase; margin-bottom:14px; }
.ui-strip a{ padding:9px 14px 8px; border-right:1px solid var(--hair); color:var(--ink); text-decoration:none; }
.ui-strip a:last-child{ border-right:0; }
.ui-strip a:hover{ background:rgba(30,42,56,.08); }
.ui-strip a[aria-current]{ background:var(--ink); color:var(--paper); }
.ui-strip a:focus-visible{ outline-offset:-4px; }
.ui-pager{ display:flex; flex-wrap:wrap; align-items:center; gap:12px; margin-bottom:14px; }
.ui-pager-ro{ font:11px/1 var(--mono); letter-spacing:.06em; text-transform:uppercase; color:var(--ink-2); }
.ui-pager-ro b{ color:var(--ink); font-weight:500; }
.ui p a, .ui-tabpanel a{ color:var(--ink); text-decoration:underline; text-underline-offset:2px; text-decoration-thickness:1px; }
.ui p a:hover, .ui-tabpanel a:hover{ background:var(--ink); color:var(--paper); text-decoration:none; }

/* ---- motion: honoured, with the page's review override (?on=motion) */
@media (prefers-reduced-motion: reduce){
  body:not(.fx-motion) .ui-lamp.busy{ animation:none; }
  body:not(.fx-motion) .ui-bar.scan i{ animation:none; width:100%; opacity:.35; }
  body:not(.fx-motion) .ui-switch .knob, body:not(.fx-motion) .ui-bar i{ transition:none; }
}
@media (max-width:720px){
  .ui-fkey{ min-width:0; flex-basis:33.333%; }
  .ui-tabs, .ui-notice, .ui-list{ max-width:none; }
}
