/* BYOI terminal UI — the one colour and type layer.
 *
 * The desk, the guest phone and the table kiosk are three apps on three
 * origins, but they are one design. Every colour any of them paints comes from
 * here, so a token is fixed once rather than three times, and light/dark is a
 * property of this file rather than something each app reinvents.
 *
 * Served to all three from their own path (/host/assets/tui.css,
 * /guest/tui.css, /seat/assets/tui.css) rather than one shared mount: the
 * guest is a PWA whose service worker is scoped to /guest/ and only caches
 * /guest*, so a token file anywhere else would drop out of the offline cache
 * and leave a phone on a dead uplink unstyled.
 *
 * Themes. `:root` carries light. Dark is applied either by the OS (AUTO, the
 * default) or by an explicit choice, and an explicit choice has to beat the OS
 * in both directions — hence the :not([data-theme="light"]) guard on the media
 * query. Never give a colour its only definition inside the media block.
 */

/* Self-hosted, not linked from a CDN: the salon runs on a room's own Wi-Fi and
 * may never reach the internet, and a design drawn out of box-drawing glyphs
 * degrades badly into a proportional fallback. The full release is used rather
 * than a "latin" subset because the subsets drop U+2500-259F — the rules and
 * meters this whole interface is built from. `block` over `swap`: these load
 * from the same machine in milliseconds, and a flash of the wrong font means a
 * flash of disconnected box rules.
 *
 * JetBrains Mono v2.304, SIL Open Font License 1.1 — see fonts/OFL.txt.
 */
@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/JetBrainsMono-Light.woff2") format("woff2");
  font-weight: 300;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/JetBrainsMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/JetBrainsMono-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/JetBrainsMono-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/JetBrainsMono-ExtraBold.woff2") format("woff2");
  font-weight: 800;
  font-style: normal;
  font-display: block;
}

:root {
  color-scheme: light dark;

  /* One family, everywhere. The stack behind it is what a machine that could
     not load the file falls back to — still monospaced, so the grid survives. */
  --tui-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", "Cascadia Mono",
    Menlo, Consolas, "DejaVu Sans Mono", monospace;

  /* ---- light ---- */
  --bg-base: #f4efe4;
  --bg-panel: #fbf8f1;
  --bg-raised: #ede7d9;
  --bg-select: #dcebdf;
  --bg-inverse: #155f3a;
  --bg-user: #155f3a;

  --line-idle: #cfc7b4;
  --line-active: #155f3a;

  --ink-bright: #12251a;
  --ink-base: #3b5546;
  --ink-dim: #63725e;
  --ink-inverse: #fbf8f1;
  --ink-user: #fbf8f1;

  --acc-green: #12794a;
  --acc-amber: #96631a;
  --acc-cyan: #0f6e76;
  --acc-magenta: #8a3b93;
  --acc-red: #a5342a;
  --acc-blue: #2c5aa8;

  /* The slip QR is the one thing that must not theme: it is read by a camera,
     and a light-on-dark QR does not scan. Fixed in both modes, deliberately. */
  --qr-paper: #ffffff;
  --qr-ink: #0b0e0b;

  /* Type. Shorthands so a rule can say `font: var(--t-body)` and get weight,
     size and leading together; tracking is separate because `font` has no slot
     for it. Sizes are the ones the Figma ramp is built on. */
  --t-display: 800 34px/40px var(--tui-mono);
  --t-h1: 700 22px/28px var(--tui-mono);
  --t-h2: 700 15px/22px var(--tui-mono);
  --t-title: 700 13px/20px var(--tui-mono);
  --t-body: 400 13px/20px var(--tui-mono);
  --t-body-bold: 700 13px/20px var(--tui-mono);
  --t-log: 400 12px/18px var(--tui-mono);
  --t-small: 400 11px/16px var(--tui-mono);
  --t-small-bold: 700 11px/16px var(--tui-mono);
  --t-key: 500 10px/14px var(--tui-mono);

  --ls-display: -0.01em;
  --ls-title: 0.06em;
  --ls-small: 0.02em;
  --ls-key: 0.08em;

  /* A character cell, for anything that wants to sit on the grid. */
  --cell-w: 7.8px;
  --cell-h: 20px;
}

