/* Hallmark · genre: modern-minimal · macrostructure: app (split-auth / workbench / form-card families)
 * theme: custom · vibe: "precise, engineered, clean-room calm, instant"
 * paper: oklch(97.5% 0.006 230) · accent: oklch(55% 0.19 235) · display: Space Grotesk · body: system
 * axes: light / geometric-sans / cool · designed-as-app · design-system: design.md
 * governing rule: subtraction wins — no ambient motion, no ornament that performs.
 * utility-family recomposed 2026-07-24 (hallmark redesign: .field /
 * .status-line / one-accent-per-card; see design.md § form/utility).
 *
 * SwitchDesk — the locked brand stylesheet (later·9; supersedes the
 * PR 4-B c5 utility skin). Hand-written; no framework. Light/dark via
 * prefers-color-scheme. Every color and font routes through :root
 * tokens — no inline values in templates.
 */

@font-face {
  font-family: "Space Grotesk";
  src: url("/static/fonts/space-grotesk-latin-wght.woff2") format("woff2-variations");
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Tell the UA the page follows its scheme, so form controls,
     scrollbars, and canvas defaults switch with the token swap. */
  color-scheme: light dark;

  --paper:        oklch(97.5% 0.006 230);
  --paper-2:      oklch(99.3% 0.003 230);
  --ink:          oklch(21% 0.012 235);
  --ink-2:        oklch(45% 0.012 235);
  --muted:        oklch(48% 0.014 235);
  --rule:         oklch(88.5% 0.009 230);
  --accent:       oklch(55% 0.19 235);
  --accent-hover: oklch(48% 0.19 238);
  --accent-ink:   oklch(98.5% 0.005 230);
  --focus:        oklch(55% 0.21 235);

  /* The auth brand rail + video surround stay dark in BOTH schemes. */
  --panel:        oklch(19% 0.020 238);
  --panel-ink:    oklch(93% 0.010 230);
  --panel-muted:  oklch(70% 0.015 233);
  --panel-grid:   oklch(93% 0.010 230 / 0.045);
  --stage:        oklch(17% 0.012 235);
  --stage-ink:    oklch(60% 0.020 235);

  --ok-bg:   oklch(95% 0.030 155); --ok-fg:   oklch(35% 0.09 155); --ok-rule:   oklch(85% 0.06 155);
  --err-bg:  oklch(95% 0.025 20);  --err-fg:  oklch(40% 0.13 25);  --err-rule:  oklch(85% 0.06 22);
  --warn-bg: oklch(96% 0.035 85);  --warn-fg: oklch(42% 0.09 80);  --warn-rule: oklch(87% 0.07 85);

  --shadow: 0 1px 3px oklch(20% 0.01 235 / 0.08);
  --radius: 6px;
  /* Outer split-auth surface only (design.md § spacing/shape:
     controls and cards stay 6px). */
  --radius-surface: 8px;

  --font-display: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper:        oklch(16% 0.012 235);
    --paper-2:      oklch(20.5% 0.013 235);
    --ink:          oklch(93% 0.008 230);
    --ink-2:        oklch(68% 0.010 232);
    --muted:        oklch(66% 0.012 232);
    --rule:         oklch(30% 0.013 235);
    --accent:       oklch(70% 0.15 235);
    --accent-hover: oklch(76% 0.14 233);
    --accent-ink:   oklch(15% 0.012 235);
    --focus:        oklch(74% 0.19 235);
    --panel:        oklch(14% 0.035 238);
    --stage:        oklch(11% 0.010 235);
    --ok-bg:   oklch(28% 0.045 155); --ok-fg:   oklch(85% 0.07 155); --ok-rule:   oklch(38% 0.06 155);
    --err-bg:  oklch(27% 0.045 20);  --err-fg:  oklch(84% 0.07 22);  --err-rule:  oklch(38% 0.07 22);
    --warn-bg: oklch(29% 0.045 85);  --warn-fg: oklch(86% 0.08 85);  --warn-rule: oklch(40% 0.07 85);
    --shadow: none;
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* ---- chrome ---- */

.site-header {
  padding: 14px 22px;
  border-bottom: 1px solid var(--rule);
  background: var(--paper-2);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.site-logo {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 17px;
  color: var(--ink);
  text-decoration: none;
  letter-spacing: -0.02em;
  display: flex;
  align-items: center;
  gap: 9px;
}

/* The brand's only mark: the accent square. */
.site-logo::before {
  content: "";
  width: 11px;
  height: 11px;
  border-radius: 3px;
  background: var(--accent);
  flex: none;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 18px;
  font-size: 13.5px;
  font-family: var(--font-display);
  font-weight: 500;
}

.site-nav a { color: var(--ink-2); white-space: nowrap; }
.site-nav a:hover { color: var(--ink); text-decoration: none; }

.site-nav a.is-current {
  color: var(--ink);
  border-bottom: 2px solid var(--accent);
  padding-bottom: 2px;
}

/* The balance chip: ambient money awareness on every app page
   (balance-awareness stage 2). Mono like all money; links to /topup. */
.site-nav a.nav-balance {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12.5px;
  padding: 3px 10px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  color: var(--ink);
}

.site-nav a.nav-balance:hover {
  border-color: var(--accent);
  color: var(--ink);
  text-decoration: none;
}

.site-main {
  flex: 1;
  padding: 48px 24px;
  display: flex;
  justify-content: center;
  align-items: flex-start;
}

.site-footer {
  padding: 12px 22px;
  border-top: 1px solid var(--rule);
  background: var(--paper-2);
  color: var(--muted);
  font-size: 12.5px;
  text-align: center;
}

.site-footer p { margin: 0; }

/* ---- surfaces ---- */

.card {
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 30px;
  width: 100%;
  max-width: 420px;
}

.card h1 {
  margin: 0 0 22px;
  font-family: var(--font-display);
  font-size: 23px;
  font-weight: 700;
  letter-spacing: -0.025em;
}

/* ---- forms ---- */

form { display: flex; flex-direction: column; gap: 16px; }

label {
  display: flex;
  flex-direction: column;
  font-family: var(--font-display);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--ink-2);
  gap: 6px;
}

input[type="email"],
input[type="password"],
input[type="text"],
input[type="number"] {
  font: inherit;
  font-family: var(--font-body);
  /* 16px floor: iOS Safari zooms the viewport on focus below it. */
  font-size: 16px;
  padding: 10px 12px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  /* Transparent (not none): forced-colors mode paints it, so the
     focus ring survives Windows High Contrast. */
  outline: 2px solid transparent;
  outline-offset: 1px;
  /* border-color only: the focus ring below must appear instantly. */
  transition: border-color 0.15s ease;
}

input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--focus) 26%, transparent);
}

