/* Portal Web App — the surface Solomon and Grant share.
 *
 * Built on Portal OS's SHIPPED tokens (cockpit/os/styles/base.css), not on the
 * organic-portal skill doc. The two disagree: the doc specifies Fraunces and
 * IBM Plex on a warm ground, the code ships the Apple system stack on pure
 * black with iridescent accents. The code is what is real, so this matches the
 * code. If the doc is meant to win, it is the doc that needs updating.
 *
 * No webfont is loaded. The Apple stack resolves locally on every machine
 * either of us uses, which means no network round-trip, no FOUT, and no
 * dependency on a font CDN this sandbox cannot even reach.
 */

:root{
  /* Portal Web's own DNA — four hues from the client OS particle palette, so
     the chrome and the background field are visibly the same system. */
  --h1:#C4B5FD; --h2:#7DD3FC; --h3:#FDE68A; --h4:#6EE7B7;
  --core:#0A0A0A; --tempo:1;

  --bg:#000; --surface:#0A0A0A; --surface-2:#111; --panel:#0B0C13;
  --line:rgba(255,255,255,.09); --line-2:rgba(255,255,255,.17); --line-3:rgba(255,255,255,.22);
  --text:#EDEDED; --muted:#A1A1AA; --faint:#71717A; --paper:#FAFAFA;
  --accent:#C4B5FD; --gold:#FDE68A;
  --ok:#6EE7B7; --warn:#FDE68A; --stop:#FDA4AF; --unknown:#5A6070;
  --human:#FDE68A; --agent:#C4B5FD;

  --sans:-apple-system,BlinkMacSystemFont,"SF Pro Display","SF Pro Text","Geist","Inter","Helvetica Neue",sans-serif;
  --mono:ui-monospace,"SF Mono","Geist Mono","Cascadia Mono",Menlo,Consolas,monospace;
  --r:14px; --rail:236px;
}

*{box-sizing:border-box}
html,body{height:100%}
body{margin:0;background:var(--bg);color:var(--text);
  font:400 15px/1.6 var(--sans);-webkit-font-smoothing:antialiased;
  font-feature-settings:"kern","ss01","cv02","cv11"}
h1,h2,h3{margin:0;font-weight:600;letter-spacing:-.028em}
a{color:var(--accent);text-decoration:none}
button{font:inherit;cursor:pointer;color:inherit}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:6px}
[hidden]{display:none !important}

/* The field sits behind everything.
   width/height are REQUIRED, not belt-and-braces: a canvas is a replaced
   element, so `inset:0` positions it but does not stretch it — it keeps its
   intrinsic 300x150 and the whole field renders as a smudge in the corner. */
#field{position:fixed;inset:0;width:100vw;height:100vh;z-index:-2;pointer-events:none;background:var(--bg)}

.mono{font-family:var(--mono);font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}

/* ── shell ─────────────────────────────────────────────────────────────── */
#app{display:flex;min-height:100dvh}
.rail{width:var(--rail);flex:none;background:rgba(10,10,10,.72);backdrop-filter:blur(20px) saturate(180%);
  border-right:1px solid var(--line);display:flex;flex-direction:column;
  position:sticky;top:0;height:100dvh;z-index:6}
.brand{display:flex;align-items:center;gap:10px;padding:20px 18px 16px;font-size:15px;font-weight:600;letter-spacing:-.02em}
.brand .m{width:16px;height:16px;border-radius:50%;flex:none;
  background:radial-gradient(circle at 50% 50%,var(--core) 0 34%,var(--h3) 38%,var(--h1) 54%,transparent 76%);
  animation:eclipse calc(6s / var(--tempo)) ease-in-out infinite alternate}
@keyframes eclipse{from{transform:scale(.94);opacity:.85}to{transform:scale(1.06);opacity:1}}
.rail nav{display:flex;flex-direction:column;gap:2px;padding:6px 10px;overflow-y:auto}
.rail nav button{display:flex;align-items:center;gap:10px;background:none;border:0;border-radius:9px;
  color:var(--muted);padding:9px 11px;font-size:14px;text-align:left;width:100%;
  transition:background .14s,color .14s}
.rail nav button.on{background:var(--surface-2);color:var(--text);font-weight:500}
.rail nav button:hover{color:var(--text)}
.rail nav .ic{width:9px;height:9px;border-radius:50%;flex:none;opacity:.42;transition:opacity .14s;
  background:radial-gradient(circle at 50% 50%,var(--core) 0 52%,var(--faint) 58%,transparent 92%)}
.rail nav button.on .ic{opacity:1;
  background:radial-gradient(circle at 50% 50%,var(--core) 0 52%,var(--h1) 58%,transparent 92%)}
.rail .foot{margin-top:auto;padding:14px 16px;border-top:1px solid var(--line);
  display:flex;align-items:center;gap:8px;font-size:12px;color:var(--faint)}
