/* styles.css — the Access-gated relay console (bifrost/dashboard/).
 *
 * The block between the two "=== TOKENS ===" markers is BYTE-IDENTICAL to
 * dashboard/app/tokens.css (the local console's token sheet). The two consoles are
 * deployed separately — this one is staged into dashboard/dist by `npm run build:dashboard`,
 * which copies exactly index.html, app.js and styles.css — so the tokens are copied here,
 * not imported. To update: edit dashboard/app/tokens.css, then paste it between the two
 * marker comment lines below (a `diff` of that block against tokens.css must be empty).
 *
 * Below the tokens: the relay console's own rules, in the family idioms — badge (deep text
 * on a tint; "Live" is a strip with the breathing dot, never a badge), receipts, a paper
 * table, the trust footer as a card floater. Idle is still; nothing spins.
 */
/* === TOKENS START === */
/* tokens.css — the Convers design tokens for the two web consoles
 * (docs/60-design-system.md §2 colour, §3 type, §4 ladders, §6 motion).
 *
 * Names match the Swift files in heimdall/Sources/HeimdallApp/Design/ (ValhallaColor,
 * PortalTint, ValhallaMetrics, ValhallaShadow, ValhallaMotion) with kebab-case:
 * `--ink-secondary`, `--warning-deep`, `--tint-slate-mark`, `--r-card`, `--lift1`, `--tick`.
 *
 * Light values sit on :root. Dark values are set twice on purpose — once under
 * prefers-color-scheme (guarded so an explicit data-theme="light" wins) and once under
 * [data-theme="dark"] so the console's toggle wins in both directions.
 *
 * SHARED FILE: this sheet is byte-identical to the token block at the head of
 * bifrost/dashboard/styles.css. The two consoles are deployed separately (this one from
 * dashboard/app/, that one from bifrost/dashboard/dist/), so the block is copied, not
 * imported. Edit it here, then copy it there (see the header of that file).
 *
 * Rules the values encode: violet (`--accent`) is a verb — a dot, a rail marker, a live
 * fill — never text and never a button; `--ink-tertiary` is non-text only (2.4:1 on paper);
 * text on a status tint uses the `-deep` variant; portal tints never touch text.
 */
:root{
  color-scheme:light dark;

  /* surfaces */
  --canvas:#F2F0EA; --paper:#FAF9F6; --card:#F6F4EE; --well:#FFFFFF;
  --scrim:rgba(31,29,25,.32);

  /* ink */
  --ink:#1F1D19; --ink-inverse:#FAF9F6; --ink-secondary:#6F6B62; --ink-tertiary:#A8A399;

  /* lines and interaction surfaces */
  --hairline:#E6E3DA; --hairline-strong:#D8D5CB; --pill:#EAE7DE; --pill-hover:#E2DFD4;
  --row-hover:rgba(31,29,25,.05); --row-selected:var(--well);
  --selected-tint:rgba(31,29,25,.055); --focus-ring:rgba(31,29,25,.35);

  /* accent + status: solids, 14% tints, `deep` text-on-tint */
  --accent:#6C57D2; --success:#4F7D51; --warning:#A6742C; --danger:#B5483C;
  --accent-tint:rgba(108,87,210,.14); --success-tint:rgba(79,125,81,.14);
  --warning-tint:rgba(166,116,44,.14); --danger-tint:rgba(181,72,60,.14);
  --success-deep:#3B6140; --warning-deep:#7A5520; --danger-deep:#8E3529;

  /* portal tints: mark = glyph / initial only, wash = fill (mark @ .18 over canvas) */
  --tint-slate-mark:#3F5F8F;    --tint-slate-wash:#D2D6DA;
  --tint-petrol-mark:#2E7A96;   --tint-petrol-wash:#CFDBDB;
  --tint-teal-mark:#2F7C6A;     --tint-teal-wash:#CFDBD3;
  --tint-moss-mark:#6E7A3E;     --tint-moss-wash:#DADBCB;
  --tint-rose-mark:#B14F6E;     --tint-rose-wash:#E6D3D4;
  --tint-plum-mark:#8A4F86;     --tint-plum-wash:#DFD3D8;
  --tint-graphite-mark:#6F6B62; --tint-graphite-wash:#DAD8D1;

  /* radii ladder */
  --r-dialog:20px; --r-panel:16px; --r-card:12px; --r-tile:10px; --r-ctl:9px;
  --r-pill:8px; --r-keycap:7px; --r-chip:6px; --r-badge:999px;

  /* spacing ladder (4 pt base) */
  --s2:2px; --s4:4px; --s6:6px; --s8:8px; --s12:12px; --s16:16px; --s20:20px; --s24:24px; --s32:32px; --s40:40px;

  /* metrics */
  --avatar:28px; --tile:36px; --tile-compact:28px; --dot:6px; --job-row:52px; --touch-row:32px; --badge-h:16px;

  /* shadows — a lift is the shadow plus the caller's own 1px hairline */
  --lift1:0 1px 2px rgba(31,29,25,.08); --lift2:0 2px 8px rgba(31,29,25,.06); --overlay:0 12px 32px rgba(31,29,25,.18);

  /* motion */
  --ack:120ms; --tick:250ms; --enter:300ms; --toast-out:160ms; --breathe:1.6s; --ease:cubic-bezier(.2,0,0,1);

  /* type — serif for identity moments, sans for work, mono for anything literal */
  --serif:"Fraunces",ui-serif,"New York","Iowan Old Style",Georgia,serif;
  --sans:-apple-system,BlinkMacSystemFont,"SF Pro Text","Segoe UI",Inter,system-ui,sans-serif;
  --mono:ui-monospace,"SF Mono","IBM Plex Mono",Menlo,monospace;
}

