/* Self-hosted fonts (Task 8): served from /app/static/fonts/, never an
   external origin -- the panel must make zero third-party network
   requests. font-display:swap avoids a blocked render on first paint. */
@font-face{font-family:"Inter";font-style:normal;font-weight:400;font-display:swap;src:url("fonts/inter-400.woff2") format("woff2")}
@font-face{font-family:"Inter";font-style:normal;font-weight:500;font-display:swap;src:url("fonts/inter-500.woff2") format("woff2")}
@font-face{font-family:"Inter";font-style:normal;font-weight:600;font-display:swap;src:url("fonts/inter-600.woff2") format("woff2")}
@font-face{font-family:"Inter";font-style:normal;font-weight:700;font-display:swap;src:url("fonts/inter-700.woff2") format("woff2")}
@font-face{font-family:"Inter";font-style:normal;font-weight:800;font-display:swap;src:url("fonts/inter-800.woff2") format("woff2")}
@font-face{font-family:"Inter";font-style:normal;font-weight:900;font-display:swap;src:url("fonts/inter-900.woff2") format("woff2")}
@font-face{font-family:"JetBrains Mono";font-style:normal;font-weight:400;font-display:swap;src:url("fonts/jetbrains-mono-400.woff2") format("woff2")}
@font-face{font-family:"JetBrains Mono";font-style:normal;font-weight:500;font-display:swap;src:url("fonts/jetbrains-mono-500.woff2") format("woff2")}
@font-face{font-family:"JetBrains Mono";font-style:normal;font-weight:600;font-display:swap;src:url("fonts/jetbrains-mono-600.woff2") format("woff2")}