.rail .foot button{background:none;border:1px solid var(--line);border-radius:7px;
  padding:4px 9px;font-size:11.5px;color:var(--muted);margin-left:auto}
.rail .foot button:hover{color:var(--text);border-color:var(--line-3)}

main{flex:1;min-width:0;padding:30px 30px 90px;max-width:1240px}
.head{display:flex;align-items:baseline;gap:14px;margin-bottom:22px;flex-wrap:wrap}
.head h2{font-size:26px}
.lede{color:var(--muted);font-size:14px;margin:6px 0 20px;max-width:74ch;line-height:1.65}
.panel{background:rgba(11,12,19,.66);backdrop-filter:blur(14px);
  border:1px solid var(--line);border-radius:var(--r);padding:20px;margin-bottom:18px}

.empty{color:var(--faint);padding:30px 18px;text-align:center;border:1px dashed var(--line);border-radius:var(--r)}
.empty strong{display:block;color:var(--muted);font-family:var(--mono);font-size:10.5px;
  letter-spacing:.09em;text-transform:uppercase;margin-bottom:7px}

/* ── the graph ─────────────────────────────────────────────────────────── */
.graphwrap{overflow-x:auto;padding:6px 0}
svg.graph{display:block}
.node rect{fill:rgba(17,17,17,.86);stroke:var(--line);stroke-width:1.5}
.node.agent rect{stroke:color-mix(in srgb,var(--agent) 42%,var(--line))}
.node.human rect{stroke:color-mix(in srgb,var(--human) 46%,var(--line));stroke-dasharray:5 3}
.node[data-state="done"] rect{fill:color-mix(in srgb,var(--ok) 10%,rgba(17,17,17,.86));stroke:color-mix(in srgb,var(--ok) 46%,var(--line))}
.node[data-state="ready"] rect{fill:color-mix(in srgb,var(--agent) 12%,rgba(17,17,17,.86));stroke:var(--agent)}
.node[data-state="waiting"] rect{fill:color-mix(in srgb,var(--human) 11%,rgba(17,17,17,.86));stroke:var(--human)}
.node[data-state="blocked"] rect{opacity:.5}
.node .title{fill:var(--text);font:500 12.5px var(--sans);letter-spacing:-.01em}
.node .who{fill:var(--faint);font:10px var(--mono);letter-spacing:.07em;text-transform:uppercase}
.node{cursor:pointer}
.node:hover rect{stroke:var(--h2)}
.node .halo{opacity:.5}
.edge{stroke:var(--line-2);stroke-width:1.4;fill:none;marker-end:url(#arrow)}
.edge.blocking{stroke:color-mix(in srgb,var(--human) 50%,var(--line));stroke-dasharray:4 4}
/* Rule 1: motion reports a fact. The only pulse is on a node that can run now. */
@media (prefers-reduced-motion:no-preference){
  .node[data-state="ready"] .pulse{animation:pulsering calc(4.2s / var(--tempo)) ease-out infinite}
}
@keyframes pulsering{0%{transform:scale(.7);opacity:.45}100%{transform:scale(1.5);opacity:0}}

.legend{display:flex;gap:18px;flex-wrap:wrap;margin-top:12px;font-size:12px;color:var(--faint)}
.legend span{display:flex;align-items:center;gap:7px}
.legend i{width:22px;height:11px;border-radius:3px;border:1.5px solid var(--line);display:block}
.legend .ag i{border-color:var(--agent);background:color-mix(in srgb,var(--agent) 12%,transparent)}
.legend .hu i{border-color:var(--human);border-style:dashed;background:color-mix(in srgb,var(--human) 12%,transparent)}
.legend .dn i{border-color:color-mix(in srgb,var(--ok) 46%,var(--line));background:color-mix(in srgb,var(--ok) 10%,transparent)}
.legend .bl i{opacity:.5}

.detail{margin-top:14px;padding:15px 17px;background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r)}
.detail h3{font-size:14.5px;margin-bottom:5px}
.detail .why{color:var(--muted);font-size:13.5px;line-height:1.65}
.detail dl{display:grid;grid-template-columns:auto 1fr;gap:5px 14px;margin:13px 0 0;font-size:12px}
.detail dt{color:var(--faint);font-family:var(--mono);font-size:10px;letter-spacing:.07em;text-transform:uppercase}
.detail dd{margin:0;color:var(--muted);font-family:var(--mono);font-size:11.5px;word-break:break-all}

/* ── goals ─────────────────────────────────────────────────────────────── */
.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fill,minmax(228px,1fr))}
.goal{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r);
  padding:13px 15px;position:relative;overflow:hidden}