@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --canvas:#211F1D; --paper:#282623; --card:#302E2A; --well:#3A3733; --scrim:rgba(0,0,0,.48);
    --ink:#EDEBE4; --ink-inverse:#211F1D; --ink-secondary:#A39F96; --ink-tertiary:#75716A;
    --hairline:#413E38; --hairline-strong:#4E4A43; --pill:#3B3833; --pill-hover:#44403A;
    --row-hover:rgba(237,235,228,.06); --selected-tint:rgba(237,235,228,.08); --focus-ring:rgba(237,235,228,.45);
    --accent:#9C8CF0; --success:#8FBF92; --warning:#D9A85C; --danger:#E08074;
    --accent-tint:rgba(156,140,240,.14); --success-tint:rgba(143,191,146,.14);
    --warning-tint:rgba(217,168,92,.14); --danger-tint:rgba(224,128,116,.14);
    --success-deep:#8FBF92; --warning-deep:#D9A85C; --danger-deep:#EDA59C;
    --tint-slate-mark:#8FA9D6;    --tint-slate-wash:#33353B;
    --tint-petrol-mark:#7FB5CC;   --tint-petrol-wash:#303739;
    --tint-teal-mark:#7FBBA9;     --tint-teal-wash:#303833;
    --tint-moss-mark:#B1BC7C;     --tint-moss-wash:#38382C;
    --tint-rose-mark:#D68DA5;     --tint-rose-wash:#3E3133;
    --tint-plum-mark:#C49BC0;     --tint-plum-wash:#3B3337;
    --tint-graphite-mark:#A39F96; --tint-graphite-wash:#363330;
    --lift1:0 1px 2px rgba(0,0,0,.35); --lift2:0 2px 8px rgba(0,0,0,.40); --overlay:0 12px 32px rgba(0,0,0,.55);
  }
}
:root[data-theme="dark"]{
  --canvas:#211F1D; --paper:#282623; --card:#302E2A; --well:#3A3733; --scrim:rgba(0,0,0,.48);
  --ink:#EDEBE4; --ink-inverse:#211F1D; --ink-secondary:#A39F96; --ink-tertiary:#75716A;
  --hairline:#413E38; --hairline-strong:#4E4A43; --pill:#3B3833; --pill-hover:#44403A;
  --row-hover:rgba(237,235,228,.06); --selected-tint:rgba(237,235,228,.08); --focus-ring:rgba(237,235,228,.45);
  --accent:#9C8CF0; --success:#8FBF92; --warning:#D9A85C; --danger:#E08074;
  --accent-tint:rgba(156,140,240,.14); --success-tint:rgba(143,191,146,.14);
  --warning-tint:rgba(217,168,92,.14); --danger-tint:rgba(224,128,116,.14);
  --success-deep:#8FBF92; --warning-deep:#D9A85C; --danger-deep:#EDA59C;
  --tint-slate-mark:#8FA9D6;    --tint-slate-wash:#33353B;
  --tint-petrol-mark:#7FB5CC;   --tint-petrol-wash:#303739;
  --tint-teal-mark:#7FBBA9;     --tint-teal-wash:#303833;
  --tint-moss-mark:#B1BC7C;     --tint-moss-wash:#38382C;
  --tint-rose-mark:#D68DA5;     --tint-rose-wash:#3E3133;
  --tint-plum-mark:#C49BC0;     --tint-plum-wash:#3B3337;
  --tint-graphite-mark:#A39F96; --tint-graphite-wash:#363330;
  --lift1:0 1px 2px rgba(0,0,0,.35); --lift2:0 2px 8px rgba(0,0,0,.40); --overlay:0 12px 32px rgba(0,0,0,.55);
}