button {
  font-family: var(--font-display);
  font-size: 14.5px;
  font-weight: 500;
  letter-spacing: 0.005em;
  padding: 10px 18px;
  border: none;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-ink);
  cursor: pointer;
  transition: background-color 0.15s ease;
}

button:hover { background: var(--accent-hover); }

button:active { transform: translateY(1px); }

button:disabled {
  opacity: 0.55;
  pointer-events: none;
}

button.button-secondary {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--rule);
}

button.button-secondary:hover {
  background: var(--paper);
  border-color: var(--ink-2);
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover { text-decoration: underline; }

/* Keyboard focus: visible instantly, on everything clickable. */
button:focus-visible,
a:focus-visible,
a.button-link:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

a.button-link {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 14.5px;
  font-weight: 500;
  padding: 10px 18px;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-ink);
  text-decoration: none;
  transition: background-color 0.15s ease;
}

a.button-link:hover {
  background: var(--accent-hover);
  text-decoration: none;
}

/* ---- text utilities ---- */

.muted {
  color: var(--muted);
  font-size: 13.5px;
  margin-top: 16px;
  text-align: center;
}

.hint {
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 400;
  font-family: var(--font-body);
  letter-spacing: 0;
}

.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ---- banners + badges ---- */

.banner {
  padding: 11px 14px;
  border-radius: var(--radius);
  margin-bottom: 14px;
  font-size: 13.5px;
  border: 1px solid transparent;
}

.banner-success { background: var(--ok-bg); color: var(--ok-fg); border-color: var(--ok-rule); }
.banner-error { background: var(--err-bg); color: var(--err-fg); border-color: var(--err-rule); }
.banner-warn { background: var(--warn-bg); color: var(--warn-fg); border-color: var(--warn-rule); }

/* Links inside banners inherit the banner voice: the semantic fg
   tokens carry the contrast the accent can't on tinted grounds, and
   the underline is the non-color affordance. */
.banner a { color: inherit; text-decoration: underline; }

.badge {
  font-family: var(--font-display);
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-left: 6px;
}

.badge-ok { background: var(--ok-bg); color: var(--ok-fg); border: 1px solid var(--ok-rule); }
.badge-warn { background: var(--warn-bg); color: var(--warn-fg); border: 1px solid var(--warn-rule); }
.badge-error { background: var(--err-bg); color: var(--err-fg); border: 1px solid var(--err-rule); }