.goal::before{content:"";position:absolute;inset:0 auto 0 0;width:3px;background:var(--unknown)}
.goal[data-state="on_track"]::before{background:var(--ok)}
.goal[data-state="at_risk"]::before{background:var(--warn)}
.goal[data-state="off_track"]::before{background:var(--stop)}
.goal .label{font-size:12.5px;color:var(--muted);margin-bottom:7px}
.goal .val{font-family:var(--mono);font-size:23px;font-weight:500;letter-spacing:-.02em}
.goal .tgt{font-family:var(--mono);font-size:10px;color:var(--faint);margin-top:4px;letter-spacing:.02em}
.goal[data-state="unknown"] .val{font-size:11.5px;color:var(--unknown);text-transform:uppercase;letter-spacing:.1em}
.goal .why{font-size:11.5px;color:var(--faint);line-height:1.5;margin-top:9px;display:none}
.goal:hover .why,.goal:focus-within .why{display:block}
.tally{display:flex;gap:16px;flex-wrap:wrap;font-family:var(--mono);font-size:10.5px;
  text-transform:uppercase;letter-spacing:.07em;margin-bottom:16px}
.tally span{display:flex;align-items:center;gap:6px;color:var(--faint)}
.tally i{width:8px;height:8px;border-radius:2px;background:var(--unknown);display:block}
.tally .on i{background:var(--ok)}.tally .at i{background:var(--warn)}
.tally .off i{background:var(--stop)}.tally .un i{background:var(--unknown)}

/* ── tables ────────────────────────────────────────────────────────────── */
table{width:100%;border-collapse:collapse;font-size:13.5px}
th{text-align:left;font:500 10px var(--mono);letter-spacing:.08em;text-transform:uppercase;
  color:var(--faint);padding:8px 10px;border-bottom:1px solid var(--line)}
td{padding:11px 10px;border-bottom:1px solid var(--line);color:var(--muted);vertical-align:middle}
tbody tr:hover td{background:var(--surface-2)}
td.name{color:var(--text);font-weight:500}
.stage{font:500 10px var(--mono);letter-spacing:.06em;text-transform:uppercase;padding:3px 9px;
  border-radius:20px;border:1px solid var(--line);color:var(--muted);white-space:nowrap}

/* ── agent cards, with characters ──────────────────────────────────────── */
.agents{display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(268px,1fr))}
.agent{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r);
  padding:16px;display:flex;gap:14px;align-items:flex-start;transition:border-color .16s}
.agent:hover{border-color:var(--line-3)}
.agent .por{width:72px;height:86px;flex:none;position:relative;display:flex;
  align-items:flex-end;justify-content:center;
  background:radial-gradient(60% 60% at 50% 78%,rgba(196,181,253,.13),transparent 72%)}
.agent h3{font-size:14.5px;margin-bottom:3px}
.agent .model{font:10px var(--mono);letter-spacing:.06em;color:var(--faint);text-transform:uppercase}
.agent .obj{font-size:12.5px;color:var(--muted);line-height:1.55;margin-top:8px}
.pw-sprite-img{image-rendering:pixelated;filter:drop-shadow(0 3px 10px rgba(0,0,0,.6));
  will-change:transform;display:block}
.pw-sprite-idle{position:relative}

/* ── the overseer card — taps to open and close ───────────────────────── */
.ovc{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.ovc summary{list-style:none;cursor:pointer;padding:15px 18px;display:flex;align-items:center;gap:12px}
.ovc summary::-webkit-details-marker{display:none}
.ovc .dot{width:9px;height:9px;border-radius:50%;flex:none;background:var(--unknown)}
.ovc[data-v="OK"] .dot{background:var(--ok)}
.ovc[data-v="PROBLEM"] .dot{background:var(--stop)}
.ovc[data-v="NOT CHECKED"] .dot{background:var(--unknown);box-shadow:0 0 0 3px rgba(90,96,112,.22)}
.ovc .verdict{font-size:14px;font-weight:500}
.ovc .when{margin-left:auto;font:10px var(--mono);letter-spacing:.06em;color:var(--faint)}
.ovc .chev{color:var(--faint);transition:transform .2s}
.ovc[open] .chev{transform:rotate(90deg)}
.ovc .body{padding:0 18px 18px;border-top:1px solid var(--line)}
.check{display:flex;gap:12px;padding:11px 0;border-bottom:1px solid var(--line);font-size:13px}
.check:last-child{border-bottom:0}
.check .st{font:500 9.5px var(--mono);letter-spacing:.08em;padding:2px 7px;border-radius:4px;
  flex:none;height:fit-content;border:1px solid var(--line);color:var(--muted)}
.check[data-s="OK"] .st{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 40%,transparent)}
.check[data-s="PROBLEM"] .st{color:var(--stop);border-color:color-mix(in srgb,var(--stop) 40%,transparent)}
.check[data-s="NOT CHECKED"] .st{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 40%,transparent)}
.check .txt{color:var(--muted);line-height:1.55}
.check .txt b{color:var(--text);font-weight:500;display:block;margin-bottom:2px}