/* Portal tint on an element: `data-tint="slate"` sets --mark / --wash for its subtree. */
[data-tint="slate"]{--mark:var(--tint-slate-mark); --wash:var(--tint-slate-wash)}
[data-tint="petrol"]{--mark:var(--tint-petrol-mark); --wash:var(--tint-petrol-wash)}
[data-tint="teal"]{--mark:var(--tint-teal-mark); --wash:var(--tint-teal-wash)}
[data-tint="moss"]{--mark:var(--tint-moss-mark); --wash:var(--tint-moss-wash)}
[data-tint="rose"]{--mark:var(--tint-rose-mark); --wash:var(--tint-rose-wash)}
[data-tint="plum"]{--mark:var(--tint-plum-mark); --wash:var(--tint-plum-wash)}
[data-tint="graphite"],[data-tint]{--mark:var(--mark,var(--tint-graphite-mark)); --wash:var(--wash,var(--tint-graphite-wash))}

/* The one loop in the family: the live dot breathes 0.45 ↔ 1.0 in opacity only.
 * Under Reduce Motion it freezes lit. Parked (warning) dots never blink. */
@keyframes valhalla-breathe{from{opacity:1}to{opacity:.45}}
.live-dot{
  display:inline-block; width:var(--dot); height:var(--dot); border-radius:50%; background:var(--accent);
  animation:valhalla-breathe var(--breathe) ease-in-out infinite alternate; flex:0 0 auto;
}
.still-dot{display:inline-block; width:var(--dot); height:var(--dot); border-radius:50%; background:var(--ink-tertiary); flex:0 0 auto}
.still-dot.warn{background:var(--warning)}
.still-dot.ok{background:var(--success)}
.still-dot.bad{background:var(--danger)}
@media (prefers-reduced-motion:reduce){
  .live-dot{animation:none}
  *{transition-duration:0s !important}
}
/* === TOKENS END === */

*{box-sizing:border-box}
html,body{margin:0; padding:0}
body{
  background:var(--canvas); color:var(--ink); font-family:var(--sans); font-size:14px; line-height:1.5;
  -webkit-font-smoothing:antialiased;
}
::selection{background:var(--pill); color:var(--ink)}
a{color:inherit}
button{font-family:inherit}
:focus-visible{outline:2px solid var(--focus-ring); outline-offset:2px; border-radius:var(--r-pill)}

.app-shell{max-width:960px; margin:0 auto; padding:0 var(--s20) 96px; min-height:100vh}

/* --- Header: serif wordmark, the tab pills (selected = the lifted white pill) --- */

.app-header{display:flex; align-items:center; justify-content:space-between; gap:var(--s16); padding:var(--s24) 0 var(--s20)}
.wordmark{font-family:var(--serif); font-size:19px; font-weight:600; letter-spacing:-.2px; display:flex; align-items:baseline; gap:var(--s8)}
.wordmark small{font-family:var(--sans); font-size:11px; font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--ink-secondary)}
nav.tabs{display:flex; gap:var(--s2)}
nav.tabs a{
  display:block; padding:5px var(--s12); border-radius:var(--r-pill); border:1px solid transparent; text-decoration:none;
  font-size:13px; color:var(--ink-secondary); transition:background var(--ack) var(--ease), color var(--ack) var(--ease);
}
nav.tabs a:hover{background:var(--row-hover); color:var(--ink)}
nav.tabs a.active{background:var(--row-selected); color:var(--ink); font-weight:500; border-color:var(--hairline); box-shadow:var(--lift1)}