/* ---- auth: chromeless split (design.md · auth family) ---- */

.auth {
  display: grid;
  grid-template-columns: 5fr 6fr;
  width: 100%;
  max-width: 900px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-surface);
  overflow: hidden;
  background: var(--paper-2);
  box-shadow: var(--shadow);
  align-self: center;
  margin: auto 0;
}

.auth-rail {
  background-color: var(--panel);
  /* material: film grain over a precision grid, both whisper-quiet */
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E"),
    linear-gradient(var(--panel-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--panel-grid) 1px, transparent 1px);
  background-size: 140px 140px, 28px 28px, 28px 28px;
  color: var(--panel-ink);
  padding: 34px 32px;
  display: flex;
  flex-direction: column;
  min-height: 430px;
}

.auth-rail .site-logo { color: var(--panel-ink); font-size: 18px; }

/* The rail headline is a <p>, not a heading: the form's h1 must stay
   the page's first heading (screen-reader heading order). */
.auth-rail .rail-headline {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.035em;
  font-size: clamp(32px, 4vw, 41px);
  line-height: 1.08;
  margin: 40px 0 0;
}

.auth-rail .rail-headline .soft { color: var(--panel-muted); }

.auth-form { padding: 36px 34px; align-self: center; width: 100%; }

.auth-form h1 {
  margin: 0 0 22px;
  font-family: var(--font-display);
  font-size: 23px;
  font-weight: 700;
  letter-spacing: -0.025em;
}

/* True facts at the decision point — never in the rail. */
.form-fact {
  color: var(--muted);
  font-size: 12.5px;
  text-align: center;
  margin: 14px 0 0;
  font-family: var(--font-mono);
}

@media (max-width: 760px) {
  .auth { grid-template-columns: 1fr; }
  .auth-rail { min-height: 0; }
  .auth-rail .rail-headline { margin-top: 20px; }
}

/* ---- session: workbench (design.md · app family) ---- */

.wb {
  width: 100%;
  max-width: 1240px;
}

.wb-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 2px 2px 14px;
  flex-wrap: wrap;
}

.wb-bar h1 {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
}

.wb-bar .sep { width: 1px; height: 22px; background: var(--rule); }

.session-status {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 13.5px;
  color: var(--ink-2);
  margin-right: auto;
}

.session-status .badge { margin-left: 0; }

.session-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.wb-stage { position: relative; }

#session-desktop {
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--stage);
  border: 1px solid var(--rule);
  border-radius: 8px;
  display: block;
}

/* The stage renders in every state: placeholder text until the
 * stream exists (the video keeps its box; only the copy swaps). */
.stage-idle {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--stage-ink);
  font-family: var(--font-mono);
  font-size: 13px;
  pointer-events: none;
}

.stage-idle .t {
  font-family: var(--font-display);
  font-size: 14.5px;
  font-weight: 500;
  color: var(--panel-muted);
}

.wb-stage:has(#session-desktop:not([hidden])) .stage-idle { display: none; }

/* Keep the stage box visible pre-stream: the video carries the panel
 * even while hidden-from-JS, via the wrapper background. */
.wb-stage {
  background: var(--stage);
  border: 1px solid var(--rule);
  border-radius: 8px;
  min-height: 200px;
}

.wb-stage:has(#session-desktop[hidden]) { aspect-ratio: 16 / 9; }

.wb-stage #session-desktop { border: none; border-radius: 8px; }

#session-intro { text-align: left; margin: 0 2px 12px; }

.wb:has(#session-status[data-state="live"]) #session-intro { display: none; }

/* Advisory desks-free line: a true fact at the Start decision point.
 * session.js owns its visibility (hidden flag) — shown only while no
 * session is active. */
.wb-avail {
  color: var(--muted);
  font-size: 13.5px;
  margin: 0 2px 12px;
}

.wb-hint {
  display: none;
  color: var(--muted);
  font-size: 13px;
  margin: 10px 2px 0;
}

.wb:has(#session-status[data-state="live"]) .wb-hint { display: block; }

/* ---- fullscreen mode (immersion increment; bench-gated) ---- */

/* The ONE surface allowed over the desk: the low-balance warning
   floats at the stage's bottom edge in BOTH modes. It lives inside
   the stage element because nothing outside the fullscreened element
   can render in fullscreen. */
.wb-stage #session-warning {
  position: absolute;
  left: 50%;
  bottom: 16px;
  transform: translateX(-50%);
  z-index: 3;
  margin: 0;
  max-width: min(92%, 560px);
  width: max-content;
}

/* Local cursor overlay (Option A prototype): painted by session.js
   via transform; never intercepts input. No display override here —
   the hidden attribute must keep working (the #session-desktop
   lesson). */
.stage-cursor {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 4;
  pointer-events: none;
  will-change: transform;
  line-height: 0;
}

/* Zero chrome in fullscreen: the desk on true black, letterboxed
   honestly (contain, never crop). */
.wb-stage:fullscreen {
  border: none;
  border-radius: 0;
  background: #000;
}

.wb-stage:fullscreen #session-desktop {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  border-radius: 0;
  object-fit: contain;
}

#session-preview:not([hidden]) {
  display: block;
  width: 100%;
  max-width: 320px;
  margin-top: 12px;
  border-radius: var(--radius);
  background: var(--stage);
  aspect-ratio: 16 / 9;
  object-fit: cover;
  /* Self-view mirror (later·12, matches the SBC-side flip): display
   * only — the transmitted stream stays true orientation, so the SBC's
   * single flip is never doubled. Never mirror #session-desktop. */
  transform: scaleX(-1);
}

/* ---- utility-card family (design.md · recomposed 2026-07-24) ----
   The composition rules that replaced the accreted account/topup
   layout (hallmark redesign, decisions.md 2026-07-24 s3 addendum 3):
   ONE left axis (every group is label-over-value); ONE accent control
   per card; status whispers with its remedy inline; spacing does the
   grouping (28px between fields, a single rule before the sign-out
   zone). The retired .stat/.kv/.account-actions/.resend-form rows
   live in git history. */

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 0 0 28px;
}