:root{
  --bg-0:#050314; --bg-1:#0f0a1f; --bg-2:#1a0b3d; --bg-3:#0b1f3d;
  --purple:#a855f7; --purple-deep:#7c3aed; --cyan:#38bdf8; --cyan-deep:#0ea5e9;
  --text:#f8fafc; --text-dim:#cbd5e1; --text-faint:#94a3b8;
  --line:rgba(255,255,255,0.08); --line-strong:rgba(255,255,255,0.18);
  --card:rgba(255,255,255,0.025); --card-hover:rgba(255,255,255,0.05);
  /* Flight deck (Task 3): status colours must read independently of the
     purple/cyan brand accent, so these are new tokens, never aliases of
     --purple/--cyan. Values ported verbatim from the approved mockup
     (panel-directions.html). */
  --ok:#34d399; --warn:#fbbf24; --bad:#f87171;
}
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:Inter,system-ui,sans-serif;color:var(--text);background:var(--bg-0);line-height:1.6;-webkit-font-smoothing:antialiased;padding-bottom:72px}
.mono{font-family:"JetBrains Mono",monospace}
.bg-stage{position:fixed;inset:0;z-index:-1;background:
  radial-gradient(ellipse 80% 60% at 80% 0%,rgba(168,85,247,.25) 0%,transparent 50%),
  radial-gradient(ellipse 60% 50% at 0% 30%,rgba(14,165,233,.18) 0%,transparent 50%),
  radial-gradient(ellipse 70% 60% at 50% 100%,rgba(124,58,237,.15) 0%,transparent 50%),
  linear-gradient(180deg,#050314 0%,#0a0820 50%,#050314 100%)}
.bg-stage::before{content:"";position:absolute;inset:0;background-image:
  linear-gradient(rgba(255,255,255,.02) 1px,transparent 1px),
  linear-gradient(90deg,rgba(255,255,255,.02) 1px,transparent 1px);background-size:64px 64px}
#root{max-width:1280px;margin:0 auto;padding:20px 16px}
.card{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:16px;margin-bottom:12px}
nav{position:fixed;bottom:0;left:0;right:0;display:flex;background:rgba(5,3,20,.92);
  backdrop-filter:blur(12px);border-top:1px solid var(--line);padding-bottom:env(safe-area-inset-bottom)}
nav a{flex:1;text-align:center;padding:14px 0;color:var(--text-faint);font-size:13px;text-decoration:none;cursor:pointer}
nav a.active{color:var(--cyan)}
/* F1: logout lives in the same nav bar as the four view links but is a
   <button>, not an <a data-view> -- it performs an action, not a
   navigation. all:unset strips the generic `button{}` gradient styling
   below so it visually matches the nav a's it sits beside. */
nav button.nav-logout{all:unset;flex:1;text-align:center;padding:14px 0;color:var(--text-faint);font-size:13px;cursor:pointer;box-sizing:border-box}
nav button.nav-logout:hover{color:#fca5a5}
/* Systems: the deeper views (Deck, Traces, Evidence, Record, Brain, Models)
   collapse under one parent so the sidebar leads with the everyday ones
   (asked for 2026-08-18). The parent is a <button>, not an <a data-view>, so
   it toggles rather than navigates; app.js keeps it open while one of its
   views is active. */
nav .nav-group{display:flex;flex-direction:column;flex:1}
nav .nav-parent{all:unset;box-sizing:border-box;display:flex;align-items:center;justify-content:center;gap:8px;padding:14px 0;color:var(--text-faint);font-size:13px;cursor:pointer}
nav .nav-parent:hover,nav .nav-group.open .nav-parent{color:var(--text)}
nav .nav-chev{width:6px;height:6px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(-45deg);transition:transform .15s}
nav .nav-group.open .nav-chev{transform:rotate(45deg)}
nav .nav-sub{display:none}
nav .nav-group.open .nav-sub{display:flex;flex-direction:column}
nav .nav-sub a{flex:none}
@media(min-width:768px){
  body{padding-bottom:0;padding-left:200px}
  nav{top:0;bottom:0;right:auto;width:200px;flex-direction:column;border-top:0;border-right:1px solid var(--line);padding-top:24px}
  nav a{flex:none;text-align:left;padding:12px 24px}
  nav button.nav-logout{flex:none;text-align:left;padding:12px 24px;margin-top:auto;margin-bottom:24px}
  nav .nav-group{flex:none}
  nav .nav-parent{justify-content:space-between;padding:12px 24px}
  nav .nav-sub a{padding-left:40px;font-size:12px}
}
/* Below the sidebar breakpoint the bar is horizontal; the open sub-menu
   floats above its parent rather than stretching the bar. */
@media(max-width:767px){
  nav .nav-group{position:relative}
  nav .nav-sub{position:absolute;bottom:100%;left:0;min-width:160px;background:rgba(5,3,20,.98);border:1px solid var(--line);border-radius:10px 10px 0 0}
  nav .nav-sub a{text-align:left;padding:12px 16px}
}

h1{font-size:22px;font-weight:600;margin-bottom:12px}
h2{font-size:14px;font-weight:600;color:var(--text-dim);text-transform:uppercase;letter-spacing:.04em;margin-bottom:10px}
.dim{color:var(--text-faint);font-size:13px}
.loading{color:var(--text-faint);padding:24px 0;text-align:center}
.error{color:#fca5a5;margin-bottom:10px}

.row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 0;border-bottom:1px solid var(--line);font-size:13px}
.row:last-child{border-bottom:0}
.row.link{cursor:pointer;text-decoration:none;color:inherit}
.row.link:hover{color:var(--cyan)}
.ts{color:var(--text-faint);white-space:nowrap}

.badges{display:flex;flex-wrap:wrap;gap:8px}
.badge{display:inline-block;padding:4px 10px;border-radius:999px;font-size:11px;border:1px solid var(--line-strong);color:var(--text-dim)}
.badge.ok{color:#6ee7b7;border-color:rgba(110,231,183,.35)}
.badge.bad{color:#fca5a5;border-color:rgba(252,165,165,.35)}

.login-card{max-width:360px;margin:15vh auto 0}
.login-card form{display:flex;flex-direction:column;gap:12px;margin-top:12px}
.login-card label{display:flex;flex-direction:column;gap:6px;font-size:13px;color:var(--text-dim)}
.login-card label.checkbox{flex-direction:row;align-items:center;gap:8px}

/* Re-authentication card (reauthCardHTML in app.js): same field/heading
   styling as .login-card above, deliberately not sharing its class -- an
   inline step-up prompt (askStepUp, prepended atop existing content) must
   not inherit .login-card's full-page centring. .reauth-standalone opts
   back into that centring for the Branding entry gate, which replaces a
   whole view the same way the login screen does. */
.reauth-card form{display:flex;flex-direction:column;gap:12px;margin-top:12px}
.reauth-card label{display:flex;flex-direction:column;gap:6px;font-size:13px;color:var(--text-dim)}
.reauth-card.reauth-standalone{max-width:360px;margin:15vh auto 0}
.reauth-card .reauth-passkey{margin-top:8px}
input[type="password"],input[type="text"]{background:rgba(255,255,255,.04);border:1px solid var(--line-strong);
  border-radius:8px;padding:10px 12px;color:var(--text);font-size:15px}
input[type="password"]:focus,input[type="text"]:focus{outline:2px solid var(--cyan);outline-offset:1px}
button{background:linear-gradient(135deg,var(--purple-deep),var(--cyan-deep));border:0;border-radius:8px;
  color:#fff;padding:12px;font-size:14px;font-weight:600;cursor:pointer;margin-top:4px}
button.secondary{background:transparent;border:1px solid var(--line-strong);color:var(--text-dim);margin-top:12px;width:100%}
button:active{opacity:.85}

.degraded-banner{position:sticky;top:0;z-index:5;background:#7c2d12;color:#fed7aa;padding:10px 16px;font-size:12.5px;text-align:center;border-bottom:1px solid rgba(255,255,255,.15)}
/* Degraded state (Task 8): applied to <body> whenever the last /app/api
   read reported degraded:true. Disables every mutating control below --
   F1 built the write UI this rule was always the ready-made hook for. */
body.degraded [data-mutating]{pointer-events:none;opacity:.45;cursor:not-allowed}

.item-detail{margin-bottom:12px}
.item-path{color:var(--text-faint);margin-bottom:8px}
.item-body{white-space:pre-wrap;word-break:break-word;font-family:"JetBrains Mono",monospace;font-size:12.5px;
  line-height:1.5;max-height:60vh;overflow-y:auto}

/* F1: the write UI -- forms, per-row action buttons, inline status,
   inline step-up prompt. Mobile-first: stacked, full-width, large tap
   targets; row-buttons wrap on narrow screens rather than overflowing. */
form{display:flex;flex-direction:column;gap:10px}
form label{display:flex;flex-direction:column;gap:6px;font-size:13px;color:var(--text-dim)}
textarea,select{background:rgba(255,255,255,.04);border:1px solid var(--line-strong);border-radius:8px;
  padding:10px 12px;color:var(--text);font-size:15px;font-family:inherit}
textarea:focus,select:focus{outline:2px solid var(--cyan);outline-offset:1px}
textarea.item-edit{width:100%;min-height:180px;font-family:"JetBrains Mono",monospace;font-size:12.5px;resize:vertical}

.row-actions{flex-direction:column;align-items:stretch;gap:8px}
.row-main{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.row-buttons{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.row-buttons form{flex-direction:row}

button.chip{all:unset;box-sizing:border-box;padding:8px 14px;font-size:12.5px;font-weight:600;border-radius:999px;
  border:1px solid var(--line-strong);color:var(--text-dim);cursor:pointer;text-align:center}
button.chip.ok{color:#6ee7b7;border-color:rgba(110,231,183,.35)}
button.chip.warn{color:#fcd34d;border-color:rgba(252,211,77,.35)}
button.chip.bad{color:#fca5a5;border-color:rgba(252,165,165,.35)}
button.chip:active{opacity:.7}

.action-status{font-size:12px;color:var(--text-faint)}
.action-status.ok{color:#6ee7b7}
.action-status.bad{color:#fca5a5}

.cold-start p{margin-top:8px;line-height:1.5}

/* ===========================================================================
   Flight deck (Task 3): components consumed by renderDeck() in app.js.
   Ported from the approved mockup (panel-directions.html) verbatim except
   for token names, mapped onto the tokens already defined above:
     --dim -> --text-dim, --faint -> --text-faint, --bg -> --bg-0,
     --line-2 -> --line-strong (same role, pre-existing token).
   Additive only -- every rule here is new; nothing above is touched, so
   the Work/Brain/Agents screens (.card/.row) are unaffected.
   =========================================================================== */
.num{font-variant-numeric:tabular-nums}

/* ---------- top status strip ---------- */
/* Stand-alone here (no phone frame around the deck like the mockup had),
   so unlike the mockup's border-bottom-only strip this carries its own
   full border/radius/margin, matching how every other section below
   already stands alone. */
.strip{padding:11px 13px 10px;border:1px solid var(--line);border-radius:14px;margin-bottom:16px;
  background:linear-gradient(180deg,rgba(52,211,153,.09),transparent)}
.strip.bad{background:linear-gradient(180deg,rgba(248,113,113,.09),transparent)}
.strip-top{display:flex;align-items:center;gap:9px}
.pulse{width:9px;height:9px;border-radius:50%;background:var(--ok);flex:none}
.pulse.bad{background:var(--bad)}
.strip-top strong{font-size:14px;font-weight:700;letter-spacing:-.01em}
.strip-top .clock{margin-left:auto;font-family:"JetBrains Mono",monospace;font-size:11px;color:var(--text-dim)}
.strip-sub{display:flex;gap:12px;margin-top:7px;font-family:"JetBrains Mono",monospace;font-size:10px;color:var(--text-faint);letter-spacing:.04em}
.strip-sub b{color:var(--text-dim);font-weight:500}

/* vitals row */
.vitals{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;margin-top:9px}
.vital{text-align:center}
.vital .lbl{font-family:"JetBrains Mono",monospace;font-size:8.5px;letter-spacing:.11em;text-transform:uppercase;color:var(--text-faint)}
.vital .val{font-family:"JetBrains Mono",monospace;font-size:12px;font-weight:600;margin-top:1px;font-variant-numeric:tabular-nums}
.vbar{height:3px;border-radius:99px;background:rgba(255,255,255,.08);margin-top:4px;overflow:hidden}
.vbar i{display:block;height:100%;border-radius:99px;background:var(--cyan);transition:width .8s cubic-bezier(.2,.7,.3,1)}
.vbar i.hot{background:var(--warn)}
.vbar i.unknown{background:var(--text-faint)}

h3.sec{font-family:"JetBrains Mono",monospace;font-size:9.5px;letter-spacing:.15em;text-transform:uppercase;color:var(--text-faint);
  margin:16px 0 8px;display:flex;align-items:center;gap:8px}
h3.sec::after{content:"";flex:1;height:1px;background:var(--line)}

/* ---------- countdown ---------- */
.countdown{border:1px solid var(--line);border-radius:13px;padding:11px 13px;background:rgba(255,255,255,.022);
  display:flex;align-items:center;gap:12px}
.countdown .t{font-family:"JetBrains Mono",monospace;font-size:22px;font-weight:700;letter-spacing:-.01em;font-variant-numeric:tabular-nums;
  color:var(--cyan)}
.countdown .d{font-size:11.5px;color:var(--text-faint);line-height:1.4}
.countdown .d b{color:var(--text-dim);font-weight:600;display:block;font-size:12.5px}

/* ---------- agents (the crew) ---------- */
.agent{border:1px solid var(--line);border-radius:14px;padding:12px;margin-bottom:9px;background:rgba(255,255,255,.022);
  display:flex;gap:11px;align-items:flex-start;position:relative;overflow:hidden}
.agent.live{border-color:rgba(56,189,248,.34);background:linear-gradient(150deg,rgba(56,189,248,.10),rgba(255,255,255,.015))}
.agent.working::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(100deg,transparent 30%,rgba(56,189,248,.10) 50%,transparent 70%);
  background-size:220% 100%}
.ring{width:46px;height:46px;flex:none;border-radius:50%;display:grid;place-items:center;position:relative;
  background:rgba(255,255,255,.08)}
.ring b{width:36px;height:36px;border-radius:50%;background:var(--bg-1);display:grid;place-items:center;
  font-family:"JetBrains Mono",monospace;font-size:11px;font-weight:700;z-index:1}
.agent-main{min-width:0;flex:1}
.nm{font-weight:650;font-size:13.5px;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.sub{font-family:"JetBrains Mono",monospace;font-size:10px;color:var(--text-faint);margin-top:2px}
.doing{font-size:12px;color:var(--text-dim);margin-top:6px;padding-top:6px;border-top:1px dashed var(--line)}
.tier{font-family:"JetBrains Mono",monospace;font-size:8.5px;letter-spacing:.1em;text-transform:uppercase;padding:2px 6px;border-radius:99px;
  border:1px solid var(--line-strong);color:var(--text-faint)}
.tier.watch{color:var(--warn);border-color:rgba(251,191,36,.35)}
.tier.review{color:var(--cyan);border-color:rgba(56,189,248,.35)}
.tier.auto{color:var(--ok);border-color:rgba(52,211,153,.35)}
.toNext{height:3px;border-radius:99px;background:rgba(255,255,255,.07);margin-top:6px;overflow:hidden}
.toNext i{display:block;height:100%;background:var(--warn);border-radius:99px;transition:width 1.2s ease-out}

/* ---------- shared brain ---------- */
.brainbar{display:flex;height:10px;border-radius:99px;overflow:hidden;border:1px solid var(--line)}
.brainbar i{display:block;height:100%;transition:width 1s cubic-bezier(.2,.7,.3,1)}
.brainbar i.bar-safb{background:var(--purple)}
.brainbar i.bar-projects{background:var(--cyan)}
.brainbar i.bar-personal{background:var(--warn)}
.brainbar i.bar-user{background:var(--text-faint)}
.legend{display:flex;flex-wrap:wrap;gap:10px;margin-top:8px;font-size:10.5px;color:var(--text-faint)}
.legend span{display:flex;align-items:center;gap:5px}
.dot{width:7px;height:7px;border-radius:2px;display:inline-block}
.dot-safb{background:var(--purple)}
.dot-projects{background:var(--cyan)}
.dot-personal{background:var(--warn)}
.dot-user{background:var(--text-faint)}
.locked{font-size:11px;color:var(--text-faint);margin-top:7px;display:flex;align-items:center;gap:5px}

/* ---------- ticker (live feed) ---------- */
.ticker{border:1px solid var(--line);border-radius:12px;background:rgba(0,0,0,.28);overflow:hidden;max-height:180px;position:relative;overflow-y:auto}
.ticker-in{padding:9px 11px;font-family:"JetBrains Mono",monospace;font-size:10.5px;line-height:1.85}
.tick{display:flex;gap:8px;opacity:0;transform:translateY(6px);animation:deck-in .45s forwards}
.tick .tm{color:var(--text-faint);flex:none}
.tick .ag{color:var(--purple);flex:none}
.tick .tx{color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tick.ok .tx{color:var(--ok)}

/* ---------- spend ---------- */
.spend-card{border:1px solid var(--line);border-radius:13px;padding:12px;background:rgba(255,255,255,.022)}
.spend-row{display:flex;align-items:baseline;justify-content:space-between}
.spend-row .big{font-family:"JetBrains Mono",monospace;font-size:21px;font-weight:700;font-variant-numeric:tabular-nums}
.spend-row .cap{font-family:"JetBrains Mono",monospace;font-size:11px;color:var(--text-faint)}
.meter{height:5px;border-radius:99px;background:rgba(255,255,255,.08);margin-top:8px;overflow:hidden}
.meter i{display:block;height:100%;border-radius:99px;background:linear-gradient(90deg,var(--cyan-deep),var(--cyan));
  transition:width 1s ease-out}
.spark{display:flex;align-items:flex-end;gap:2px;height:26px;margin-top:9px}
.spark i{flex:1;background:linear-gradient(180deg,var(--purple),rgba(168,85,247,.25));border-radius:1px;
  transform-origin:bottom}
.spark-lbl{font-family:"JetBrains Mono",monospace;font-size:9px;color:var(--text-faint);letter-spacing:.1em;margin-top:5px;display:flex;justify-content:space-between}

@media (prefers-reduced-motion:no-preference){
  .pulse{animation:deck-beat 2.4s ease-in-out infinite}
  @keyframes deck-beat{0%,100%{box-shadow:0 0 0 4px rgba(52,211,153,.18)}50%{box-shadow:0 0 0 8px rgba(52,211,153,.04)}}
  .pulse.bad{animation:deck-beat-bad 2.4s ease-in-out infinite}
  @keyframes deck-beat-bad{0%,100%{box-shadow:0 0 0 4px rgba(248,113,113,.18)}50%{box-shadow:0 0 0 8px rgba(248,113,113,.04)}}
  .agent.working::after{animation:deck-sweep 2.6s linear infinite}
  @keyframes deck-sweep{from{background-position:120% 0}to{background-position:-120% 0}}
  @keyframes deck-in{to{opacity:1;transform:none}}
  .spark i{transform:scaleY(0);animation:deck-grow .6s cubic-bezier(.2,.7,.3,1) forwards}
  @keyframes deck-grow{to{transform:scaleY(1)}}
}
@media (prefers-reduced-motion:reduce){
  /* Final states only -- no animation, but bars/rings/ticks still land at
     their real (JS-set) widths/backgrounds since those are applied via
     element.style.* regardless of this media query; this block only
     neutralises the keyframe-driven entrance effects above. */
  .pulse,.pulse.bad{box-shadow:none}
  .agent.working::after{display:none}
  .spark i{transform:scaleY(1);animation:none}
  .tick{opacity:1;transform:none;animation:none}
}

/* --- Traces / waterfall ---------------------------------------------------
   A bar's LEFT is when the span started as a share of the trace, and its
   WIDTH is how long it ran. Both are set inline by app.js because they are
   data, not style. Status colours use the --ok/--bad deck tokens rather
   than the purple/cyan brand accent, so "this step failed" reads without
   knowing the palette. */
.trace{padding:14px 16px}
.trace-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-size:13px}
.trace-head .mono:first-child{color:var(--text);font-weight:600}
.trace-head .mono:last-child{margin-left:auto}
.trace-when{font-size:10px;letter-spacing:.08em;margin:2px 0 10px}

.waterfall{display:flex;flex-direction:column;gap:4px}
.span-row{display:grid;grid-template-columns:130px 1fr 56px;align-items:center;
  column-gap:10px;font-size:11px}
.span-name{color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.span-track{position:relative;height:14px;background:var(--card);
  border:1px solid var(--line);border-radius:3px;overflow:hidden}
.span-bar{position:absolute;top:0;bottom:0;border-radius:2px;min-width:2px;
  background:linear-gradient(90deg,var(--cyan),var(--cyan-deep))}
.span-bar.bad{background:linear-gradient(90deg,var(--bad),#b91c1c)}
.span-dur{text-align:right;color:var(--text-faint)}
/* The meta line sits under the bar, spanning the two right-hand columns, so
   a long model name never squeezes the track. */
.span-meta{grid-column:2 / 4;font-size:10px;margin:-1px 0 3px}

@media (max-width:620px){
  .span-row{grid-template-columns:92px 1fr 48px}
  .span-name{font-size:10px}
}

/* --- Console -------------------------------------------------------------
   The JARVIS grammar -- dark ground, concentric rings, a living centre --
   in the existing violet/cyan accent rather than the borrowed cyan-on-navy,
   so this reads as this product and not as fan art of another one.

   What that reference gets WRONG for us, and what is deliberately absent
   here: CPU, RAM, disk, weather, camera, uptime. Those are the machine's
   vitals. They are on that screen because it has nothing else to say. The
   panels here carry the business instead -- what needs a decision, what it
   cost, who is working. */

.c-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: 20rem minmax(0, 1fr) 23rem;
  align-items: start;
}
@media (max-width: 1180px) { .c-grid { grid-template-columns: 1fr; } }

.c-side { display: flex; flex-direction: column; gap: 16px; }
.c-card { margin: 0; }
.c-after { font-size: 12px; color: var(--text-faint); margin-top: 8px; line-height: 1.5; }
.c-none { color: var(--text-faint); font-size: 13px; }

/* the queue: the only block on this screen with verbs */
.c-queue { display: flex; flex-direction: column; gap: 9px; }
.c-q {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 10px 11px; border-radius: 9px;
  background: rgba(251, 191, 36, .06);
  border: 1px solid rgba(251, 191, 36, .2);
}
.c-n { font-size: 11px; color: var(--warn); flex: none; padding-top: 2px; }
.c-qbody { flex: 1; min-width: 0; }
.c-qbody p { margin: 0 0 8px; font-size: 13px; line-height: 1.45; color: var(--text); }

/* Not started. Deliberately NOT the amber of the queue: amber means there is
   something for you to judge, and these were refused before anything ran.
   Same shape, cooler colour -- it should read as a note, not an alarm, and
   it should not compete with the work actually waiting on a decision. */
.c-blocked .c-q {
  background: rgba(148, 163, 184, .07);
  border-color: rgba(148, 163, 184, .22);
}
.c-blocked .c-n { color: var(--text-faint); }
.c-why { margin: 0; font-size: 11px; }
.c-qfoot { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.c-qfoot .c-why { flex: 1; min-width: 0; }
.c-bin { flex: none; font-size: 11px; padding: 2px 10px; }
.c-bin:disabled { opacity: .6; cursor: default; }

/* Mail items. NOW is amber like the console queue -- it means the same thing
   there and here, something wants a person. SOON is deliberately quieter:
   this week is not this minute, and a screen where everything shouts is a
   screen nobody reads twice. */
.mi {
  padding: 11px 12px; border-radius: 9px; margin-bottom: 9px;
  background: rgba(148, 163, 184, .06);
  border: 1px solid rgba(148, 163, 184, .18);
}
.mi-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.mi-pri { font-size: 10px; letter-spacing: .08em; padding: 2px 6px; border-radius: 5px; }
.mi-pri.now { color: var(--warn); background: rgba(251, 191, 36, .12); }
.mi-pri.soon { color: var(--text-faint); background: rgba(148, 163, 184, .12); }
.mi-from { font-size: 13px; flex: 1 1 auto; min-width: 0; }
.mi-when { font-size: 11px; flex: none; }
.mi-what { margin: 6px 0 0; font-size: 13px; line-height: 1.45; color: var(--text); }
.mi-next { margin: 5px 0 8px; font-size: 11px; }
.mi .row-buttons { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }

/* The tick, for something the owner wrote down themselves. Deliberately a real
   checkbox: it is the one control on this dashboard everybody already knows
   how to use, and a to-do list that invents its own is a to-do list people
   stop ticking. */
.mi-tick {
  display: inline-flex; align-items: center; gap: 7px; margin-top: 8px;
  font-size: 12px; color: var(--text-dim, #8b949e); cursor: pointer;
}
.mi-tick input { width: 15px; height: 15px; cursor: pointer; accent-color: var(--cyan, #22d3ee); }
.mi-tick:hover { color: var(--text); }

/* A dated item leans cyan rather than amber: a deadline is a fact about
   time, not a level of alarm. Overdue ones are grouped under their own
   heading, which says more than a colour can. */
.mi-dated { border-color: rgba(34, 211, 238, .22); }

/* Adding something. Full width, because the thing you are typing is a
   sentence and a single-line box invites three words that mean nothing in
   a fortnight. */
.td-add { display: flex; flex-direction: column; gap: 8px; }
.td-add textarea {
  width: 100%; resize: vertical; font: inherit; font-family: inherit;
  font-size: 13px; line-height: 1.5; color: var(--text);
  background: rgba(255,255,255,.04); border: 1px solid var(--line);
  border-radius: 9px; padding: 10px 12px;
}
.td-add textarea::placeholder { color: var(--text-faint); }
.td-add textarea:focus, .td-add select:focus, .td-add input:focus {
  outline: none; border-color: var(--line-strong);
}
.td-row { display: flex; gap: 7px; flex-wrap: wrap; align-items: center; }
.td-row select, .td-row input[type="date"] {
  font: inherit; font-size: 12px; color: var(--text);
  background: rgba(255,255,255,.04); border: 1px solid var(--line);
  border-radius: 8px; padding: 7px 9px;
}
.td-row button {
  font: inherit; font-size: 12px; font-weight: 600; cursor: pointer; color: #0b0618;
  background: linear-gradient(90deg, var(--purple), var(--cyan));
  border: 0; border-radius: 8px; padding: 8px 18px; margin-left: auto;
}

/* Amber only for the urgent ones, and only on the border -- the card itself
   stays calm so a column of them is still readable. */
.mi:has(.mi-pri.now) { border-color: rgba(251, 191, 36, .28); }

/* Closed: still legible, clearly done. Not hidden -- seeing what you dealt
   with is half of trusting that the list is complete. */
.mi-done { opacity: .62; }
.mi-done .mi-what { color: var(--text-dim, #8b949e); }
.mi-closed { margin: 6px 0 0; font-size: 11px; color: var(--ok, #34d399); }

/* Mail: mailboxes, the sorted list, the message. Three columns like the
   console, but weighted towards the middle and right -- the list and the
   message are what you came for; the mailbox picker is furniture. */
.m-grid {
  display: grid; gap: 16px;
  grid-template-columns: minmax(240px, 1fr) minmax(300px, 1.3fr) minmax(320px, 1.7fr);
  align-items: start;
}
@media (max-width: 1240px) { .m-grid { grid-template-columns: 1fr; } }

.m-accts { display: flex; flex-direction: column; gap: 5px; }
.m-acct {
  display: flex; flex-direction: column; gap: 1px; text-align: left;
  font: inherit; color: var(--text); cursor: pointer;
  background: none; border: 1px solid transparent; border-radius: 8px; padding: 7px 9px;
}
.m-acct b { font-size: 13px; font-weight: 500; }
.m-acct span { font-size: 11px; }
.m-acct:hover { background: rgba(148, 163, 184, .07); }
.m-acct.on { background: rgba(148, 163, 184, .1); border-color: rgba(148, 163, 184, .25); }

.ml { display: flex; flex-direction: column; gap: 3px; max-height: 62vh; overflow-y: auto; }
.ml-row {
  display: flex; flex-direction: column; gap: 3px; width: 100%; text-align: left;
  font: inherit; color: inherit; cursor: pointer;
  background: none; border: 1px solid transparent; border-radius: 8px; padding: 8px 9px;
}
.ml-row:hover { background: rgba(148, 163, 184, .07); }
.ml-row.on { background: rgba(148, 163, 184, .12); border-color: rgba(148, 163, 184, .3); }
.ml-top { display: flex; align-items: baseline; gap: 7px; }
.ml-from { font-size: 12.5px; flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ml-date { font-size: 11px; flex: none; }
.ml-subj { font-size: 12.5px; color: var(--text-dim, #8b949e); line-height: 1.35; }

.m-head h2 { margin-bottom: 2px; }
.m-meta { font-size: 11px; margin: 0 0 10px; }
/* Rendered as text, deliberately -- see openMessage(). Wrapped, because a
   mail body full of long URLs would otherwise scroll the page sideways. */
.m-body {
  white-space: pre-wrap; word-break: break-word;
  max-height: 44vh; overflow-y: auto;
  font-size: 12px; line-height: 1.55;
  background: rgba(148, 163, 184, .05);
  border: 1px solid rgba(148, 163, 184, .16);
  border-radius: 8px; padding: 10px 11px; margin: 0;
}
.m-reply { margin-top: 14px; }
.m-reply h3 {
  margin: 0 0 7px; font-size: 0.78rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-faint);
}
.m-reply textarea {
  width: 100%; min-height: 110px; resize: vertical; font: inherit; font-size: 13px;
  line-height: 1.5; color: var(--text); font-family: inherit;
  background: rgba(255,255,255,.04); border: 1px solid var(--line);
  border-radius: 9px; padding: 10px 12px;
}
.m-reply textarea::placeholder { color: var(--text-faint); }
.m-reply textarea:focus { outline: none; border-color: var(--line-strong); }
.m-reply .row-buttons { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 9px; }

/* The diary. Seven columns on a wide screen, stacked on a phone -- a week
   is the unit somebody plans in, and a month grid at this size is unreadable
   without shrinking the text past legibility. */
.dy-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.dy-range { font-size: 13px; }
.dy-week { display: grid; gap: 10px; grid-template-columns: repeat(7, 1fr); align-items: start; }
@media (max-width: 1180px) { .dy-week { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .dy-week { grid-template-columns: 1fr; } }

.dy {
  background: var(--card, rgba(255,255,255,.02));
  border: 1px solid var(--line); border-radius: 10px; padding: 10px 10px 12px;
  min-height: 120px;
}
.dy-today { border-color: rgba(34, 211, 238, .35); }
.dy-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 6px; margin-bottom: 8px;
}
.dy-head b { font-size: 12.5px; }
.dy-head span { font-size: 11px; }

/* A callout: ours, so it has a title. */
.dy-ev {
  display: flex; flex-direction: column; gap: 2px;
  padding: 6px 7px; margin-bottom: 5px; border-radius: 7px;
  background: rgba(34, 211, 238, .09);
  border: 1px solid rgba(34, 211, 238, .22);
}
.dy-ev .mono { font-size: 10.5px; color: var(--cyan, #22d3ee); }
.dy-sum { font-size: 12px; line-height: 1.35; }

/* Busy: a block with nothing in it, and that is the point. Grey and quiet,
   because it is information about time and not about content. */
.dy-busy {
  display: flex; flex-direction: column; gap: 2px;
  padding: 6px 7px; margin-bottom: 5px; border-radius: 7px;
  background: rgba(148, 163, 184, .07);
  border: 1px dashed rgba(148, 163, 184, .25);
}
.dy-busy .mono { font-size: 10.5px; color: var(--text-faint); }
.dy-free { font-size: 11px; margin: 2px 0 0; }
.dy-note { margin-top: 14px; }

/* The orb's voice. Sits under the state text, quiet until wanted -- this is
   something you reach for on the way out of the door, not a control the
   screen should be advertising. */
.c-speakrow {
  display: flex; align-items: center; justify-content: center;
  gap: 8px; flex-wrap: wrap; margin-top: 12px;
}
/* The voice picker sits beside the button rather than in a settings screen:
   which voice sounds right is decided by listening to it, and that decision
   happens here or not at all. */
.c-voicesel {
  font: inherit; font-size: 11px; color: var(--text-dim, #8b949e);
  background: rgba(148, 163, 184, .08);
  border: 1px solid rgba(148, 163, 184, .22);
  border-radius: 999px; padding: 6px 10px; max-width: 190px;
}
.c-voicesel:focus { outline: none; border-color: rgba(34, 211, 238, .35); }

.c-speak {
  font: inherit; font-size: 12px; cursor: pointer;
  color: var(--text-dim, #8b949e);
  background: rgba(148, 163, 184, .08);
  border: 1px solid rgba(148, 163, 184, .22);
  border-radius: 999px; padding: 7px 16px;
}
.c-speak:hover { color: var(--text); border-color: rgba(34, 211, 238, .35); }
.c-speak:disabled { opacity: .6; cursor: default; }

/* The words, always shown as well as spoken: a sentence missed while driving
   has to be re-readable, and somebody who cannot hear it gets the same
   answer. */
.c-brief {
  margin: 12px auto 0; max-width: 560px; text-align: left;
  font-size: 12.5px; line-height: 1.6; color: var(--text-dim, #8b949e);
  background: rgba(148, 163, 184, .05);
  border: 1px solid rgba(148, 163, 184, .16);
  border-radius: 10px; padding: 11px 13px;
}

.c-stat { display: flex; align-items: baseline; gap: 8px; }
.c-stat b {
  font-family: "JetBrains Mono", monospace; font-size: 30px; font-weight: 500;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em; color: var(--text);
}
.c-stat span { font-size: 12px; color: var(--text-faint); }
.c-meter { height: 3px; background: rgba(255,255,255,.07); border-radius: 2px; margin-top: 11px; overflow: hidden; }
.c-meter i { display: block; height: 100%; background: linear-gradient(90deg, var(--purple), var(--cyan)); }

.c-inprog { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; padding-bottom: 12px; border-bottom: 1px solid var(--line); }
.c-ip { display: flex; align-items: flex-start; gap: 9px; }
.c-ip-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-faint); flex: none; margin-top: 5px; }
.c-ip-dot.on { background: var(--cyan); box-shadow: 0 0 0 3px rgba(56,189,248,.16); }
.c-ip-body { display: flex; flex-direction: column; min-width: 0; }
.c-ip-title { color: var(--text); font-size: 13px; line-height: 1.35; }
.c-ip-meta { color: var(--text-faint); font-size: 11px; }
.c-crew { display: flex; flex-direction: column; gap: 7px; }
.c-who { display: flex; align-items: center; gap: 9px; font-size: 13px; }
.c-who i { width: 7px; height: 7px; border-radius: 50%; background: var(--text-faint); flex: none; }
.c-who i.on { background: var(--cyan); box-shadow: 0 0 0 3px rgba(56,189,248,.16); }
.c-who .n { color: var(--text); }
.c-who .r { margin-left: auto; color: var(--text-faint); font-size: 11px; }

/* the orb */
.c-stage {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 24px 16px 20px; min-height: 30rem;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
}
#orb { display: block; width: min(23rem, 70vw); height: min(23rem, 70vw); }
.c-state { text-align: center; margin-top: 4px; }
.c-big {
  font-family: "JetBrains Mono", monospace; font-size: 17px;
  letter-spacing: .18em; text-transform: uppercase; color: var(--text);
}
.c-sub { font-size: 13px; color: var(--text-dim); margin-top: 9px; max-width: 26rem; line-height: 1.55; }

/* the thread: a goal is the ask, an orchestrator ledger line is the answer */
.c-talkcard { display: flex; flex-direction: column; }
.c-talk {
  display: flex; flex-direction: column; gap: 9px;
  max-height: 26rem; overflow-y: auto; padding-right: 3px;
}
.c-msg {
  font-size: 13px; line-height: 1.55; padding: 9px 11px;
  border-radius: 11px; max-width: 92%;
}
.c-msg.them {
  background: var(--card-hover); border: 1px solid var(--line);
  color: var(--text); border-bottom-left-radius: 3px;
}
.c-msg.me {
  align-self: flex-end; background: rgba(56,189,248,.1);
  border: 1px solid rgba(56,189,248,.26); color: var(--text);
  border-bottom-right-radius: 3px;
}
.c-msg.halt { background: rgba(251,191,36,.07); border-color: rgba(251,191,36,.3); }
/* Conversations view: one exchange (ask + its replies) grouped with a gap. */
.cv-exchange { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.cv-exchange:last-child { margin-bottom: 0; }
.c-msg .t { display: block; font-size: 10px; color: var(--text-faint); margin-top: 5px; }
.c-msg .flag {
  display: block; font-size: 9px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--warn); margin-bottom: 4px;
}

/* The box you type into.

   This rule said `.c-compose input` while the markup is a <textarea>, so it
   matched NOTHING and the field rendered as a raw browser textarea: no
   padding, no radius, the wrong font, and two rows for a three-line
   placeholder -- which is why it had a scrollbar and a sentence cut off in
   the middle. A selector that matches nothing fails silently; the styles
   look present in the file and are absent on the screen.

   Both element types are named now so it survives the next change of mind
   about which one this should be. */
.c-compose {
  display: flex; flex-direction: column; gap: 8px; margin-top: 12px;
}
.c-compose input,
.c-compose textarea {
  width: 100%; min-width: 0; font: inherit; font-size: 13px; color: var(--text);
  background: rgba(255,255,255,.04); border: 1px solid var(--line);
  border-radius: 9px; padding: 10px 12px;
}
.c-compose textarea {
  /* Room for the placeholder to sit on its own lines, and for a couple of
     sentences of a real request without the box scrolling as you type. */
  min-height: 84px; line-height: 1.5; resize: vertical;
  font-family: inherit;
}
.c-compose input::placeholder,
.c-compose textarea::placeholder { color: var(--text-faint); }
.c-compose input:focus,
.c-compose textarea:focus { outline: none; border-color: var(--line-strong); }
.c-compose button {
  align-self: flex-start;
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; color: #0b0618;
  background: linear-gradient(90deg, var(--purple), var(--cyan));
  border: 0; border-radius: 9px; padding: 10px 18px;
}
.c-compose button:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

/* --- Console: telemetry, feed, command bar ------------------------------- */

/* Telemetry sits above everything as a single instrument strip. Four
   readings, no more -- a wall of gauges is how the reference screen fills
   space it has nothing to say in. */
.c-telegrid {
  display: grid; gap: 12px; margin-bottom: 16px;
  grid-template-columns: repeat(4, 1fr);
}
@media (max-width: 900px) { .c-telegrid { grid-template-columns: repeat(2, 1fr); } }

.c-tele {
  background: var(--card); border: 1px solid var(--line);
  border-radius: 10px; padding: 11px 13px;
  position: relative; overflow: hidden;
}
.c-tele::after {
  /* A hairline of accent along the top edge -- enough to read as an
     instrument, not enough to become a rainbow of four different bars. */
  content: ""; position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(56,189,248,.5), transparent);
}
.c-tele-k {
  font-size: 9px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-faint);
}
.c-tele-v { display: flex; align-items: baseline; gap: 4px; margin-top: 5px; }
.c-tele-v b {
  font-family: "JetBrains Mono", monospace; font-size: 22px; font-weight: 500;
  font-variant-numeric: tabular-nums; color: var(--text); letter-spacing: -.02em;
}
.c-tele-v span { font-size: 11px; color: var(--text-faint); }
.c-tele-bar { height: 2px; background: rgba(255,255,255,.07); border-radius: 1px; margin-top: 9px; overflow: hidden; }
.c-tele-bar i {
  display: block; height: 100%; border-radius: 1px;
  background: linear-gradient(90deg, var(--purple), var(--cyan));
  transition: width .6s cubic-bezier(.2,.7,.3,1);
}
.c-tele-h { font-size: 10px; color: var(--text-faint); margin-top: 6px; }

/* Centre column holds the orb above the feed. */
.c-mid { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.c-feedcard { margin: 0; }

/* The feed is a terminal on purpose: this is the one place the system
   should look like what it is, because "I can see what it is doing" is
   most of what earns trust. Severity is a glyph AND a colour, never
   colour alone. */
.c-feed {
  font-family: "JetBrains Mono", monospace; font-size: 11.5px; line-height: 1.75;
  max-height: 17rem; overflow-y: auto;
  display: flex; flex-direction: column;
}
.c-line {
  display: grid; grid-template-columns: 3.1rem .9rem 6.4rem 1fr;
  gap: 8px; padding: 1px 0; align-items: baseline;
  border-radius: 3px;
}
.c-line:hover { background: rgba(255,255,255,.03); }
.c-t { color: var(--text-faint); font-variant-numeric: tabular-nums; }
.c-g { font-weight: 700; }
.c-who { color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.c-txt { color: var(--text-dim); word-break: break-word; }
.c-txt em { color: var(--text-faint); font-style: normal; }

.c-line.ok   .c-g { color: var(--ok); }
.c-line.warn .c-g { color: var(--bad); }
.c-line.warn .c-txt { color: var(--text); }
.c-line.hold .c-g { color: var(--warn); }
.c-line.call .c-g { color: var(--cyan); }
.c-line.info .c-g { color: var(--text-faint); }

/* New lines arrive at the top; a brief wash rather than a slide, so a
   busy feed does not become a shuffling wall. */
@media (prefers-reduced-motion: no-preference) {
  .c-feed .c-line:first-child { animation: c-arrive .5s ease-out; }
  @keyframes c-arrive {
    from { background: rgba(56,189,248,.14); }
    to   { background: transparent; }
  }
}

/* Quick actions fill the box rather than firing. */
.c-quick { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.c-chip {
  font: inherit; font-size: 11px; cursor: pointer; color: var(--text-dim);
  background: rgba(255,255,255,.04); border: 1px solid var(--line);
  border-radius: 999px; padding: 5px 11px;
  transition: color .15s, border-color .15s, background .15s;
}
.c-chip:hover { color: var(--text); border-color: var(--line-strong); background: rgba(255,255,255,.07); }
.c-chip:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

/* The command bar. The focus ring is the one place a glow is literal
   rather than decorative: it marks where typing goes. */
.c-compose { margin-top: 10px; }
.c-compose input {
  transition: border-color .18s, box-shadow .18s, background .18s;
}
.c-compose input:focus {
  border-color: rgba(56,189,248,.55);
  background: rgba(56,189,248,.05);
  box-shadow: 0 0 0 3px rgba(56,189,248,.13), 0 0 22px -4px rgba(56,189,248,.35);
}
.c-compose button { transition: filter .15s, transform .08s; }
.c-compose button:hover { filter: brightness(1.12); }
.c-compose button:active { transform: translateY(1px); }

/* The command box is a textarea, not an input: every quick action ends by
   asking you to paste something under it, and a single line cannot hold a
   paragraph. Enter sends, Shift+Enter breaks the line -- so it behaves the
   way a message box behaves. */
.c-compose textarea {
  flex: 1; min-width: 0; font: inherit; font-size: 13px; color: var(--text);
  background: rgba(255,255,255,.04); border: 1px solid var(--line);
  border-radius: 9px; padding: 10px 12px; resize: vertical;
  min-height: 44px; max-height: 40vh; line-height: 1.5;
  font-family: inherit;
  transition: border-color .18s, box-shadow .18s, background .18s;
}
.c-compose textarea::placeholder { color: var(--text-faint); }
.c-compose textarea:focus {
  outline: none;
  border-color: rgba(56,189,248,.55);
  background: rgba(56,189,248,.05);
  box-shadow: 0 0 0 3px rgba(56,189,248,.13), 0 0 22px -4px rgba(56,189,248,.35);
}
.c-compose { align-items: flex-start; }
.c-compose button { flex: none; }

/* --- Evidence: read-only statistics --------------------------------------
   A table of small numbers reads as knowledge unless something says
   otherwise, so the caveat note is styled to be read, not skipped, and any
   row without enough judged runs is dimmed rather than hidden. Hiding it
   would make the table look more certain than it is. */
.l-note {
  font-size: 12.5px; line-height: 1.55; color: var(--text-dim);
  padding: 9px 11px; margin-bottom: 12px; border-radius: 8px;
  background: rgba(251,191,36,.07); border: 1px solid rgba(251,191,36,.22);
}
.l-note.ok { background: rgba(52,211,153,.07); border-color: rgba(52,211,153,.24); }

.l-wrap { overflow-x: auto; }
.l-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.l-table th {
  text-align: left; font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-faint); font-weight: 700; padding: 0 10px 7px 0; white-space: nowrap;
}
.l-table td { padding: 7px 10px 7px 0; border-top: 1px solid var(--line); color: var(--text-dim); }
.l-table td:first-child, .l-table td:nth-child(2) { color: var(--text); }
.l-table .num { text-align: right; font-family: "JetBrains Mono", monospace; font-variant-numeric: tabular-nums; }
.l-table th.num { text-align: right; }
.l-table .strong { color: var(--text); font-weight: 600; }
.l-table tr.thin td { opacity: .5; }
.l-table .src { font-size: 10.5px; color: var(--text-faint); white-space: nowrap; }
.l-table .src b { color: var(--ok); font-weight: 600; }

.l-legend { font-size: 11.5px; line-height: 1.6; margin-top: 12px; }
.l-stats { display: flex; flex-wrap: wrap; gap: 22px; }
.l-stats dt { font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-faint); }
.l-stats dd {
  margin: 3px 0 0; font-family: "JetBrains Mono", monospace;
  font-variant-numeric: tabular-nums; font-size: 20px; color: var(--text);
}

/* The waiting card now carries what you are being asked to judge. Without
   it the buttons were one tap and the DECISION was a navigation, which is
   why almost nothing was ever labelled. */
.c-skill {
  font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-faint); margin-left: 6px;
}
.c-verdict {
  font-size: 11.5px; line-height: 1.5; margin: 0 0 7px;
  padding: 6px 8px; border-radius: 6px;
  background: rgba(255,255,255,.04); border-left: 2px solid var(--text-faint);
  color: var(--text-dim);
}
.c-verdict b { color: var(--text); font-weight: 600; }
.c-verdict.pass { border-left-color: var(--ok); }
.c-verdict.fail { border-left-color: var(--bad); }
.c-verdict.unsure { border-left-color: var(--warn); }
.c-preview {
  font-size: 12px; line-height: 1.55; color: var(--text-dim);
  background: rgba(0,0,0,.22); border: 1px solid var(--line);
  border-radius: 7px; padding: 8px 10px; margin-bottom: 9px;
  max-height: 11rem; overflow-y: auto; white-space: pre-wrap; word-break: break-word;
}
.c-more { color: var(--text-faint); }
.c-preview-img { max-width: 100%; height: auto; border-radius: 8px; display: block; }

/* THE TEAM.
   Cards that read as people rather than rows in a table. The portrait is the
   anchor -- a face is recognisable at a glance in a way a name in a monospace
   list never is, which is the whole reason this screen exists. */
.people { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.person {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 12px; border: 1px solid var(--line, #2a2f37); border-radius: 10px;
  background: var(--panel, #14181d);
}
/* A quiet left edge that says who is busy, without shouting. */
.person[data-state="working"] { border-left: 3px solid var(--ok, #3fb950); }
.person[data-state="queued"]  { border-left: 3px solid var(--warn, #d29922); }
.person[data-state="clear"]   { border-left: 3px solid var(--line, #2a2f37); }
.person-face {
  width: 64px; height: 64px; border-radius: 50%; object-fit: cover;
  flex: 0 0 64px; background: var(--line, #2a2f37);
}
.person-initials {
  display: flex; align-items: center; justify-content: center;
  font-weight: 600; letter-spacing: 0.05em; color: var(--dim, #8b949e);
}
.person-main { min-width: 0; flex: 1; }
.person-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.person-role {
  font-size: 0.82rem; color: var(--accent, #58a6ff);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.person-skills { font-size: 0.78rem; margin-top: 3px; }
.person-stats { display: flex; gap: 14px; margin-top: 6px; font-size: 0.82rem; }
.person-model { font-size: 0.74rem; margin-top: 5px; }

/* A text button that reads as a link. Used for "Forgot your password?" and
   "Back to sign in" -- both are navigation, not actions, and should not
   compete with the primary button on the login card. */
.linky {
  background: none; border: none; padding: 6px 0; margin-top: 6px;
  color: var(--accent, #58a6ff); cursor: pointer;
  font: inherit; font-size: 0.85rem; text-decoration: underline;
}
.linky:hover { opacity: 0.85; }

/* A checkbox label anywhere, not just on the login card.
   `form label` lays labels out as a column so the caption sits above its
   input -- correct for text fields, wrong for a checkbox, which ends up
   stranded above and away from its own words. That rule existed only as
   .login-card label.checkbox, so the identical markup on the Models screen
   fell back to the column layout and the box floated off on its own. */
form label.checkbox {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}
form label.checkbox input[type="checkbox"] {
  width: 16px; height: 16px; flex: 0 0 16px; margin: 0; accent-color: var(--cyan, #22d3ee);
}

/* A person card is a control: it expands to show that person's work. */
.person-wrap { display: contents; }
button.person {
  display: flex; gap: 12px; align-items: flex-start; text-align: left;
  width: 100%; font: inherit; color: inherit; cursor: pointer;
  padding: 12px; border: 1px solid var(--line, #2a2f37); border-radius: 10px;
  background: var(--panel, #14181d);
}
button.person:hover { border-color: var(--cyan, #22d3ee); }
button.person[aria-expanded="true"] { border-color: var(--cyan, #22d3ee); }
.person-panel {
  grid-column: 1 / -1;
  padding: 14px 16px; margin-top: -4px;
  border: 1px solid var(--cyan, #22d3ee); border-radius: 10px;
  background: rgba(255,255,255,.02);
}
.person-job { margin: 0 0 10px; font-size: 0.9rem; color: var(--text-dim, #8b949e); }
.person-detail h4 {
  margin: 12px 0 6px; font-size: 0.78rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--accent, #58a6ff);
}
.person-items { list-style: none; margin: 0; padding: 0; }
.person-items li {
  display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
  padding: 5px 0; border-bottom: 1px solid var(--line, #2a2f37);
}
.pi-title { flex: 1 1 240px; }
.pi-meta { font-size: 0.76rem; }

/* A work row opens to show the brief and the output. */
button.pi-open {
  display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
  width: 100%; text-align: left; font: inherit; color: inherit;
  background: none; border: 0; padding: 5px 0; cursor: pointer;
}
button.pi-open:hover .pi-title { color: var(--cyan, #22d3ee); }
.pi-detail { padding: 8px 0 12px; }

/* The same row inside a queue card. It sits above the verdict buttons, so
   it needs to read as the way IN to the work rather than as another chip:
   the title carries the underline, and the whole row lifts on hover. */
.c-q .q-open { padding: 0 0 8px; align-items: center; }
.c-q .q-open .pi-title {
  font-size: 13px; line-height: 1.45; color: var(--text);
  text-decoration: underline; text-decoration-color: rgba(148, 163, 184, .45);
  text-underline-offset: 3px;
}
.c-q .q-open:hover .pi-title { text-decoration-color: var(--cyan, #22d3ee); }
.c-q .pi-detail { padding-bottom: 4px; }
.c-q .pi-detail pre {
  max-height: 260px; overflow: auto; font-size: 11px; line-height: 1.5;
}
/* Parked: no verdict to give, so it must not look like the amber queue. */
.c-q-parked {
  background: rgba(148, 163, 184, .07);
  border-color: rgba(148, 163, 184, .22);
}
.c-q-parked .c-n { color: var(--text-faint); }
.pi-block h5 {
  margin: 8px 0 4px; font-size: 0.72rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-dim, #8b949e);
}
.pi-block pre {
  margin: 0; padding: 10px 12px; max-height: 260px; overflow: auto;
  background: rgba(255,255,255,.03); border: 1px solid var(--line, #2a2f37);
  border-radius: 8px; white-space: pre-wrap; word-break: break-word;
  font-size: 0.82rem; line-height: 1.45;
}

/* ---------------------------------------------------------------------------
   CONSOLE DENSITY.
   The three columns start level and then the queue runs away: six tall cards
   push the page to several screens while the middle and right columns end
   near the fold, leaving a long empty void beside a list. A dashboard that
   cannot be read without scrolling past its own dead space is not a
   dashboard.
   Two changes. The queue scrolls INSIDE its card instead of stretching the
   page, so the screen stays one screen. And each card gets tighter: the
   preview is clamped to three lines and the three verbs fit on one row
   instead of wrapping to two.
   --------------------------------------------------------------------------- */

/* Bounded, and scrolls within itself. */
.c-side > .c-card:first-child .c-queue {
  max-height: 58vh;
  overflow-y: auto;
  padding-right: 4px;
}
.c-side > .c-card:first-child .c-queue::-webkit-scrollbar { width: 8px; }
.c-side > .c-card:first-child .c-queue::-webkit-scrollbar-thumb {
  background: var(--line-strong, #2f3742); border-radius: 4px;
}

/* Tighter cards. */
.c-q { padding: 8px 9px; gap: 8px; }
.c-qbody > p { margin: 0 0 4px; font-size: 13.5px; line-height: 1.35; }
.c-preview {
  /* Three lines is enough to recognise the work. The full text is one click
     away on the Team screen, and the decision here is usually made from the
     title and the reviewer's verdict anyway. */
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; margin: 4px 0 6px; font-size: 12.5px; line-height: 1.4;
}
.c-verdict { font-size: 12px; line-height: 1.4; margin: 2px 0 4px; }

/* All three verbs on one row: they wrapped because the column is 20rem and
   the chips were sized for a full-width form. */
.c-q .row-buttons { display: flex; flex-wrap: nowrap; gap: 6px; }
.c-q .row-buttons .chip {
  flex: 1 1 auto; padding: 5px 8px; font-size: 12px; white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   THE RING: who is waiting on you, around the orb.
   A list of task filenames answers neither of the two questions actually
   being asked -- who needs me, and for what. Faces answer the first at a
   glance; clicking one goes to that person on the Team screen for the
   second. Only people with work waiting or running appear: a ring of seven
   where five are idle says nothing.
   --------------------------------------------------------------------------- */
.c-stage { position: relative; }
.c-ring { position: absolute; inset: 0; pointer-events: none; }
.c-ring-person {
  position: absolute; transform: translate(-50%, -50%);
  pointer-events: auto; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: none; border: 0; padding: 0; font: inherit; color: inherit;
}
.c-ring-person img, .c-ring-initials {
  width: 46px; height: 46px; border-radius: 50%; object-fit: cover;
  border: 2px solid var(--line-strong, #2f3742);
  background: var(--panel, #14181d);
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 600; color: var(--text-dim, #8b949e);
}
.c-ring-person:hover img, .c-ring-person:hover .c-ring-initials { border-color: var(--cyan, #22d3ee); }
/* Green ring while genuinely running, amber while merely waiting. */
.c-ring-person.on img, .c-ring-person.on .c-ring-initials { border-color: var(--ok, #3fb950); }
.c-ring-count {
  position: absolute; top: -4px; right: -4px;
  min-width: 18px; height: 18px; padding: 0 4px; border-radius: 9px;
  background: var(--warn, #d29922); color: #12181f;
  font-size: 11px; font-weight: 700; line-height: 18px; text-align: center;
}
.c-ring-name { font-size: 10.5px; color: var(--text-dim, #8b949e); }

/* Who did it, at the head of a queue card. */
.c-qwho { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; font-size: 12px; }
.c-qwho img { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; }
.c-qwho .dim { font-size: 11px; }

.c-more-link {
  display: block; width: 100%; margin-top: 10px; padding: 8px;
  background: none; border: 1px dashed var(--line-strong, #2f3742); border-radius: 8px;
  color: var(--text-dim, #8b949e); font: inherit; font-size: 12.5px; cursor: pointer;
}
.c-more-link:hover { border-color: var(--cyan, #22d3ee); color: var(--cyan, #22d3ee); }

/* ===========================================================================
   ONE PERSON'S DASHBOARD.
   The same three-column language as the Console, with their face where the
   orb is -- the thing you came to look at is a person, so the person is the
   centrepiece. The halo carries the same state colours the orb uses: green
   while running, amber while something waits, quiet when clear.
   =========================================================================== */
.p-top { margin-bottom: 10px; }

.p-stage {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 340px; padding: 28px 16px;
  border-radius: 14px;
  background: radial-gradient(circle at 50% 42%, rgba(255,255,255,.05), transparent 62%);
}
.p-halo {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 260px; height: 260px; border-radius: 50%;
  border: 1px solid var(--line-strong, #2f3742);
  box-shadow: 0 0 60px rgba(255,255,255,.04) inset;
}
/* State, in the orb's own vocabulary. */
.p-stage[data-state="working"] .p-halo {
  border-color: rgba(63,185,80,.5); box-shadow: 0 0 70px rgba(63,185,80,.18) inset;
}
.p-stage[data-state="attend"] .p-halo {
  border-color: rgba(251,191,36,.45); box-shadow: 0 0 70px rgba(251,191,36,.16) inset;
}
.p-face {
  position: relative; width: 148px; height: 148px; border-radius: 50%;
  object-fit: cover; border: 3px solid var(--line-strong, #2f3742);
  background: var(--panel, #14181d);
}
.p-face-initials {
  display: flex; align-items: center; justify-content: center;
  font-size: 44px; font-weight: 600; color: var(--text-dim, #8b949e);
}
.p-stage[data-state="working"] .p-face { border-color: rgba(63,185,80,.7); }
.p-stage[data-state="attend"] .p-face { border-color: rgba(251,191,36,.65); }
.p-ident { position: relative; text-align: center; margin-top: 14px; }
.p-name { font-size: 22px; font-weight: 600; letter-spacing: .01em; }
.p-role {
  font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent, #58a6ff); margin-top: 3px;
}

/* Their record: three numbers, not a table. */
.p-stats { display: flex; gap: 18px; margin: 4px 0 2px; }
.p-stats div { display: flex; flex-direction: column; }
.p-stats b { font-size: 22px; line-height: 1.1; }
.p-stats span { font-size: 11px; color: var(--text-faint); }

/* Their brief, as prose -- it is what the model is told, in those words. */
.p-block { margin-bottom: 12px; }
.p-block h4 {
  margin: 0 0 4px; font-size: .74rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-dim, #8b949e);
}
.p-block p { margin: 0; font-size: 12.8px; line-height: 1.5; }
/* The rules that override any brief, including one that arrived from
   WhatsApp. Marked so they read as rules rather than description. */
.p-never { padding-left: 10px; border-left: 2px solid rgba(252,165,165,.4); }
.p-never h4 { color: #fca5a5; }

.p-feed { list-style: none; margin: 0; padding: 0; max-height: 320px; overflow-y: auto; }
.p-feed li {
  padding: 5px 0; border-bottom: 1px solid var(--line, #2a2f37);
  font-size: 12.2px; line-height: 1.4;
}

/* ---------------------------------------------------------------------------
   Record -- the processing record for one month.

   The caveat block is styled as the loudest element on the screen and not as
   a footnote, deliberately. It carries what the record CANNOT show, and a
   compliance artefact whose limits are set in small grey type is one whose
   limits nobody reads.
   --------------------------------------------------------------------------- */
.r-head {
  display: flex; flex-wrap: wrap; align-items: flex-start;
  justify-content: space-between; gap: 16px; margin-bottom: 14px;
}
.r-head h2 { margin-bottom: 4px; }
.r-head p { font-size: 12.5px; max-width: 62ch; }
.r-controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.r-controls label { font-size: 12px; }
.r-controls select {
  background: var(--card); color: var(--text); border: 1px solid var(--line-strong);
  border-radius: 8px; padding: 7px 10px; font: inherit; font-size: 13px;
}
.r-dl {
  display: inline-block; padding: 7px 14px; border-radius: 8px;
  border: 1px solid rgba(56,189,248,.4); background: rgba(56,189,248,.1);
  color: var(--cyan); font-size: 13px; font-weight: 600; text-decoration: none;
}
.r-dl:hover { background: rgba(56,189,248,.18); }

.r-tiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px; margin: 0 0 14px;
}
.r-tiles > div {
  background: var(--card); border: 1px solid var(--line);
  border-radius: 10px; padding: 11px 13px;
}
.r-tiles dt { font-size: 11px; color: var(--text-faint); text-transform: uppercase; letter-spacing: .06em; }
.r-tiles dd {
  font-size: 21px; font-weight: 700; color: var(--text); line-height: 1.25;
  font-family: "JetBrains Mono", monospace; font-variant-numeric: tabular-nums;
}
.r-tiles span { font-size: 11.5px; color: var(--text-faint); }

.r-caveat {
  border: 1px solid rgba(251,191,36,.34); background: rgba(251,191,36,.07);
  border-radius: 10px; padding: 12px 14px;
}
.r-caveat b { display: block; color: var(--warn); font-size: 13px; margin-bottom: 6px; }
.r-caveat ul { margin: 0; padding-left: 18px; }
.r-caveat li { font-size: 12.3px; color: var(--text-dim); line-height: 1.55; margin-bottom: 4px; }
.r-caveat li:last-child { margin-bottom: 0; }

.r-paths {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px; margin: 12px 0 14px;
}
.r-paths dt { font-size: 11px; color: var(--text-faint); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 3px; }
.r-paths dd { font-size: 12px; color: var(--text-dim); line-height: 1.6; word-break: break-all; }

.l-table tr.r-bad td { color: var(--bad); }

.r-dl.alt { border-color: var(--line-strong); background: var(--card); color: var(--text-dim); }
.r-dl.alt:hover { background: var(--card-hover); color: var(--text); }
.l-note.bad { background: rgba(248,113,113,.08); border-color: rgba(248,113,113,.32); }

/* --- Setup (first run) --- */
.s-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; }
.s-grid label { display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; color: var(--text-dim); }
.s-grid input { background: var(--card); color: var(--text); border: 1px solid var(--line-strong); border-radius: 8px; padding: 8px 10px; font: inherit; font-size: 13.5px; }
.s-person { border: 1px solid var(--line); border-radius: 10px; padding: 12px; margin-bottom: 12px; background: var(--card); }
.s-person-head { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.s-person-head input { flex: 1 1 180px; background: var(--bg-1); color: var(--text); border: 1px solid var(--line-strong); border-radius: 8px; padding: 8px 10px; font: inherit; font-size: 13.5px; }
.s-jobs { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 6px; }
.s-job { display: flex; align-items: flex-start; gap: 8px; padding: 7px 9px; border-radius: 8px; border: 1px solid transparent; cursor: pointer; font-size: 12.5px; }
.s-job:hover { background: var(--card-hover); }
.s-job input { margin-top: 3px; }
.s-job span { display: flex; flex-direction: column; gap: 2px; }
.s-job b { color: var(--text); font-family: "JetBrains Mono", monospace; font-size: 12px; }
.s-job em { color: var(--text-faint); font-style: normal; font-size: 11.5px; line-height: 1.45; }
.s-job.taken { opacity: .45; cursor: default; }
#s-mail { width: 100%; background: var(--card); color: var(--text); border: 1px solid var(--line-strong); border-radius: 8px; padding: 9px 11px; font: inherit; font-size: 13px; resize: vertical; }

/* NEEDS YOUR GO-AHEAD.
   The one card on the console that is genuinely blocking work, so it sits
   first in the side column and is allowed a warm border -- everything else
   there is a queue or a note. The step list is the substance: a person
   cannot approve a number, only a set of things being bought. */
.c-approve { border-color: rgba(252, 211, 77, .3); }
.c-ap { padding: 8px 0; border-top: 1px solid var(--line); }
.c-ap:first-of-type { border-top: 0; }
.c-ap-title { margin: 0 0 2px; font-size: 13px; line-height: 1.4; }
.c-ap-cost { margin: 0 0 6px; font-size: 11px; }
.c-ap-steps { margin: 0 0 8px; padding-left: 14px; font-size: 12px; color: var(--text-dim); line-height: 1.6; }
.c-ap-who { color: var(--text); }
.c-ap-act { display: flex; gap: 8px; }

/* THE READER.
   A full-screen layer, because the thing it shows is the actual work and
   everything else on this panel is a glance. Real reading type: 14px at 1.7,
   a measure that does not run the width of a wide monitor, and the document
   scrolls rather than the page behind it. */
.doc-overlay { position: fixed; inset: 0; z-index: 200; display: flex;
  align-items: center; justify-content: center; padding: 24px; }
.doc-back { position: absolute; inset: 0; background: rgba(5, 3, 20, .82); }
.doc-open-body { overflow: hidden; }
.doc-panel {
  position: relative; z-index: 1;
  width: min(920px, 100%); max-height: 100%;
  display: flex; flex-direction: column;
  background: var(--bg-1); border: 1px solid var(--line-strong);
  border-radius: 10px; padding: 16px 20px 20px;
}
.doc-head { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; border-bottom: 1px solid var(--line); padding-bottom: 12px; }
.doc-headings h2 { margin: 0 0 2px; font-size: 15px; line-height: 1.4; }
.doc-sub { margin: 0; font-size: 11px; }
.doc-actions { display: flex; gap: 8px; flex: none; }
.doc-actions .chip { text-decoration: none; display: inline-block; }
.doc-note { margin: 10px 0 0; font-size: 12px; color: var(--warn, #fbbf24); }
.doc-body { overflow: auto; margin-top: 12px; }
.doc-body pre {
  margin: 0; white-space: pre-wrap; word-wrap: break-word;
  font-size: 14px; line-height: 1.7; color: var(--text);
  font-family: inherit;
}
@media (max-width: 640px) {
  .doc-overlay { padding: 0; }
  .doc-panel { border-radius: 0; height: 100%; width: 100%; }
}
/* The way into the document, above the verdict buttons: you read it, then
   you judge it. Separated from them so it does not read as a fourth verdict. */
.c-qread { margin: 8px 0 4px; }

/* The drawn default face. Sized inline by avatarHTML so one rule serves the
   46px roster chip, the 64px header and the 148px person page. */
.avatar-initials {
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; color: var(--text); font-weight: 600;
  letter-spacing: .02em; line-height: 1; flex: none;
}
/* A real uploaded photo gets the same circular crop the initials draw,
   whichever call site's own class (.person-face, .p-face, ...) is doing
   the sizing. */
.avatar-img { border-radius: 50%; object-fit: cover; }

/* The brand on the login card and in the editor form. */
.brand-logo { display: block; margin: 0 auto 10px; max-width: 220px; object-fit: contain; }
.brand-tagline { margin: 2px 0 12px; font-size: 12px; }
.f-lab { display: block; margin: 10px 0; font-size: 12px; color: var(--text-dim); }
.f-lab input { display: block; width: 100%; margin-top: 4px; padding: 7px 9px;
  background: rgba(148,163,184,.08); border: 1px solid var(--line-strong);
  border-radius: 6px; color: var(--text); font-size: 13px; }