/* --- Section labels, numerals, copy --- */

.section-label{font-size:11px; font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--ink-secondary); margin:0 0 var(--s12)}
.section-label a{text-decoration:none}
.section-label a:hover{color:var(--ink)}
.stat-numeral{font-family:var(--serif); font-size:28px; font-weight:400; letter-spacing:-.3px; line-height:1.2}
.copy{color:var(--ink-secondary); font-size:13px; max-width:60ch}

/* --- Panels and cards --- */

.panel{background:var(--paper); border:1px solid var(--hairline); border-radius:var(--r-panel); padding:var(--s20); margin-bottom:var(--s16)}
.card-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:var(--s12)}
.card{background:var(--card); border:1px solid var(--hairline); border-radius:var(--r-card); padding:var(--s12) var(--s16)}
.card-title{font-size:13px; font-weight:500; letter-spacing:-.1px; display:flex; align-items:center; gap:var(--s8)}
.card-meta{margin-top:var(--s4); font-family:var(--mono); font-size:11px; color:var(--ink-secondary)}

/* --- Dots: 6px; the live one breathes, the parked one never blinks --- */

.dot{display:inline-block; width:var(--dot); height:var(--dot); border-radius:50%; background:var(--ink-tertiary); flex:0 0 auto; vertical-align:middle}
.dot.live{background:var(--accent); animation:valhalla-breathe var(--breathe) ease-in-out infinite alternate}
.dot.ok{background:var(--success)}
.dot.warn{background:var(--warning)}
.dot.bad{background:var(--danger)}

/* --- Badge: capsule 16, 10px semibold, deep text on the state's tint --- */

.chip{
  display:inline-flex; align-items:center; gap:5px; height:var(--badge-h); min-width:var(--badge-h); padding:0 7px; margin-right:var(--s4);
  border-radius:var(--r-badge); background:var(--pill); color:var(--ink); font-size:10px; font-weight:600; letter-spacing:.02em;
  line-height:1; white-space:nowrap; vertical-align:middle;
}
.chip.state-queued::before{content:""; width:var(--dot); height:var(--dot); border-radius:50%; background:var(--ink-tertiary)}
.chip.state-running::before,.chip.state-delivered::before,.chip.job-running::before{
  content:""; width:var(--dot); height:var(--dot); border-radius:50%; background:var(--accent);
  animation:valhalla-breathe var(--breathe) ease-in-out infinite alternate;
}
.chip.state-awaiting_input,.chip.state-needs_human,.chip.state-awaiting_approval{background:var(--warning-tint); color:var(--warning-deep)}
.chip.state-done,.chip.job-done{background:var(--success-tint); color:var(--success-deep)}
.chip.state-failed,.chip.state-expired,.chip.job-failed{background:var(--danger-tint); color:var(--danger-deep)}
.chip.state-cancelled,.chip.job-mixed{background:var(--pill); color:var(--ink-secondary)}

/* --- The Mac's own job counters (Fleet) --- */

.job-stats{display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--s24); padding:var(--s12) 0 var(--s16); border-bottom:1px solid var(--hairline); margin-bottom:var(--s16)}
.job-stat-value{font-family:var(--serif); font-size:26px; line-height:1.1; color:var(--ink); display:flex; align-items:center; gap:var(--s8)}
.job-stat-value.live::after{content:""; width:var(--dot); height:var(--dot); border-radius:50%; background:var(--accent); animation:valhalla-breathe var(--breathe) ease-in-out infinite alternate}
.job-stat-label{font-size:11px; font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--ink-secondary)}
.job-stat-meta{margin-left:auto; font-family:var(--mono); font-size:11px; color:var(--ink-secondary)}

/* --- The open question: the ask row --- */

.open-ask{margin:var(--s12) 0; padding:var(--s12); border-radius:var(--r-card); background:var(--warning-tint)}
.open-ask .card-title{color:var(--ink)}

/* --- Table --- */