.field:last-of-type { margin-bottom: 0; }

.field-label {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink-2);
  text-transform: uppercase;
}

.field-value { font-size: 15px; overflow-wrap: anywhere; }

.field-value-money {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 32px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.15;
}

/* Actions belonging to a field: one row, content-width controls
   (proceed/retreat pairs wrap gracefully at narrow widths). */
.field-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 10px;
}

.field-actions form { margin: 0; flex-direction: row; }

/* Quiet status: a semantic dot + one sentence, remedy inline. */
.status-line {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  color: var(--muted);
  margin: 2px 0 0;
}

.status-line::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 999px;
  flex: none;
}

.status-ok::before { background: var(--ok-fg); }
.status-warn::before { background: var(--warn-fg); }
.status-line form { display: inline; margin: 0; }

/* Inline link-voice action — row-level remedies (resend email,
   manage billing). Deliberately styled as a link: it lives inside a
   sentence or beside the card's one accent control. */
button.button-inline {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--accent);
  cursor: pointer;
  border-radius: 2px;
}

button.button-inline:hover { text-decoration: underline; background: none; }
button.button-inline:active { transform: none; }

/* Zone-level secondary (Sign out): compact, content width, never a
   full-width slab. */
.card form.zone-form { flex-direction: row; }

button.button-compact {
  background: transparent;
  color: var(--ink-2);
  border: 1px solid var(--rule);
  font-size: 12px;
  padding: 5px 12px;
  letter-spacing: 0.02em;
  align-self: flex-start;
}

button.button-compact:hover {
  background: var(--paper);
  border-color: var(--ink-2);
  color: var(--ink);
}

.hr {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 20px 0;
}

/* The single rule a utility card keeps, above the sign-out zone. */
.hr-zone { margin: 28px 0 18px; }

/* Utility cards read on one left axis; the auth pages keep their own
   centered .muted convention (they don't use .card). */
.card .muted { text-align: left; }

/* ---- topup (redesigned 2026-07-24: chips set the input in place,
   money reads mono, and the two hint paragraphs collapsed into one
   live dollars→minutes support line — the decision fact, not the
   rulebook) ---- */

.chip-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

button.chip {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  font-weight: 600;
  padding: 6px 14px;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-2);
  border: 1px solid var(--rule);
  transition: border-color 0.15s ease, color 0.15s ease;
}

button.chip:hover {
  background: var(--paper);
  border-color: var(--ink-2);
  color: var(--ink);
}

button.chip[aria-pressed="true"] {
  border-color: var(--accent);
  color: var(--ink);
}

.amount-wrap {
  position: relative;
  display: block;
}

.amount-wrap::before {
  content: "$";
  position: absolute;
  left: 13px;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: 17px;
  color: var(--ink-2);
  pointer-events: none;
}

.amount-wrap input {
  width: 100%;
  padding-left: 30px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 17px;
  appearance: textfield;
  -moz-appearance: textfield;
}

.amount-wrap input::-webkit-outer-spin-button,
.amount-wrap input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.support-line {
  color: var(--muted);
  font-size: 13px;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}