/* ── login ─────────────────────────────────────────────────────────────── */
.login{max-width:330px;margin:0 auto;padding:16vh 20px 0;text-align:center;position:relative;z-index:1}
.login .m{width:34px;height:34px;border-radius:50%;margin:0 auto 18px;
  background:radial-gradient(circle at 50% 50%,var(--core) 0 34%,var(--h3) 38%,var(--h1) 54%,transparent 76%);
  animation:eclipse calc(6s / var(--tempo)) ease-in-out infinite alternate}
.login h1{font-size:25px;margin-bottom:6px;letter-spacing:-.03em}
.login p{color:var(--muted);font-size:13.5px;margin:0 0 24px}
.login input{width:100%;padding:12px 14px;margin-bottom:10px;background:rgba(17,17,17,.8);
  border:1px solid var(--line);border-radius:10px;color:var(--text);font:15px var(--sans)}
.login input:focus{outline:none;border-color:var(--line-3)}
.login button[type=submit]{width:100%;padding:12px;background:var(--paper);color:#000;border:0;
  border-radius:10px;font-weight:600;font-size:15px}
.login .err{color:var(--stop);font-size:12.5px;min-height:20px;margin-top:12px}
.login .walk{position:relative;height:110px;margin-top:26px}
.pw-sprite-shade{position:absolute;bottom:0;left:0;border-radius:50%;pointer-events:none;
  background:radial-gradient(ellipse at 50% 50%,rgba(0,0,0,.55),transparent 70%);
  will-change:transform,opacity}
.login .walk .pw-sprite-img{position:absolute;bottom:0;left:0;transform-origin:50% 100%}

@media(max-width:860px){
  #app{flex-direction:column}
  .rail{width:100%;height:auto;position:static;flex-direction:row;align-items:center;
    border-right:0;border-bottom:1px solid var(--line);overflow-x:auto}
  .rail nav{flex-direction:row;padding:8px}
  .rail nav button{white-space:nowrap}
  .rail .foot{margin-top:0;border-top:0;padding:8px 14px}
  main{padding:20px 16px 80px}
}

/* ── Guardrails ───────────────────────────────────────────────────────────────
   Three states with three different looks, on purpose. Grey is "never run" and
   must not be mistaken for green. */
.lede.small { font-size: 13px; opacity: .72; margin-top: -4px; }
.guards { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.guard {
  border: 1px solid rgba(255,255,255,.09); border-radius: 14px; padding: 14px 15px;
  background: rgba(255,255,255,.02);
}
.guard[data-s="STOPPED"] { border-color: rgba(248,113,113,.45); background: rgba(248,113,113,.06); }
.guard[data-s="NO DATA"] { opacity: .68; border-style: dashed; }
.guard .gh { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.guard .gh .dot { width: 8px; height: 8px; border-radius: 50%; background: #6EE7B7; flex: none; }
.guard[data-s="STOPPED"] .gh .dot { background: #F87171; }
.guard[data-s="NO DATA"] .gh .dot { background: #71717A; }
.guard .gm { font-size: 11px; opacity: .6; font-variant-numeric: tabular-nums; }
.guard .gs { margin-left: auto; font-size: 10.5px; letter-spacing: .08em; opacity: .7; }
.guard[data-s="STOPPED"] .gs { color: #FCA5A5; opacity: 1; }
.gbar { height: 5px; border-radius: 3px; background: rgba(255,255,255,.07); margin: 11px 0 9px; overflow: hidden; }
.gbar i { display: block; height: 100%; background: #C4B5FD; border-radius: 3px; transition: width .4s ease; }
.guard[data-s="STOPPED"] .gbar i { background: #F87171; }
.guard .gn { display: grid; gap: 3px; font-size: 12px; opacity: .78; font-variant-numeric: tabular-nums; }
.guard .gn .est { color: #FCD34D; opacity: .95; }
.guard .gw { margin-top: 9px; font-size: 12.5px; line-height: 1.45; color: #FCA5A5; }
.guard[data-s="OK"] .gw, .guard[data-s="NO DATA"] .gw { color: inherit; opacity: .6; }
.guard .gb { margin-top: 9px; font-size: 12px; }
.guard .gb summary { cursor: pointer; opacity: .55; }
.guard .gb p { margin: 6px 0 0; opacity: .72; line-height: 1.5; }
.greset {
  margin-top: 11px; width: 100%; padding: 8px; border-radius: 9px; cursor: pointer;
  border: 1px solid rgba(248,113,113,.4); background: rgba(248,113,113,.1); color: #FCA5A5;
  font: inherit; font-size: 12.5px;
}
.greset:disabled { opacity: .6; cursor: default; }