table{width:100%; border-collapse:collapse}
thead th{
  text-align:left; font-size:11px; font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--ink-secondary);
  padding:0 var(--s12) var(--s8); border-bottom:1px solid var(--hairline); white-space:nowrap;
}
tbody td{padding:10px var(--s12); border-bottom:1px solid var(--hairline); vertical-align:middle}
tbody tr:last-child td{border-bottom:none}
tbody tr.clickable{cursor:pointer; transition:background var(--ack) var(--ease)}
tbody tr.clickable:hover{background:var(--row-hover)}
.mono{font-family:var(--mono); font-size:12px; color:var(--ink-secondary)}
.intent-verb{font-weight:500; letter-spacing:-.1px}

/* --- Receipts (the trust product): one mono line on a card --- */

.receipt{
  font-family:var(--mono); font-size:12px; color:var(--ink-secondary); background:var(--card);
  border:1px solid var(--hairline); border-radius:var(--r-card); padding:var(--s8) var(--s12); margin:var(--s6) 0;
}
.receipt .redaction-tier{color:var(--success-deep); font-weight:600}
.receipt .redaction-tier.warn{color:var(--danger-deep)}
.receipt .mono{color:var(--ink)}

/* --- Masked values (inputs masked by default) --- */

.masked{font-family:var(--mono); letter-spacing:2px}
.reveal-toggle{
  border:none; background:none; color:var(--ink); font-size:11px; font-weight:600; letter-spacing:.04em; text-transform:uppercase;
  cursor:pointer; padding:0; margin-left:var(--s8); text-decoration:underline; text-underline-offset:2px;
}
.reveal-toggle:hover{color:var(--ink-secondary)}

/* --- Timeline: a 1px rail with 4px dots; notable events get the 6px ink dot --- */

.timeline{border-left:1px solid var(--hairline); margin:var(--s12) 0 0 var(--s6); padding-left:var(--s20)}
.timeline-event{position:relative; padding-bottom:var(--s16)}
.timeline-event::before{content:""; position:absolute; left:-23px; top:7px; width:4px; height:4px; border-radius:50%; background:var(--ink-tertiary)}
.timeline-event.notable::before{left:-24px; top:6px; width:var(--dot); height:var(--dot); background:var(--ink)}
.timeline-event.clickable{cursor:pointer; margin-left:calc(-1 * var(--s8)); padding-left:var(--s8); border-radius:var(--r-pill)}
.timeline-event.clickable:hover{background:var(--row-hover)}
.timeline-event.clickable::before{left:-31px}
.timeline-kind{font-size:12px; font-weight:600}
.timeline-ts{font-family:var(--mono); font-size:11px; color:var(--ink-secondary)}

/* --- Privacy page --- */

.privacy-columns{display:grid; grid-template-columns:1fr 1fr; gap:var(--s16)}
@media (max-width:640px){.privacy-columns{grid-template-columns:1fr}}
.privacy-list{list-style:none; margin:0; padding:0}
.privacy-list li{padding:10px 0; border-bottom:1px solid var(--hairline); font-size:13px}
.privacy-list li:last-child{border-bottom:none}
.privacy-heading{font-family:var(--serif); font-size:18px; font-weight:400; letter-spacing:-.1px; margin:0 0 var(--s4); color:var(--ink)}
.privacy-heading.leaves,.privacy-heading.never{color:var(--ink)}

/* --- Trust footer: the one floater, card + hairline + lift2 (the no-glass form) --- */

.trust-footer{position:fixed; left:0; right:0; bottom:0; display:flex; justify-content:center; padding:var(--s12) var(--s20) calc(var(--s12) + env(safe-area-inset-bottom)); pointer-events:none}
.trust-footer-pill{
  pointer-events:auto; background:var(--card); border:1px solid var(--hairline); box-shadow:var(--lift2); border-radius:var(--r-card);
  padding:var(--s8) var(--s16); font-size:12px; color:var(--ink-secondary); display:flex; align-items:center; gap:var(--s8);
}

/* --- Empty / loading / error states (no spinners, ever — "idle is still") --- */

.empty-state{font-family:var(--serif); font-size:17px; letter-spacing:-.1px; color:var(--ink); padding:var(--s24) 0; text-align:center; margin:0}
.error-banner{background:var(--danger-tint); border-radius:var(--r-card); padding:10px 14px; color:var(--danger-deep); font-size:13px; margin-bottom:var(--s16)}