/* AUTO: no explicit choice, so follow the device. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg-base: #070806;
    --bg-panel: #0b0f0b;
    --bg-raised: #111710;
    --bg-select: #12301e;
    --bg-inverse: #3dff8a;
    --bg-user: #14361f;

    --line-idle: #1d3325;
    --line-active: #3dff8a;

    --ink-bright: #e7f6ec;
    --ink-base: #9dbca9;
    --ink-dim: #67856f;
    --ink-inverse: #070806;
    --ink-user: #e7f6ec;

    --acc-green: #3dff8a;
    --acc-amber: #e0a85c;
    --acc-cyan: #56d8d8;
    --acc-magenta: #c77bd1;
    --acc-red: #ff6b5a;
    --acc-blue: #6c9ce8;
  }
}

/* An explicit choice, which beats the OS either way. */
:root[data-theme="dark"] {
  --bg-base: #070806;
  --bg-panel: #0b0f0b;
  --bg-raised: #111710;
  --bg-select: #12301e;
  --bg-inverse: #3dff8a;
  --bg-user: #14361f;

  --line-idle: #1d3325;
  --line-active: #3dff8a;

  --ink-bright: #e7f6ec;
  --ink-base: #9dbca9;
  --ink-dim: #67856f;
  --ink-inverse: #070806;
  --ink-user: #e7f6ec;

  --acc-green: #3dff8a;
  --acc-amber: #e0a85c;
  --acc-cyan: #56d8d8;
  --acc-magenta: #c77bd1;
  --acc-red: #ff6b5a;
  --acc-blue: #6c9ce8;
}

:root[data-theme="dark"] { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

/* ---------------------------------------------------------------------------
 * The grammar.
 *
 * Three apps draw the same handful of shapes: a ruled panel with its label
 * straddling the top border, a bracketed control, a status bar, a block meter.
 * They live here rather than three times over, and each app's own sheet is left
 * to say only where things go.
 *
 * House rules, so the parts stay recognisable as one system:
 *   - Selection is inverse video. Not a tint, not an underline, not a shadow.
 *   - Controls are bracketed, never pills. Disabled keeps its brackets and
 *     drops to ink/dim; it must not vanish.
 *   - Nothing has a corner radius and nothing casts a shadow.
 *   - Meters are block glyphs on the character grid, never a styled div.
 * ------------------------------------------------------------------------- */

.tui,
.tui button,
.tui input,
.tui select,
.tui textarea {
  font: var(--t-body);
  color: var(--ink-base);
}
.tui * { box-sizing: border-box; }

/* --- panel: a 1px rule with its name cut into the top border --- */
.panel {
  position: relative;
  background: var(--bg-panel);
  border: 1px solid var(--line-idle);
  padding: 18px 16px 14px;
}
.panel > .panel-title {
  position: absolute;
  top: -10px;
  left: 14px;
  margin: 0;
  padding: 0 6px;
  /* Matches the panel's own fill so the rule is cut, not overlaid. */
  background: var(--bg-panel);
  font: var(--t-title);
  letter-spacing: var(--ls-title);
  text-transform: uppercase;
  color: var(--acc-green);
}
.panel.is-active { border-color: var(--line-active); }
.panel.is-selected { background: var(--bg-select); border-color: var(--line-active); }
.panel.is-selected > .panel-title { background: var(--bg-select); }
.panel.is-quiet > .panel-title { color: var(--ink-dim); }
.panel.is-warn { border-color: var(--acc-amber); }
.panel.is-warn > .panel-title { color: var(--acc-amber); }
.panel.is-bad { border-color: var(--acc-red); }
.panel.is-bad > .panel-title { color: var(--acc-red); }

/* --- controls --- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: 0;
  background: none;
  padding: 4px 0;
  font: var(--t-body);
  color: var(--acc-green);
  text-decoration: none;
  cursor: pointer;
}
.btn::before { content: "[ "; }
.btn::after { content: " ]"; }
.btn:disabled,
.btn.is-disabled { color: var(--ink-dim); cursor: default; }
.btn.is-danger { color: var(--acc-red); }
.btn.is-warn { color: var(--acc-amber); }
/* The one action the Enter key would take. Inverse video, no brackets. */
.btn.is-primary {
  background: var(--bg-inverse);
  color: var(--ink-inverse);
  font: var(--t-body-bold);
  padding: 6px 14px;
}
.btn.is-primary::before,
.btn.is-primary::after { content: ""; }
.btn.is-primary:disabled { background: var(--bg-raised); color: var(--ink-dim); }
.btn.is-block { display: flex; width: 100%; padding-block: 10px; }
.btn.is-boxed { border: 1px solid var(--line-idle); padding: 8px 12px; }
.btn.is-boxed::before,
.btn.is-boxed::after { content: ""; }

/* --- tabs and chips: selection is inverse video --- */
.tab,
.chip {
  border: 0;
  background: none;
  font: var(--t-body);
  color: var(--ink-base);
  padding: 4px 12px;
  cursor: pointer;
}
.tab.is-on {
  background: var(--bg-inverse);
  color: var(--ink-inverse);
  font: var(--t-body-bold);
}
.chip {
  font: var(--t-small);
  padding: 2px 9px;
  border: 1px solid var(--line-idle);
  color: var(--ink-dim);
}
.chip.is-on {
  background: var(--bg-inverse);
  border-color: var(--bg-inverse);
  color: var(--ink-inverse);
  font: var(--t-small-bold);
}

/* --- fields --- */
.field {
  width: 100%;
  background: var(--bg-base);
  border: 1px solid var(--line-idle);
  color: var(--ink-bright);
  font: var(--t-body);
  padding: 7px 10px;
}
.field::placeholder { color: var(--ink-dim); }
.field:focus { outline: none; border-color: var(--line-active); }
.field.is-bad { border-color: var(--acc-red); }

/* --- status bar --- */
.statusbar {
  display: flex;
  align-items: center;
  gap: 18px;
  background: var(--bg-panel);
  border-top: 1px solid var(--line-idle);
  padding: 7px 20px;
}
.statusbar .keys,
.statusbar .health { display: flex; align-items: center; gap: 16px; }
.hint { display: inline-flex; align-items: center; gap: 5px; }
.kbd { font: var(--t-key); letter-spacing: var(--ls-key); color: var(--acc-green); }
.kbd-label { font: var(--t-key); letter-spacing: var(--ls-key); color: var(--ink-dim); }

/* --- odds and ends --- */
.dot { color: var(--acc-green); }
.dot.is-warn { color: var(--acc-amber); }
.dot.is-bad { color: var(--acc-red); }
.dot.is-idle { color: var(--ink-dim); }
.meter { font: var(--t-body); color: var(--acc-green); letter-spacing: 0; }
.meter.is-cyan { color: var(--acc-cyan); }
.meter.is-idle { color: var(--ink-dim); }
.key-label {
  font: var(--t-key);
  letter-spacing: var(--ls-key);
  text-transform: uppercase;
  color: var(--ink-dim);
}
.quiet { color: var(--ink-dim); }
.fine { font: var(--t-small); letter-spacing: var(--ls-small); color: var(--ink-dim); }
.bright { color: var(--ink-bright); }
.spacer { flex: 1 1 auto; }
.rule { color: var(--line-idle); user-select: none; }

/* The theme control: reports the mode in force and advances it when pressed. */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--line-idle);
  background: none;
  padding: 1px 8px;
  cursor: pointer;
}
.theme-toggle .glyph { color: var(--acc-green); font: var(--t-body); }
.theme-toggle .label { font: var(--t-key); letter-spacing: var(--ls-key); color: var(--ink-base); }

/* A three-way segmented control, where there is room to state all of it. */
.segmented { display: flex; border: 1px solid var(--line-idle); }
.segmented button {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: 0;
  background: none;
  padding: 8px 10px;
  font: var(--t-small-bold);
  color: var(--ink-base);
  cursor: pointer;
}
.segmented button + button { border-left: 1px solid var(--line-idle); }
.segmented button .glyph { color: var(--acc-green); }
.segmented button[aria-pressed="true"] { background: var(--bg-inverse); color: var(--ink-inverse); }
.segmented button[aria-pressed="true"] .glyph { color: var(--ink-inverse); }

@media (prefers-reduced-motion: no-preference) {
  .blink { animation: tui-blink 1.06s steps(1, end) infinite; }
  @keyframes tui-blink { 50% { opacity: 0; } }
}
