/* mppdb web UI — hand-written CSS reproducing the canonical design mock
 * (docs/webui/design-mock, Chat mock, Stacked variant). Tokens are verbatim
 * from the mock's applyTheme() / design-mock README. Dark is the default. */

/* ---------------------------------------------------------------- fonts */
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(fonts/geist-var-latin.woff2) format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(fonts/jetbrains-mono-var-latin.woff2) format("woff2");
}
@font-face {
  font-family: "Dune Rise";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/dune-rise-wordmark.woff2?v=full) format("woff2");
}

/* ---------------------------------------------------------------- tokens */
:root {
  --bg: #0a0d13;
  --panel: #11151d;
  --panel2: #161b25;
  --panel3: #1c2230;
  --border: #242c3a;
  --border2: #2f3848;
  --text: #e7eaf0;
  --dim: #98a2b5;
  --faint: #5d6a80;
  --accent: #5891f5;
  --accent2: #3f6fd6;
  --accentSoft: rgba(88, 145, 245, 0.16);
  --ok: #43c07f;
  --okSoft: rgba(67, 192, 127, 0.15);
  --warn: #e0a94e;
  --warnSoft: rgba(224, 169, 78, 0.15);
  --err: #ec6a60;
  --errSoft: rgba(236, 106, 96, 0.15);
  --kw: #5891f5;
  --fn: #c58af9;
  --fnSoft: rgba(197, 138, 249, 0.16);
  --str: #43c07f;
  --num: #e0a94e;
  --punc: #98a2b5;
  --shadow: 0 8px 30px rgba(0, 0, 0, 0.45);
  --gridline: rgba(255, 255, 255, 0.06);
  --mcolor: #c58af9;
  --radius: 8px;
  --sel: rgba(88, 145, 245, 0.32);
  /* WP-25 console surface tokens (dark) — dormant; consumed by stages B/C.
     Existing --text/--faint/--err + ADQL hues --kw/--fn/--str/--num/--punc
     are reused as-is (spec §3/§4.1) and intentionally not redefined here. */
  --app: #1e1e1e;
  --side: #252526;
  --line: #3a3a3a;
  --line2: #2f2f2f;
  --code: #262626;
  --codeline: #363636;
  --muted: #9aa0a8; /* WP-25: bumped from #8a9099 for AA on meta/tag/note (≥4.5:1 on --app/--line2) */
  --in: #5aa3e0;
  --out: #e0895a;
  --cmd: #42a5f5;
  --edit: #57c463;
  --tmpl: #4dd0e1;
  --stale: #e0a94e;
  --brandM: #c792ea;
  --brandDb: #5aa3e0;
  --kernel: #f37726;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, "Roboto Mono", Consolas, monospace;
}
:root[data-theme="light"] {
  --bg: #eef1f6;
  --panel: #ffffff;
  --panel2: #f4f6fa;
  --panel3: #e9edf4;
  --border: #e2e7f0;
  --border2: #d0d8e5;
  --text: #151a24;
  --dim: #5b6577;
  --faint: #8b97ab;
  --accent: #2f6fe0;
  --accent2: #245ec4;
  --accentSoft: rgba(47, 111, 224, 0.10);
  --ok: #1f9d57;
  --okSoft: rgba(31, 157, 87, 0.12);
  --warn: #b9791b;
  --warnSoft: rgba(185, 121, 27, 0.12);
  --err: #d64a41;
  --errSoft: rgba(214, 74, 65, 0.10);
  --kw: #2f6fe0;
  --fn: #8a3fd1;
  --fnSoft: rgba(138, 63, 209, 0.12);
  --str: #1f9d57;
  --num: #b9791b;
  --punc: #5b6577;
  --shadow: 0 8px 30px rgba(20, 25, 40, 0.12);
  --gridline: rgba(0, 0, 0, 0.07);
  --sel: rgba(47, 111, 224, 0.28);
  /* WP-25 console surface tokens (light) — dormant; consumed by stages B/C. */
  --app: #ffffff;
  --side: #f7f7f7;
  --line: #e6e6e6;
  --line2: #ededed;
  --code: #f6f6f6;
  --codeline: #ececec;
  --muted: #5f6773; /* WP-25: bumped from #8b939c for AA on meta/tag/note (≥4.5:1 on --app/--line2) */
  --in: #2a6ea8; /* WP-25 §8: darkened from the mock's #307fc1 so In[n] prompt text hits WCAG AA (5.39:1 on white) */
  --out: #ad5424; /* WP-25 §8: darkened from the mock's #c1622d so Out[n] prompt text hits WCAG AA (5.16:1 on white) */
  --cmd: #2196f3;
  --edit: #3fb950;
  --tmpl: #00838f;
  --stale: #9a6700;
  --brandM: #8250df;
  --brandDb: #307fc1;
  --kernel: #f37726;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, "Roboto Mono", Consolas, monospace;
}

/* ---------------------------------------------------------------- base */
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: "Geist", system-ui, sans-serif;
  font-size: 13px;
}
::selection { background: var(--sel); }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-thumb {
  background: var(--border2);
  border-radius: 7px;
  border: 3px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--faint); background-clip: content-box; }
::-webkit-scrollbar-track { background: transparent; }
input::placeholder, textarea::placeholder { color: var(--faint); }
button { font-family: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
[hidden] { display: none !important; }
.flex1 { flex: 1; }
.mono { font-family: "JetBrains Mono", ui-monospace, monospace; }
.acc { color: var(--accent); }
.fn { color: var(--fn); }

@keyframes mp-spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------------- login */
/* The login screen adopts the imported "Rubin space" design: a deep-space
   gradient, a twinkling starfield, four crossfading nebula scenes (a CSS
   stand-in for the design's Rubin-sky slideshow, drifting via Ken-Burns
   zooms), and a legibility overlay — with the wordmark pinned top-left and
   the tagline above the auth card. Everything animates in pure CSS (the CSP
   forbids inline script). The card itself is unchanged (.login-card below).
   The screen is pinned to the dark palette so a saved light theme (applied
   at boot, before login) can't wash out the scene. */
#login-view {
  --panel: #11151d;
  --panel2: #161b25;
  --border: #242c3a;
  --border2: #2f3848;
  --text: #e7eaf0;
  --dim: #98a2b5;
  --faint: #5d6a80;
  --accent: #5891f5;
  --accent2: #3f6fd6;
  --shadow: 0 8px 30px rgba(0, 0, 0, 0.45);
}
.login-wrap {
  position: relative;
  min-height: 100vh;
  width: 100%;
  overflow: hidden;
  background:
    radial-gradient(130% 90% at 22% 28%, rgba(60, 96, 190, 0.32), transparent 46%),
    radial-gradient(120% 100% at 82% 72%, rgba(150, 72, 190, 0.20), transparent 50%),
    radial-gradient(140% 120% at 50% 108%, rgba(28, 130, 150, 0.22), transparent 52%),
    linear-gradient(180deg, #070a16 0%, #05070f 60%, #04050b 100%);
}

/* starfield — one element carrying many box-shadow points, twinkling */
.login-stars { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
/* starfield: three layers of box-shadow points, twinkling gently out of phase
   (different durations + negative delays) so the field shimmers softly rather
   than pulsing in unison. */
.login-stars i {
  position: absolute;
  top: 0;
  left: 0;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: transparent;
}
.login-stars .a { animation: login-tw-a 6.5s ease-in-out infinite; box-shadow: 81px 952px 0 0.8px rgba(255,255,255,0.51),1866px 1px 0 0.8px rgba(255,255,255,0.71),1020px 786px 0 0.3px rgba(255,255,255,0.55),291px 1034px 0 0.3px rgba(255,255,255,0.43),304px 61px 0 0.3px rgba(255,255,255,0.83),1500px 993px 0 0.8px rgba(255,255,255,0.55),1658px 1207px 0 0.3px rgba(255,255,255,0.65),2142px 245px 0 0.3px rgba(255,255,255,0.44),282px 1036px 0 0.8px rgba(255,255,255,0.81),156px 1172px 0 0.3px rgba(255,255,255,0.48),1571px 336px 0 0.8px rgba(255,255,255,0.51),948px 521px 0 0.8px rgba(255,255,255,0.52),568px 983px 0 0.8px rgba(255,255,255,0.83),1817px 1022px 0 0.3px rgba(255,255,255,0.38),962px 85px 0 0.3px rgba(255,255,255,0.55),859px 227px 0 0.8px rgba(255,255,255,0.58),142px 1203px 0 0.8px rgba(255,255,255,0.81),1880px 400px 0 0.8px rgba(255,255,255,0.81),1485px 778px 0 0.8px rgba(255,255,255,0.57),1379px 12px 0 0.3px rgba(255,255,255,0.49),1503px 880px 0 1.4px rgba(255,255,255,0.66),945px 273px 0 0.3px rgba(255,255,255,0.69),1856px 401px 0 0.3px rgba(255,255,255,0.45),180px 33px 0 0.8px rgba(255,255,255,0.64),1545px 466px 0 0.3px rgba(255,255,255,0.39),1658px 613px 0 0.3px rgba(255,255,255,0.82),1169px 1366px 0 0.8px rgba(255,255,255,0.38),1019px 351px 0 0.3px rgba(255,255,255,0.39),1138px 1150px 0 0.3px rgba(255,255,255,0.82),585px 700px 0 0.8px rgba(255,255,255,0.61),74px 1080px 0 0.8px rgba(255,255,255,0.55),1155px 86px 0 0.8px rgba(255,255,255,0.68),1373px 292px 0 0.3px rgba(255,255,255,0.36),336px 507px 0 1.4px rgba(255,255,255,0.36),529px 57px 0 0.8px rgba(255,255,255,0.42),2155px 963px 0 0.3px rgba(255,255,255,0.57),1215px 187px 0 0.8px rgba(255,255,255,0.85),2195px 317px 0 0.3px rgba(255,255,255,0.46),482px 832px 0 0.8px rgba(255,255,255,0.62),292px 1128px 0 1.4px rgba(255,255,255,0.83),1089px 263px 0 0.3px rgba(255,255,255,0.69),394px 537px 0 0.3px rgba(255,255,255,0.72),1668px 266px 0 1.4px rgba(255,255,255,0.7),165px 384px 0 0.8px rgba(255,255,255,0.72),2188px 328px 0 0.3px rgba(255,255,255,0.32),661px 837px 0 0.8px rgba(255,255,255,0.71),1940px 1171px 0 0.8px rgba(255,255,255,0.46),1945px 733px 0 0.3px rgba(255,255,255,0.85),1981px 71px 0 0.8px rgba(255,255,255,0.59),115px 627px 0 0.3px rgba(255,255,255,0.33),938px 709px 0 0.3px rgba(255,255,255,0.69),1833px 612px 0 0.3px rgba(255,255,255,0.79),2113px 1120px 0 0.3px rgba(255,255,255,0.26),3px 78px 0 0.3px rgba(255,255,255,0.75),1636px 527px 0 0.3px rgba(255,255,255,0.43),1666px 900px 0 0.3px rgba(255,255,255,0.82),298px 169px 0 0.3px rgba(255,255,255,0.71),1296px 1010px 0 0.8px rgba(255,255,255,0.67),2094px 349px 0 1.4px rgba(255,255,255,0.34),1636px 570px 0 0.8px rgba(255,255,255,0.59),146px 992px 0 0.3px rgba(255,255,255,0.36),1272px 502px 0 0.3px rgba(255,255,255,0.71),2041px 2px 0 0.8px rgba(255,255,255,0.35),1061px 1149px 0 0.3px rgba(255,255,255,0.6),1614px 1284px 0 1.4px rgba(255,255,255,0.4),1729px 1305px 0 1.4px rgba(255,255,255,0.64),1044px 1093px 0 0.8px rgba(255,255,255,0.79),766px 603px 0 0.8px rgba(255,255,255,0.38),1533px 1303px 0 0.8px rgba(255,255,255,0.59),935px 251px 0 0.3px rgba(255,255,255,0.32),1979px 962px 0 0.3px rgba(255,255,255,0.47),2187px 1206px 0 0.3px rgba(255,255,255,0.45),748px 562px 0 0.3px rgba(255,255,255,0.51),1157px 420px 0 0.3px rgba(255,255,255,0.6); }
.login-stars .b { animation: login-tw-b 4.7s ease-in-out -2.1s infinite; box-shadow: 1030px 964px 0 0.3px rgba(255,255,255,0.75),1380px 202px 0 0.8px rgba(255,255,255,0.77),1230px 128px 0 0.3px rgba(255,255,255,0.54),587px 799px 0 0.3px rgba(255,255,255,0.45),1284px 402px 0 0.8px rgba(255,255,255,0.72),1992px 989px 0 1.4px rgba(255,255,255,0.72),1025px 484px 0 0.3px rgba(255,255,255,0.26),2022px 333px 0 1.4px rgba(255,255,255,0.43),1280px 457px 0 0.8px rgba(255,255,255,0.47),819px 368px 0 0.3px rgba(255,255,255,0.69),1444px 1224px 0 1.4px rgba(255,255,255,0.36),674px 886px 0 0.3px rgba(255,255,255,0.25),202px 955px 0 0.3px rgba(255,255,255,0.35),349px 890px 0 0.8px rgba(255,255,255,0.37),1327px 501px 0 0.8px rgba(255,255,255,0.37),1770px 863px 0 0.3px rgba(255,255,255,0.78),191px 868px 0 0.8px rgba(255,255,255,0.42),668px 382px 0 1.4px rgba(255,255,255,0.41),1973px 1262px 0 0.3px rgba(255,255,255,0.45),662px 1159px 0 0.3px rgba(255,255,255,0.68),143px 332px 0 0.8px rgba(255,255,255,0.25),350px 234px 0 0.8px rgba(255,255,255,0.6),1041px 208px 0 0.3px rgba(255,255,255,0.53),896px 1024px 0 0.8px rgba(255,255,255,0.66),1645px 945px 0 1.4px rgba(255,255,255,0.71),988px 131px 0 0.3px rgba(255,255,255,0.45),1317px 598px 0 0.3px rgba(255,255,255,0.65),1254px 208px 0 0.8px rgba(255,255,255,0.32),1675px 891px 0 1.4px rgba(255,255,255,0.63),152px 1300px 0 0.3px rgba(255,255,255,0.59),444px 142px 0 1.4px rgba(255,255,255,0.52),870px 55px 0 0.8px rgba(255,255,255,0.44),128px 738px 0 0.3px rgba(255,255,255,0.52),933px 365px 0 0.8px rgba(255,255,255,0.45),2033px 1280px 0 0.8px rgba(255,255,255,0.62),570px 1371px 0 0.8px rgba(255,255,255,0.74),2191px 144px 0 0.3px rgba(255,255,255,0.49),2091px 786px 0 1.4px rgba(255,255,255,0.74),433px 153px 0 0.3px rgba(255,255,255,0.84),703px 1337px 0 0.8px rgba(255,255,255,0.36),1597px 1262px 0 0.3px rgba(255,255,255,0.43),1470px 443px 0 0.3px rgba(255,255,255,0.68),35px 352px 0 0.3px rgba(255,255,255,0.59),2032px 1291px 0 0.8px rgba(255,255,255,0.36),2038px 1357px 0 0.3px rgba(255,255,255,0.38),1164px 69px 0 0.3px rgba(255,255,255,0.28),2066px 54px 0 0.3px rgba(255,255,255,0.28),1518px 37px 0 1.4px rgba(255,255,255,0.62),340px 262px 0 0.3px rgba(255,255,255,0.73),308px 721px 0 1.4px rgba(255,255,255,0.44),564px 154px 0 0.8px rgba(255,255,255,0.66),422px 1386px 0 0.8px rgba(255,255,255,0.48),375px 550px 0 0.8px rgba(255,255,255,0.78),886px 1391px 0 0.8px rgba(255,255,255,0.41),1911px 1032px 0 0.8px rgba(255,255,255,0.6),457px 903px 0 0.8px rgba(255,255,255,0.32),957px 196px 0 0.8px rgba(255,255,255,0.76),627px 726px 0 0.8px rgba(255,255,255,0.61),2152px 132px 0 1.4px rgba(255,255,255,0.74),1581px 906px 0 1.4px rgba(255,255,255,0.61),2120px 556px 0 0.8px rgba(255,255,255,0.49),1169px 932px 0 0.8px rgba(255,255,255,0.71),540px 353px 0 0.3px rgba(255,255,255,0.76),1347px 961px 0 1.4px rgba(255,255,255,0.7),1524px 670px 0 0.3px rgba(255,255,255,0.68),1621px 17px 0 0.8px rgba(255,255,255,0.76),1860px 1px 0 0.8px rgba(255,255,255,0.69),1810px 1122px 0 0.8px rgba(255,255,255,0.52),1407px 572px 0 0.3px rgba(255,255,255,0.8),2059px 638px 0 0.3px rgba(255,255,255,0.45),2117px 333px 0 0.8px rgba(255,255,255,0.54),1446px 1213px 0 0.8px rgba(255,255,255,0.71),1736px 278px 0 0.3px rgba(255,255,255,0.82); }
.login-stars .c { animation: login-tw-c 8.3s ease-in-out -4.4s infinite; box-shadow: 584px 1367px 0 0.8px rgba(255,255,255,0.79),1605px 1103px 0 0.8px rgba(255,255,255,0.8),1671px 456px 0 1.4px rgba(255,255,255,0.4),667px 337px 0 0.8px rgba(255,255,255,0.65),415px 111px 0 1.4px rgba(255,255,255,0.29),566px 1196px 0 0.3px rgba(255,255,255,0.67),1384px 329px 0 0.3px rgba(255,255,255,0.46),520px 20px 0 0.3px rgba(255,255,255,0.38),1790px 551px 0 0.8px rgba(255,255,255,0.84),424px 746px 0 0.8px rgba(255,255,255,0.59),1995px 1285px 0 0.3px rgba(255,255,255,0.26),1030px 595px 0 1.4px rgba(255,255,255,0.42),1054px 1239px 0 0.3px rgba(255,255,255,0.64),1061px 1350px 0 1.4px rgba(255,255,255,0.41),1933px 1395px 0 0.3px rgba(255,255,255,0.63),66px 31px 0 1.4px rgba(255,255,255,0.61),1565px 112px 0 0.3px rgba(255,255,255,0.76),123px 207px 0 1.4px rgba(255,255,255,0.7),52px 825px 0 1.4px rgba(255,255,255,0.84),720px 1031px 0 0.3px rgba(255,255,255,0.54),214px 1340px 0 0.8px rgba(255,255,255,0.29),1147px 682px 0 0.3px rgba(255,255,255,0.58),909px 1149px 0 0.3px rgba(255,255,255,0.25),1804px 699px 0 0.3px rgba(255,255,255,0.47),1984px 621px 0 1.4px rgba(255,255,255,0.67),288px 875px 0 0.8px rgba(255,255,255,0.81),2002px 470px 0 0.3px rgba(255,255,255,0.26),184px 634px 0 0.3px rgba(255,255,255,0.69),1758px 238px 0 0.3px rgba(255,255,255,0.6),1216px 1016px 0 0.3px rgba(255,255,255,0.59),463px 750px 0 0.3px rgba(255,255,255,0.52),2164px 681px 0 0.3px rgba(255,255,255,0.32),1491px 1069px 0 0.8px rgba(255,255,255,0.6),584px 995px 0 0.3px rgba(255,255,255,0.28),1560px 1247px 0 1.4px rgba(255,255,255,0.38),1352px 464px 0 0.3px rgba(255,255,255,0.41),1180px 1134px 0 0.8px rgba(255,255,255,0.48),1272px 117px 0 0.3px rgba(255,255,255,0.37),641px 1354px 0 0.3px rgba(255,255,255,0.82),1413px 153px 0 0.3px rgba(255,255,255,0.41),1423px 689px 0 0.3px rgba(255,255,255,0.66),1098px 1386px 0 0.8px rgba(255,255,255,0.31),10px 323px 0 0.3px rgba(255,255,255,0.29),350px 854px 0 0.8px rgba(255,255,255,0.79),2052px 875px 0 0.8px rgba(255,255,255,0.84),897px 989px 0 0.3px rgba(255,255,255,0.7),1436px 238px 0 0.3px rgba(255,255,255,0.52),237px 187px 0 0.8px rgba(255,255,255,0.39),526px 944px 0 0.8px rgba(255,255,255,0.8),1286px 1071px 0 0.3px rgba(255,255,255,0.73),1608px 1272px 0 0.3px rgba(255,255,255,0.5),608px 578px 0 1.4px rgba(255,255,255,0.77),1610px 1328px 0 1.4px rgba(255,255,255,0.26),432px 972px 0 0.3px rgba(255,255,255,0.54),282px 957px 0 0.3px rgba(255,255,255,0.68),1344px 631px 0 1.4px rgba(255,255,255,0.78),1974px 485px 0 0.8px rgba(255,255,255,0.84),1800px 1371px 0 0.8px rgba(255,255,255,0.41),371px 215px 0 1.4px rgba(255,255,255,0.57),1785px 1205px 0 0.8px rgba(255,255,255,0.54),1311px 1077px 0 0.3px rgba(255,255,255,0.54),535px 58px 0 0.3px rgba(255,255,255,0.71),1006px 902px 0 0.3px rgba(255,255,255,0.52),685px 921px 0 0.3px rgba(255,255,255,0.64),492px 1347px 0 0.3px rgba(255,255,255,0.77),2009px 762px 0 0.8px rgba(255,255,255,0.48),220px 1292px 0 0.3px rgba(255,255,255,0.77),1134px 623px 0 0.3px rgba(255,255,255,0.43),319px 1068px 0 0.3px rgba(255,255,255,0.35),546px 1388px 0 1.4px rgba(255,255,255,0.84),1532px 853px 0 0.8px rgba(255,255,255,0.49),2084px 933px 0 0.8px rgba(255,255,255,0.5),127px 467px 0 0.3px rgba(255,255,255,0.33); }

/* four fixed nebula scenes (a CSS stand-in for the Rubin sky slideshow) — no
   transitions; js/main.js reveals exactly one at random on each login. */
.login-scene { position: absolute; inset: 0; z-index: 1; opacity: 0; }
.login-scene.is-active { opacity: 1; }
.login-scene > div { position: absolute; inset: 0; overflow: hidden; }
.login-scene-0 > div {
  background:
    radial-gradient(70% 55% at 28% 30%, rgba(70, 120, 230, 0.42), transparent 60%),
    radial-gradient(60% 50% at 75% 80%, rgba(30, 150, 170, 0.30), transparent 62%);
}
.login-scene-1 > div {
  background:
    radial-gradient(65% 60% at 70% 40%, rgba(160, 80, 210, 0.40), transparent 60%),
    radial-gradient(55% 50% at 25% 75%, rgba(60, 90, 200, 0.30), transparent 60%);
}
.login-scene-2 > div {
  background:
    linear-gradient(120deg, transparent 20%, rgba(40, 170, 190, 0.30) 48%, transparent 72%),
    radial-gradient(60% 55% at 55% 30%, rgba(90, 120, 235, 0.28), transparent 62%);
}
.login-scene-3 > div {
  background:
    radial-gradient(60% 55% at 60% 68%, rgba(210, 90, 150, 0.34), transparent 60%),
    radial-gradient(55% 50% at 30% 30%, rgba(220, 160, 90, 0.20), transparent 60%);
}

/* legibility overlay */
.login-dim {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    radial-gradient(120% 110% at 50% 34%, transparent 30%, rgba(4, 6, 14, 0.62) 100%),
    linear-gradient(180deg, rgba(4, 6, 14, 0.45) 0%, transparent 26%, transparent 70%, rgba(4, 6, 14, 0.5) 100%);
}

/* wordmark (top-left) */
.login-wordmark {
  position: absolute;
  top: 26px;
  left: 30px;
  z-index: 5;
  display: flex;
  align-items: baseline;
  gap: 13px;
}
.login-wm-logo {
  font: 400 34px/1 "Dune Rise", "Geist", system-ui, sans-serif;
  letter-spacing: 0.02em;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.55);
}
.login-wm-logo .m { color: #c58af9; }
.login-wm-logo .pp { color: #e7eaf0; }
.login-wm-logo .db { color: #5891f5; }
.login-wm-tag {
  font: 600 12px/1 "JetBrains Mono", ui-monospace, monospace;
  letter-spacing: 0.24em;
  color: rgba(210, 220, 245, 0.72);
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6);
}

/* content column (above the background layers) */
.login-content {
  position: relative;
  z-index: 3;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
}
.login-box {
  width: 100%;
  max-width: 452px;
  animation: login-float-in 0.8s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
.login-tagline {
  position: absolute;
  right: 30px;
  bottom: 26px;
  z-index: 5;
  margin: 0;
  max-width: min(62vw, 430px);
  font: 400 11.55px/1.5 "JetBrains Mono", ui-monospace, monospace;
  color: rgba(214, 223, 244, 0.9);
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.5);
  text-align: right;
}

@keyframes login-float-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }
@keyframes login-tw-a { 0%, 100% { opacity: 0.42; } 50% { opacity: 0.82; } }
@keyframes login-tw-b { 0%, 100% { opacity: 0.55; } 50% { opacity: 0.90; } }
@keyframes login-tw-c { 0%, 100% { opacity: 0.32; } 50% { opacity: 0.68; } }

@media (prefers-reduced-motion: reduce) {
  .login-box,
  .login-stars .a,
  .login-stars .b,
  .login-stars .c { animation: none !important; }
}
.login-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 13px;
  padding: 22px;
  box-shadow: var(--shadow);
  margin: 0;
}
.login-label {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--dim);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}
.login-input {
  width: 100%;
  margin-top: 8px;
  padding: 11px 13px;
  background: var(--panel2);
  border: 1px solid var(--border2);
  border-radius: 9px;
  color: var(--text);
  font: 500 13px "JetBrains Mono";
  outline: none;
}
.login-input:focus { border-color: var(--accent); }
.login-connect { width: 100%; margin-top: 14px; padding: 11px; font: 600 13px "Geist"; }
.login-error {
  margin-top: 14px;
  padding: 10px 12px;
  background: var(--errSoft);
  border: 1px solid var(--err);
  border-radius: 9px;
  color: var(--text);
  font: 400 12px/1.5 "JetBrains Mono";
  overflow-wrap: anywhere;
}

/* WP-22 §8.2 auth flow: the multi-panel card rendered by js/login.js. Reuses
   the login tokens above; only the flow-specific bits are new. */
.login-card-head { font: 600 15px "Geist"; color: var(--text); margin-bottom: 4px; }
.login-card-sub { font-size: 12px; color: var(--dim); line-height: 1.5; margin-bottom: 16px; }
.login-gap { height: 12px; }
.login-optional { color: var(--faint); font-weight: 500; text-transform: none; letter-spacing: 0; }
.login-message { font-size: 13px; color: var(--dim); line-height: 1.6; margin-bottom: 16px; }
.login-notice {
  margin-bottom: 14px;
  padding: 9px 11px;
  background: var(--panel2);
  border: 1px solid var(--border2);
  border-radius: 9px;
  font-size: 12px;
  color: var(--dim);
}
.login-links {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 14px;
}
.login-link {
  font: 500 12px "Geist";
  color: var(--accent);
  text-decoration: none;
  cursor: pointer;
}
.login-link:hover { text-decoration: underline; }

/* the sidebar chip is a button now (§8.3): profile trigger, hover affordance */
.user-chip {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  color: inherit;
  border-radius: 8px;
}
.user-chip:hover { opacity: 0.85; }

/* stage-F read-only profile pane (§8.3/§8.4) */
.profile-view { padding: 22px 26px; overflow: auto; }
.profile-card {
  max-width: 640px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 13px;
  padding: 22px;
}
.profile-head { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.profile-title { font: 600 16px "Geist"; color: var(--text); }
.profile-grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 10px 20px;
  align-items: baseline;
}
.profile-key {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.profile-val { font: 500 13px "JetBrains Mono"; color: var(--text); overflow-wrap: anywhere; }
.profile-note { margin-top: 20px; font-size: 12px; color: var(--faint); }

/* WP-22 §8.4 editable profile pane (js/profile.js) — reuses the login-input /
   login-label / btn-accent / pill-btn tokens; only the layout pieces are new. */
.profile-section {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}
.profile-section:first-of-type { margin-top: 0; padding-top: 0; border-top: none; }
.profile-section-title {
  font: 600 12px "Geist";
  color: var(--text);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 12px;
}
.profile-actions { display: flex; gap: 10px; margin-top: 14px; align-items: center; }
.profile-hint { font-size: 12px; color: var(--dim); line-height: 1.5; margin: 4px 0 12px; }
.profile-token {
  padding: 11px 13px;
  background: var(--panel2);
  border: 1px solid var(--border2);
  border-radius: 9px;
  color: var(--text);
  font: 500 12px "JetBrains Mono";
  overflow-wrap: anywhere;
  user-select: all;
}
.profile-banner {
  margin: 10px 0;
  padding: 9px 12px;
  border-radius: 9px;
  font: 400 12px/1.5 "JetBrains Mono";
  overflow-wrap: anywhere;
}
.profile-banner-ok { background: var(--okSoft); border: 1px solid var(--ok); color: var(--text); }
.profile-banner-err { background: var(--errSoft); border: 1px solid var(--err); color: var(--text); }

/* WP-22 §8.5 admin console (js/admin.js) — the user table reuses .result-table;
   the edit modal reuses .modal / .modal-head. */
.admin-view { padding: 22px 26px; overflow: auto; }
.admin-wrap { max-width: 1100px; }
.admin-table-scroll { overflow-x: auto; border: 1px solid var(--border); border-radius: 10px; }
.admin-table { font-size: 12px; }
.admin-table th { cursor: pointer; white-space: nowrap; }
.admin-table td.num, .admin-table th.num { text-align: right; }
.admin-row { cursor: pointer; }
.admin-approve { display: inline-flex; margin-left: 6px; }
.admin-modal { width: min(720px, 96vw); }
.admin-modal-body { padding: 16px; overflow: auto; }
.admin-form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px 16px;
}
.admin-field { display: flex; flex-direction: column; gap: 6px; }
.admin-field-check { flex-direction: row; align-items: center; gap: 10px; }
.admin-select {
  padding: 10px 12px;
  background: var(--panel2);
  border: 1px solid var(--border2);
  border-radius: 9px;
  color: var(--text);
  font: 500 13px "JetBrains Mono";
  outline: none;
}
.admin-overrides-note {
  grid-column: 1 / -1;
  font-size: 11px;
  color: var(--faint);
  margin-top: 6px;
}
.admin-actions { display: flex; gap: 10px; margin-top: 16px; align-items: center; flex-wrap: wrap; }
.admin-events { display: flex; gap: 20px; margin-top: 20px; flex-wrap: wrap; }
.admin-events-col { flex: 1; min-width: 240px; }
.admin-event {
  font-size: 11px;
  color: var(--dim);
  padding: 4px 0;
  border-bottom: 1px solid var(--border);
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------- shell */
.shell {
  height: 100vh;
  display: grid;
  grid-template-columns: 278px minmax(0, 1fr);
  background: var(--bg);
  transition: grid-template-columns 0.28s cubic-bezier(0.2, 0, 0, 1);
}
.shell.rail-is-collapsed { grid-template-columns: 57px minmax(0, 1fr); }

/* ---------------------------------------------------------------- rail */
/* Collapse/expand animates the shell's grid column while the two rail
 * contents crossfade, all driven by .rail-is-collapsed (no hidden-attribute
 * swaps): the full panel keeps its natural width (min-width) and is clipped
 * by the rail while it fades; the mini rail sits absolutely over the same
 * space and fades in slightly late, as the width settles. */
.rail {
  height: 100vh;
  display: flex;
  position: relative;
  overflow: hidden;
  background: var(--panel);
  border-right: 1px solid var(--border);
  min-width: 0;
}
.rail-collapsed {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 56px;
  display: flex;
  flex-direction: column;
  align-items: center;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.14s ease, visibility 0s linear 0.14s;
}
.rail-is-collapsed .rail-collapsed {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.14s ease 0.12s, visibility 0s;
}
.rail-is-collapsed .rail-panel {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.12s ease, visibility 0s linear 0.12s;
}
@media (prefers-reduced-motion: reduce) {
  .shell, .rail-panel, .rail-collapsed { transition: none; }
}
.rail-collapsed-logo {
  height: 52px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-bottom: 1px solid var(--border);
  background: transparent;
  cursor: pointer;
  font: 400 22px "Dune Rise", "Geist", sans-serif;
}
.rail-collapsed-logo .mword-m { color: var(--mcolor); }
.rail-collapsed-logo:hover { background: var(--panel2); }
.rail-collapsed-new {
  margin-top: 12px;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 9px;
  background: var(--panel2);
  color: var(--accent);
  font-size: 15px;
  cursor: pointer;
}
.rail-collapsed-new:hover { background: var(--panel3); }
.rail-panel {
  flex: 1;
  min-width: 277px; /* keep natural width while the rail clips it mid-animation */
  display: flex;
  flex-direction: column;
  transition: opacity 0.14s ease 0.1s, visibility 0s;
}
.rail-brand {
  flex: none;
  height: 44px; /* match the notebook .toolbar height so the two header bars' bottom borders align */
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0 12px 0 15px;
  border-bottom: 1px solid var(--border);
}
.wordmark { font: 400 20px "Dune Rise", "Geist", sans-serif; letter-spacing: 0.05em; }
.mword-m { color: var(--mcolor); }
.mword-db { color: var(--accent); }
.icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--dim);
  font-size: 16px;
  cursor: pointer;
  flex: none;
}
.icon-btn:hover { background: var(--panel2); color: var(--text); }
.rail-new { flex: none; padding: 10px 12px 4px; }
.new-thread-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 12px;
  background: var(--panel2);
  border: none;
  border-radius: var(--radius);
  color: var(--dim);
  font: 600 12.5px "Geist";
  cursor: pointer;
}
.new-thread-btn:hover { background: var(--panel3); color: var(--text); }
.new-thread-btn .acc { font-size: 14px; }
.rail-scroll { flex: 1; overflow-y: auto; padding: 2px 8px 8px; min-height: 60px; }
.rail-header {
  padding: 8px 6px 5px;
  font: 600 10px "Geist";
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--faint);
}
.rail-header-later { padding-top: 14px; }

/* history */
.history-empty { padding: 4px 9px 6px; font: 400 11px "Geist"; color: var(--faint); }
.history-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 9px;
  margin-bottom: 1px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  text-align: left;
}
.history-item:hover { background: var(--panel2); }
.history-dot { width: 5px; height: 5px; border-radius: 50%; flex: none; background: var(--ok); }
.history-dot-error { background: var(--err); }
.history-dot-overflow { background: var(--warn); }
.history-snippet {
  flex: 1;
  min-width: 0;
  font: 500 11px "JetBrains Mono";
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--dim);
}
.history-item:hover .history-snippet { color: var(--text); }
.history-when { font: 400 9.5px "JetBrains Mono"; color: var(--faint); flex: none; }

/* schema */
.schema-search {
  width: 100%;
  margin: 2px 0 6px;
  padding: 7px 10px;
  background: var(--panel2);
  border: 1px solid var(--border);
  border-radius: 7px;
  color: var(--text);
  font: 400 12px "Geist";
  outline: none;
}
.schema-search:focus { border-color: var(--accent); }
.schema-table { margin-bottom: 1px; }
.schema-table-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 8px;
  background: transparent;
  border: none;
  border-radius: 7px;
  cursor: pointer;
  text-align: left;
}
.schema-table-btn:hover { background: var(--panel2); }
.schema-caret { color: var(--faint); font-size: 9px; width: 8px; flex: none; transition: transform 0.12s; }
.schema-caret-open { transform: rotate(90deg); }
/* shrink-to-fit (ellipsized when long) so the peek pill sits right after the
 * name; the row's spacer pushes the count to the right edge */
.schema-table-name { flex: 0 1 auto; min-width: 0; font: 600 12px "JetBrains Mono"; color: var(--accent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.schema-table-count { font: 400 9.5px "JetBrains Mono"; color: var(--faint); }
.schema-cols { padding: 2px 4px 8px 22px; }
.schema-desc { font-size: 10.5px; color: var(--dim); line-height: 1.4; margin: 2px 0 6px; }
.schema-col {
  display: flex;
  align-items: baseline;
  gap: 7px;
  padding: 4px 7px;
  border-radius: 6px;
  cursor: pointer;
}
.schema-col:hover { background: var(--panel2); }
.schema-col-name { font: 500 11px "JetBrains Mono"; color: var(--text); }
.schema-col-unit { font: 400 9.5px "JetBrains Mono"; color: var(--warn); }
.schema-col-desc {
  flex: 1;
  font-size: 10px;
  color: var(--faint);
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.schema-loading { padding: 6px 9px; font: 400 11px "Geist"; color: var(--faint); }

/* docked jobs */
.rail-jobs {
  flex: none;
  display: flex;
  flex-direction: column;
  max-height: 42%;
  border-top: 1px solid var(--border);
  background: var(--panel2);
}
.rail-jobs-head { flex: none; display: flex; align-items: center; gap: 8px; padding: 10px 14px 7px; }
.rail-jobs-title {
  font: 600 10px "Geist";
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--dim);
}
.jobs-count-chip {
  font: 600 9px "JetBrains Mono";
  color: var(--accent);
  padding: 1px 6px;
  background: var(--accentSoft);
  border-radius: 20px;
}
.jobs-list { flex: 1; overflow-y: auto; padding: 0 8px 8px; }
.jobs-empty { padding: 2px 8px 6px; font: 400 11px "Geist"; color: var(--faint); }
.job-card {
  padding: 9px;
  margin: 0 2px 6px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.job-row { display: flex; align-items: center; gap: 7px; }
.job-elapsed { font: 400 9.5px "JetBrains Mono"; color: var(--faint); }
.job-snippet {
  margin-top: 6px;
  font: 500 11px "JetBrains Mono";
  color: var(--text);
  line-height: 1.35;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.job-error-line { margin-top: 5px; font: 400 10.5px/1.4 "JetBrains Mono"; color: var(--err); overflow-wrap: anywhere; }
.job-actions { display: flex; gap: 6px; margin-top: 7px; }
.job-action {
  padding: 4px 9px;
  background: transparent;
  border: 1px solid var(--border2);
  border-radius: 7px;
  color: var(--dim);
  font: 500 10.5px "Geist";
  cursor: pointer;
}
.job-action:hover { border-color: var(--accent); color: var(--text); }
.job-action-danger:hover { border-color: var(--err); color: var(--err); }

/* phase chips */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border-radius: 20px;
  font: 600 10px "JetBrains Mono";
  letter-spacing: 0.03em;
  white-space: nowrap;
}
.chip-dot { width: 6px; height: 6px; border-radius: 50%; background: currentcolor; }
.chip-ok { background: var(--okSoft); color: var(--ok); }
.chip-exec { background: var(--accentSoft); color: var(--accent); }
.chip-warn { background: var(--warnSoft); color: var(--warn); }
.chip-err { background: var(--errSoft); color: var(--err); }
.chip-dim { background: var(--panel3); color: var(--dim); }
.spinner {
  width: 9px;
  height: 9px;
  border: 1.5px solid currentcolor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: mp-spin 0.7s linear infinite;
}

/* user chip */
.rail-user {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 12px;
  border-top: 1px solid var(--border);
}
.user-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font: 700 11px "Geist";
  color: #fff;
  flex: none;
  text-transform: uppercase;
}
.user-meta { flex: 1; min-width: 0; }
.user-name { font-size: 11px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-sub { font-size: 9.5px; color: var(--faint); }
.ghost-btn {
  background: none;
  border: none;
  color: var(--faint);
  font: 500 11px "Geist";
  cursor: pointer;
  padding: 2px 4px;
  flex: none;
}
.ghost-btn:hover { color: var(--err); }
#jobs-refresh:hover { color: var(--accent); }

/* ---------------------------------------------------------------- main */
.main { height: 100vh; display: flex; flex-direction: column; min-width: 0; background: var(--app); }

/* ------------------------------------------------ WP-25 toolbar (§5) */
/* One 44px row, always visible (flex:none); the notebook scrolls in #content
 * below it, the page itself never scrolls. Replaces the WP-24 .main-header.
 * The WP-24 sidebar (#rail) is retained (owner reversed decision #3). */
.toolbar {
  flex: none;
  height: 44px;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 12px;
  border-bottom: 1px solid var(--line);
  font-family: var(--sans);
}
.main-title,
.nbtitle { font: 600 13.5px var(--sans); color: var(--text); }
.tbpen {
  background: none;
  border: none;
  color: var(--faint);
  font-size: 12px;
  cursor: pointer;
  padding: 2px 4px;
  flex: none;
}
.tbpen:hover { color: var(--in); }
.tsep { width: 1px; height: 20px; background: var(--line); margin: 0 4px; flex: none; }
/* icon toolbar buttons (mock's .tb) */
.tb {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: none;
  background: none;
  border-radius: 6px;
  color: var(--muted);
  cursor: pointer;
  flex: none;
}
.tb:hover { background: var(--line2); color: var(--text); }
.tb:disabled { color: var(--faint); cursor: default; background: none; opacity: 0.55; }
.tb svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.tb.play svg, .tb.stopb svg, .tb.runall svg { fill: currentColor; stroke: none; }
/* WP-27 §4.1: the save-outputs toggle's "on" (pressed) state — accent-tinted,
   so the default-on saving reads as active at rest. */
.tb.save-outputs.on { color: var(--accent); }
.tb.save-outputs.on:hover { color: var(--accent); background: var(--accentSoft); }
/* sync indicator (§4a): ✓ synced / ⚠ sync lost, keyed on data-sync */
.sync-ind {
  display: inline-flex;
  align-items: center;
  font: 500 11.5px var(--sans);
  white-space: nowrap;
  flex: none;
  margin-right: 2px;
}
.sync-ind::before { font-family: var(--sans); }
.sync-ind[data-sync="ok"] { color: var(--edit); }
.sync-ind[data-sync="ok"]::before { content: "✓ synced"; }
.sync-ind[data-sync="syncing"] { color: var(--muted); }
.sync-ind[data-sync="syncing"]::before { content: "↻ syncing"; }
.sync-ind[data-sync="lost"] { color: var(--stale); }
.sync-ind[data-sync="lost"]::before { content: "⚠ sync lost"; }
/* cell-type dropdown */
.celltype-wrap { position: relative; flex: none; }
.celltype {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  border: 1px solid var(--line);
  border-radius: 7px;
  color: var(--text);
  font: 500 12px var(--sans);
  background: var(--app);
  cursor: pointer;
}
.celltype:hover { border-color: var(--codeline); background: var(--line2); }
.celltype:disabled { color: var(--muted); cursor: default; }
.celltype .car { color: var(--faint); font-size: 10px; }
#celltype-menu { top: 34px; left: 0; right: auto; bottom: auto; min-width: 130px; z-index: 40; }
/* kernel identity + dot (§5): green idle, orange pulsing halo while running */
.kernel { display: flex; align-items: center; gap: 7px; font: 500 11.5px var(--sans); color: var(--muted); flex: none; }
.kdot { width: 8px; height: 8px; border-radius: 50%; background: var(--edit); flex: none; }
.kdot.busy {
  background: var(--kernel);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--kernel) 22%, transparent);
  animation: kdot-pulse 1.4s ease-in-out infinite;
}
@keyframes kdot-pulse {
  0%, 100% { box-shadow: 0 0 0 2px color-mix(in srgb, var(--kernel) 24%, transparent); }
  50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--kernel) 8%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .kdot.busy { animation: none; }
}
/* app-chrome buttons kept from the WP-24 header (theme / shortcuts / status /
 * admin), now on the toolbar with their existing ids + role-gating */
.hdr-btn {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 5px 9px;
  background: var(--panel2);
  border: 1px solid var(--border);
  border-radius: 7px;
  color: var(--dim);
  font: 500 11.5px "Geist";
  cursor: pointer;
  flex: none;
}
.hdr-btn:hover { background: var(--panel3); color: var(--text); }
.content { flex: 1; overflow-y: auto; padding: 0 28px; background: var(--app); }

/* empty state */
.empty-state {
  min-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px 24px;
}
.empty-title { font: 600 26px "Geist"; letter-spacing: -0.02em; margin-bottom: 6px; text-align: center; }
.empty-sub { font-size: 13px; color: var(--dim); margin-bottom: 26px; text-align: center; }
.empty-examples { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; max-width: 680px; }
.example-chip {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 11px 14px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  text-align: left;
  max-width: 320px;
}
.example-chip:hover { border-color: var(--accent); }
.example-chip-play { color: var(--accent); font-size: 12px; }
.example-chip-title { font: 500 12px "Geist"; color: var(--text); line-height: 1.3; }

/* WP-29 demo-notebook onboarding nudge — a main-pane overlay (position:fixed,
 * placed by js/demo-nudge.js) whose tail points left at the demo's rail row.
 * A rounded card with a lavender sparkle chip, a soft shadow, and a gentle
 * purple glow pulse (disabled under prefers-reduced-motion). Theme-aware via
 * the shared tokens; --brandM is the mppdb purple (defined for both themes). */
.demo-nudge {
  position: fixed;
  z-index: 55; /* above the console + rail, below modal backdrops */
  transform: translateY(-50%); /* js sets `top` to the row's vertical center */
  display: flex;
  align-items: center;
  gap: 11px;
  max-width: 288px;
  padding: 11px 12px 11px 14px;
  background: var(--panel);
  border: 1px solid color-mix(in srgb, var(--brandM) 42%, var(--border));
  border-radius: 14px;
  cursor: pointer;
  box-shadow: var(--shadow), 0 0 0 1px color-mix(in srgb, var(--brandM) 18%, transparent),
    0 0 16px 1px color-mix(in srgb, var(--brandM) 22%, transparent);
  animation: demo-nudge-glow 2.4s ease-in-out infinite;
}
.demo-nudge:hover {
  border-color: color-mix(in srgb, var(--brandM) 62%, var(--border));
}
/* left-pointing tail: a rotated square showing its left+bottom border, seated
 * on the card's left edge so it reads as one shape connecting to the rail. */
.demo-nudge::before {
  content: "";
  position: absolute;
  left: -7px;
  top: 50%;
  width: 12px;
  height: 12px;
  transform: translateY(-50%) rotate(45deg);
  background: var(--panel);
  border-left: 1px solid color-mix(in srgb, var(--brandM) 42%, var(--border));
  border-bottom: 1px solid color-mix(in srgb, var(--brandM) 42%, var(--border));
  border-radius: 0 0 0 3px;
}
.demo-nudge-chip {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  line-height: 1;
  color: var(--brandM);
  background: color-mix(in srgb, var(--brandM) 20%, var(--panel));
}
.demo-nudge-text {
  flex: 1;
  font: 600 12.5px "Geist";
  line-height: 1.35;
  color: var(--text);
}
.demo-nudge-close {
  flex: none;
  align-self: flex-start;
  margin: -2px -2px 0 0;
  padding: 2px 4px;
  border: none;
  background: transparent;
  color: var(--faint);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  border-radius: 5px;
}
.demo-nudge-close:hover { color: var(--text); background: var(--panel3); }
@keyframes demo-nudge-glow {
  0%, 100% {
    box-shadow: var(--shadow), 0 0 0 1px color-mix(in srgb, var(--brandM) 18%, transparent),
      0 0 14px 1px color-mix(in srgb, var(--brandM) 20%, transparent);
  }
  50% {
    box-shadow: var(--shadow), 0 0 0 1px color-mix(in srgb, var(--brandM) 34%, transparent),
      0 0 26px 5px color-mix(in srgb, var(--brandM) 34%, transparent);
  }
}
@media (prefers-reduced-motion: reduce) {
  .demo-nudge { animation: none; }
}

/* result card (the table peek's chrome; notebook outputs reuse pieces) */
.result-card {
  margin: 0 0 6px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.result-head {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 15px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.result-table-name { font: 600 12px "JetBrains Mono"; color: var(--text); }
.result-summary { font: 400 11px "JetBrains Mono"; color: var(--dim); }
.seg {
  display: flex;
  gap: 3px;
  padding: 3px;
  background: var(--panel2);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.seg-btn {
  padding: 4px 10px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font: 600 10.5px "Geist";
  background: transparent;
  color: var(--dim);
  white-space: nowrap;
}
.seg-btn:hover { color: var(--text); }
.seg-active { background: var(--accent); color: #fff; }
.seg-active:hover { color: #fff; }

.table-scroll { overflow: auto; max-height: 46vh; }
.result-table { border-collapse: collapse; width: max-content; min-width: 100%; }
.result-table thead tr { position: sticky; top: 0; z-index: 1; }
.result-table th {
  text-align: right;
  padding: 7px 13px;
  background: var(--panel2);
  border-bottom: 1px solid var(--border2);
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
}
.result-table th:hover .th-name { color: var(--accent); }
.th-name { font: 600 10.5px "JetBrains Mono"; color: var(--text); }
.th-unit { font: 400 9px "JetBrains Mono"; color: var(--faint); height: 11px; }
.result-table td {
  padding: 5px 13px;
  font: 400 11px "JetBrains Mono";
  color: var(--text);
  white-space: nowrap;
  text-align: right;
}
.result-table tbody tr { border-bottom: 1px solid var(--border); }
.result-table tbody tr:hover { background: var(--panel2); }
.td-null { color: var(--faint); font-style: italic; }
.result-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  border-top: 1px solid var(--border);
}
.page-label { font: 400 10.5px "JetBrains Mono"; color: var(--dim); }
.page-btn {
  padding: 5px 11px;
  border-radius: 7px;
  border: 1px solid var(--border2);
  background: transparent;
  color: var(--dim);
  font: 500 11px "Geist";
  cursor: pointer;
}
.page-btn:disabled { color: var(--faint); opacity: 0.5; cursor: default; }
.page-btn:not(:disabled):hover { border-color: var(--accent); color: var(--text); }

/* error card */
.error-card {
  margin: 0 0 6px;
  display: flex;
  gap: 11px;
  padding: 14px 16px;
  background: var(--errSoft);
  border: 1px solid var(--err);
  border-radius: var(--radius);
}
.error-icon { color: var(--err); font-size: 15px; line-height: 1.2; }
.error-body { flex: 1; min-width: 0; }
.error-title { font: 600 12px "Geist"; color: var(--err); }
.error-msg {
  margin-top: 4px;
  font: 400 12px/1.5 "JetBrains Mono";
  color: var(--text);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.error-edit {
  margin-top: 9px;
  background: none;
  border: none;
  color: var(--err);
  font: 600 11px "Geist";
  cursor: pointer;
  padding: 0;
}
.error-edit:hover { color: var(--text); }

/* ---------------------------------------------------------------- buttons */
.pill-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--panel2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--dim);
  font: 500 11px "Geist";
  cursor: pointer;
  white-space: nowrap;
}
.pill-btn:hover { color: var(--text); border-color: var(--border2); }
.btn-accent {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 8px 16px;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 9px;
  font: 600 12.5px "Geist";
  cursor: pointer;
  white-space: nowrap;
}
.btn-accent:hover { background: var(--accent2); }
.btn-accent:disabled { opacity: 0.55; cursor: default; }

/* menus */
.menu-anchor { position: relative; }
.menu {
  position: absolute;
  right: 0;
  bottom: 36px;
  z-index: 30;
  min-width: 170px;
  max-width: 340px;
  max-height: 300px;
  overflow-y: auto;
  background: var(--panel2);
  border: 1px solid var(--border2);
  border-radius: 9px;
  box-shadow: var(--shadow);
  padding: 5px;
}
.menu-item {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  background: transparent;
  border: none;
  border-radius: 6px;
  color: var(--text);
  font: 500 11.5px "Geist";
  cursor: pointer;
  text-align: left;
  white-space: nowrap;
}
.menu-item:hover { background: var(--panel3); }
.menu-ext { font-size: 10px; color: var(--faint); }
.menu-item-disabled { color: var(--faint); cursor: default; }
.menu-item-disabled:hover { background: transparent; }
/* WP-27 §4.2: a re-run prompt inside a download menu on a saved-only output */
.menu-note {
  font: 400 10.5px var(--mono); color: var(--muted); line-height: 1.5;
  padding: 6px 12px; max-width: 220px; white-space: normal;
}
.menu-note .relink { color: var(--in); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }

/* ---------------------------------------------------------------- modals */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(4, 6, 10, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 30px;
}
.modal {
  background: var(--panel);
  border: 1px solid var(--border2);
  border-radius: 10px;
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  max-width: 100%;
  max-height: 100%;
}
.modal-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
}
.modal-title { font: 600 12.5px "Geist"; }
.shortcuts-modal { width: 380px; }
.shortcuts-body { padding: 14px 18px 18px; }
.shortcut-row { display: flex; align-items: center; gap: 7px; padding: 7px 0; }
.kbd {
  display: inline-block;
  padding: 3px 8px;
  background: var(--panel2);
  border: 1px solid var(--border2);
  border-radius: 6px;
  font: 500 11px "JetBrains Mono";
  color: var(--text);
}
.shortcut-desc { margin-left: 8px; font: 400 12px "Geist"; color: var(--dim); }

/* ================================================================== WP-21 */
/* Research-threads rail (spec §3): one scroll container, three sections
 * with dual-anchored sticky headers (Threads 0/76 · Schema 38/38 · Active
 * jobs 76/0 — three 39px headers overlapped 1px so borders coincide),
 * click-to-jump anchors, pen-pill new-thread action, jobs count badge.
 * Appended per §7A: existing rules above are untouched; everything here
 * reuses the token palette. */

.rail-body {
  flex: 1;
  min-height: 60px;
  overflow-y: auto;
  overflow-x: hidden;
  position: relative; /* anchors' offsetTop is measured against this */
  padding: 0 8px 8px;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.rail-body::-webkit-scrollbar { width: 0; height: 0; display: none; }
.rail-anchor { height: 0; }

.rail-sec-header {
  position: sticky;
  z-index: 6;
  height: 39px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 -8px; /* bleed to the rail edges past the container padding */
  padding: 0 14px;
  font: 600 12px "Geist";
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text);
  background: var(--panel2);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  user-select: none;
}
.rail-sec-header:hover { color: var(--text); background: var(--panel3); }
.rail-sec-label { flex: 1; }
/* offsets overlap by 1px per level so adjacent headers' borders coincide —
 * a single 1px line, no gap and no 2px double border when stacked. Four
 * headers now (threads / vo / schema / jobs) so offsets step 0/38/76/114. */
.rail-sec-threads { top: 0; bottom: 114px; }
.rail-sec-vo { top: 38px; bottom: 76px; }
.rail-sec-schema { top: 76px; bottom: 38px; }
.rail-sec-jobs { top: 114px; bottom: 0; }

/* Python & VO access — two static links under their sticky header. */
.vo-rail-list { padding: 6px 0 10px; }
.vo-rail-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 9px;
  margin-bottom: 1px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius);
  color: var(--dim);
  font: 500 12.5px "Geist";
  text-align: left;
  cursor: pointer;
}
.vo-rail-item:hover { background: var(--panel3); color: var(--text); }
.vo-rail-icon {
  flex: none;
  width: 20px;
  text-align: center;
  font-size: 12px;
  color: var(--accent);
}
.vo-rail-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.rail-pen-pill {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 24px;
  padding: 0 11px;
  border: none;
  border-radius: 20px;
  background: var(--accentSoft);
  color: var(--accent);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}
.rail-pen-pill:hover { background: var(--accent); color: #fff; }

.jobs-badge {
  font: 600 11px "JetBrains Mono";
  color: var(--accent);
  padding: 2px 9px;
  background: var(--accentSoft);
  border-radius: 20px;
}

.threads-list { padding: 6px 0 10px; }
.threads-empty { padding: 8px 9px 10px; font: 400 11px "Geist"; color: var(--faint); }
.thread-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 9px;
  margin-bottom: 1px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  cursor: pointer;
  text-align: left;
}
.thread-item:hover { background: var(--panel2); }
.thread-item-active { background: var(--accentSoft); border-color: var(--accent); }
.thread-dot { width: 5px; height: 5px; border-radius: 50%; flex: none; background: transparent; }
.thread-item-active .thread-dot { background: var(--accent); }
.thread-title {
  flex: 1;
  min-width: 0;
  font: 500 12px "Geist";
  color: var(--dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.thread-item:hover .thread-title,
.thread-item-active .thread-title { color: var(--text); }

/* WP-24 decision #17: the rail notebook context menu (rename/delete) — a
 * content-level ADDITION. The ⋯ affordance follows the rail's existing
 * hover-reveal idiom (see .schema-peek-pill): always in flow, opacity 0
 * until row hover / keyboard focus / open. */
.thread-item-wrap { position: relative; }
.thread-menu-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 18px;
  border-radius: 6px;
  color: var(--faint);
  flex: none;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  opacity: 0; /* revealed on row hover / keyboard focus */
  transition: opacity 0.12s ease;
}
.thread-item:hover .thread-menu-btn,
.thread-menu-btn:focus-visible,
.thread-menu-btn-open { opacity: 1; }
.thread-menu-btn:hover { background: var(--panel3); color: var(--text); }
.thread-menu { left: auto; right: 6px; top: 32px; bottom: auto; min-width: 150px; z-index: 40; }
@media (hover: none) {
  .thread-menu-btn { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .thread-menu-btn { transition: none; }
}

.schema-body { padding: 8px 0 10px; }
.jobs-body { padding: 6px 0 12px; }

.result-loading { padding: 14px 16px; font-size: 11px; color: var(--faint); }

/* card Download menu opens DOWNWARD so it cannot collide with the main
 * header when the card sits at the top (peek + notebook output heads) */
.result-head .menu { bottom: auto; top: 30px; }

/* ============================================================= table peek */
/* The schema browser's eye pill + the main-column table browser it opens
 * (js/peek.js): looks like a thread's result card, fills the viewport, no
 * composer. Appended per §7A; reuses the token palette and result chrome. */

.schema-peek-pill {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 18px;
  padding: 0 8px;
  border-radius: 20px;
  background: var(--accentSoft);
  color: var(--accent);
  cursor: pointer;
  flex: none;
  opacity: 0; /* revealed on row hover / keyboard focus */
  transition: opacity 0.12s ease;
}
.schema-table-btn:hover .schema-peek-pill,
.schema-peek-pill:focus-visible,
.schema-peek-pill-active {
  opacity: 1;
}
.schema-peek-pill:hover { background: var(--accent); color: #fff; }
.schema-peek-pill-active { background: var(--accent); color: #fff; }

.peek-view {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 14px 28px 20px;
}
.peek-card {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
/* the browser fills the column: no card-height cap on its table */
.peek-card .table-scroll { flex: 1; min-height: 0; max-height: none; }
.peek-card .result-foot { flex: none; }
.peek-card .result-loading { padding: 18px; }
.peek-dl-error {
  flex: none;
  padding: 6px 16px;
  font: 500 11px "Geist";
  color: var(--err);
  border-bottom: 1px solid var(--border);
}

/* ===== WP-23 server status ===== */
/* One appended block; every new selector is .status-prefixed and every value
   binds to an existing token, so light + dark both theme automatically (§7.8).
   The pane reuses .chip/.chip-*, .spinner, .jobs-badge, .table-scroll,
   .result-table, .td-dim/.td-faint, .history-dot* from the rules above. */

@keyframes status-pulse-kf {
  0% { box-shadow: 0 0 0 0 currentColor; opacity: 1; }
  70% { box-shadow: 0 0 0 7px transparent; opacity: 0.9; }
  100% { box-shadow: 0 0 0 0 transparent; opacity: 1; }
}

/* --- Python & VO access panes (js/vo-access.js) --- */
.vo-view { padding: 22px 26px 40px; overflow: auto; }
.vo-card {
  max-width: 720px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 13px;
  padding: 22px 24px 26px;
}
.vo-intro { font-size: 13px; line-height: 1.6; color: var(--dim); margin: 0 0 16px; }
.vo-warn {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 11px 13px;
  margin-bottom: 16px;
  background: var(--errSoft);
  border: 1px solid var(--err);
  border-radius: 9px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text);
}
.vo-warn-icon { flex: none; font-size: 14px; line-height: 1.4; }
.vo-toolbar { display: flex; align-items: center; gap: 14px; margin-bottom: 12px; }
.vo-hint { font-size: 12px; color: var(--faint); }
.vo-code {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: 14px 16px;
  font-size: 12px;
  line-height: 1.55;
  color: var(--text);
  overflow-x: auto;
  white-space: pre;
  margin: 0;
}
.vo-notes { margin-top: 18px; font-size: 12px; color: var(--dim); }
.vo-notes-title {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--faint);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.vo-notes ul { margin: 6px 0 0; padding-left: 18px; line-height: 1.6; }
.vo-steps {
  margin: 4px 0 0;
  padding-left: 22px;
  font-size: 13px;
  line-height: 1.7;
  color: var(--dim);
}
.vo-steps li { margin-bottom: 12px; }
.vo-steps strong { color: var(--text); font-weight: 600; }
.vo-inline {
  padding: 1px 6px;
  background: var(--panel2);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12px;
  color: var(--text);
}
.vo-cred-grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 6px 16px;
  align-items: baseline;
  margin: 8px 0 2px;
  padding: 10px 13px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 9px;
}
.vo-cred-key {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.vo-cred-val-row { display: flex; align-items: center; gap: 10px; min-width: 0; }
.vo-cred-val { font-size: 12.5px; color: var(--text); overflow-wrap: anywhere; flex: 1; min-width: 0; }
.vo-cred-copy { flex: none; padding: 3px 12px; font-size: 11px; }
.vo-cred-copy:disabled { opacity: 0.5; cursor: default; }
.vo-code-wrap { position: relative; margin-top: 8px; }
.vo-copy-btn { position: absolute; top: 8px; right: 8px; z-index: 1; }

.status-view { padding: 22px 26px 40px; overflow: auto; }
.status-wrap { max-width: 1200px; margin: 0 auto; display: flex; flex-direction: column; gap: 22px; }

/* --- vitals ribbon (the signature, §7.2) --- */
.status-ribbon {
  display: flex;
  align-items: stretch;
  gap: 22px;
  flex-wrap: wrap;
  padding: 16px 20px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-left: 3px solid var(--dim);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.status-ribbon--ok { background: var(--okSoft); border-color: var(--ok); border-left-color: var(--ok); }
.status-ribbon--warn { background: var(--warnSoft); border-color: var(--warn); border-left-color: var(--warn); }
.status-ribbon--err { background: var(--errSoft); border-color: var(--err); border-left-color: var(--err); }
.status-verdict { display: flex; align-items: center; gap: 13px; min-width: 230px; }
.status-pulse {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
  background: currentColor;
  animation: status-pulse-kf 2s ease-in-out infinite;
}
.status-pulse-sm { width: 7px; height: 7px; }
.status-pulse--ok { color: var(--ok); }
.status-pulse--warn { color: var(--warn); }
.status-pulse--err { color: var(--err); }
.status-pulse--accent { color: var(--accent); }
.status-verdict-word { font: 700 22px "Geist"; letter-spacing: 0.04em; text-transform: uppercase; line-height: 1.1; }
.status-verdict--ok { color: var(--ok); }
.status-verdict--warn { color: var(--warn); }
.status-verdict--err { color: var(--err); }
.status-verdict-reasons { margin-top: 3px; font: 500 11px "JetBrains Mono"; color: var(--dim); }
.status-vitals { display: flex; align-items: center; flex-wrap: wrap; flex: 1; }
.status-vital { display: flex; flex-direction: column; gap: 4px; padding: 0 20px; border-left: 1px solid var(--border2); }
.status-vital:first-child { border-left: none; padding-left: 0; }
.status-vital-label { font: 600 9.5px "Geist"; text-transform: uppercase; letter-spacing: 0.07em; color: var(--dim); }
.status-vital-val { font: 500 16px "JetBrains Mono"; color: var(--text); display: flex; align-items: center; gap: 8px; }
.status-updated {
  display: flex;
  align-items: center;
  gap: 7px;
  align-self: flex-start;
  font: 400 10.5px "JetBrains Mono";
  color: var(--faint);
  white-space: nowrap;
}

/* --- groups + tiles (§7.3) --- */
.status-group { display: flex; flex-direction: column; gap: 11px; }
.status-group-head { margin: 0; font: 600 11px "Geist"; text-transform: uppercase; letter-spacing: 0.07em; color: var(--faint); }
.status-group-note { color: var(--faint); font-weight: 400; text-transform: none; letter-spacing: 0; }
.status-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
.status-tile { display: flex; flex-direction: column; gap: 9px; padding: 14px 15px; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); }
.status-tile-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.status-tile-label { display: flex; align-items: center; gap: 7px; font: 600 10px "Geist"; text-transform: uppercase; letter-spacing: 0.06em; color: var(--dim); }
.status-tile-unit { font: 400 10px "JetBrains Mono"; color: var(--faint); }
.status-tile-val { font: 500 26px "JetBrains Mono"; color: var(--text); line-height: 1; letter-spacing: -0.01em; }
.status-tile-val--md { font-size: 20px; }
.status-tile-val--sm { font-size: 18px; }
.status-tile-frac { color: var(--faint); font-size: 18px; }
.status-tile-sub { font: 400 10.5px "JetBrains Mono"; color: var(--faint); }
.status-tile-sub--warn { color: var(--warn); }
.status-tile-sub--err { color: var(--err); }
.status-chips { display: flex; gap: 7px; flex-wrap: wrap; padding: 3px 0; }
.status-dot { width: 6px; height: 6px; border-radius: 50%; flex: none; background: var(--ok); }
.status-dot--warn { background: var(--warn); }
.status-dot--err { background: var(--err); }

/* --- sparkline (§7.4) --- */
.status-spark { color: var(--accent); height: 30px; }
.status-spark--warn { color: var(--warn); }
.status-spark--err { color: var(--err); }
.status-spark svg { display: block; width: 100%; height: 30px; }
.status-spark-empty { height: 30px; display: flex; align-items: center; color: var(--faint); font: 400 11px "JetBrains Mono"; }

/* --- meter (§7.5) --- */
.status-meter { height: 8px; border-radius: 5px; background: var(--panel2); overflow: hidden; }
.status-meter-fill { height: 100%; border-radius: 5px; background: var(--accent); }
.status-meter-fill--warn { background: var(--warn); }
.status-meter-fill--err { background: var(--err); }
.status-meter-mini { width: 52px; height: 6px; border-radius: 4px; background: var(--panel2); overflow: hidden; display: inline-block; vertical-align: middle; }
.status-meter-mini > i { display: block; height: 100%; background: var(--accent); border-radius: 4px; }

/* --- activity (§7.7); reuses .result-table / .table-scroll / .chip chrome --- */
.status-activity { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr); gap: 14px; }
.status-card { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; display: flex; flex-direction: column; min-width: 0; }
.status-card-head { display: flex; align-items: center; gap: 11px; padding: 11px 15px; border-bottom: 1px solid var(--border); }
.status-card-title { font: 600 12px "Geist"; color: var(--text); }
.status-empty { padding: 14px 15px; font: 400 11px "Geist"; color: var(--faint); }
/* status tables are read-only (no sort): mono header text, no pointer. */
.status-table th { cursor: default; font: 600 10.5px "JetBrains Mono"; color: var(--text); }
.status-table th.status-l, .status-table td.status-l { text-align: left; }
/* recent-activity kind chip: category, not health — blue sync / purple async. */
.status-kind-sync { background: var(--accentSoft); color: var(--accent); }
.status-kind-async { background: var(--fnSoft); color: var(--fn); }
.status-ellip { max-width: 220px; overflow: hidden; text-overflow: ellipsis; }
.status-adql { max-width: 1px; width: 100%; }

/* --- info tooltips: a quiet ⓘ beside each metric, hover + keyboard focus --- */
.status-info { position: relative; display: inline-flex; align-items: center; margin-left: 5px; vertical-align: middle; cursor: help; }
.status-info-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 13px; height: 13px; border-radius: 50%;
  border: 1px solid var(--border2); color: var(--faint);
  font: italic 400 9px "Geist"; line-height: 1; text-transform: none; letter-spacing: 0;
  transition: color 0.12s ease, border-color 0.12s ease;
}
.status-info:hover .status-info-mark,
.status-info:focus-visible .status-info-mark { color: var(--accent); border-color: var(--accent); }
.status-tip {
  position: absolute; top: calc(100% + 8px); left: 0; z-index: 60;
  width: max-content; max-width: 240px; padding: 9px 11px;
  background: var(--panel3); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  font: 400 12px/1.5 "Geist"; color: var(--dim);
  text-transform: none; letter-spacing: 0; white-space: normal; text-align: left;
  opacity: 0; visibility: hidden; transform: translateY(-3px);
  transition: opacity 0.12s ease, transform 0.12s ease, visibility 0.12s;
  pointer-events: none;
}
.status-info:hover .status-tip,
.status-info:focus .status-tip,
.status-info:focus-within .status-tip { opacity: 1; visibility: visible; transform: translateY(0); }

/* --- auto-refresh cadence control, in the liveness cluster --- */
.status-refresh { display: inline-flex; align-items: center; gap: 5px; margin-left: 6px; }
.status-refresh-label { color: var(--faint); }
.status-refresh-select {
  font: 400 10.5px "JetBrains Mono"; color: var(--dim);
  background: var(--panel2); border: 1px solid var(--border); border-radius: 6px;
  padding: 1px 5px; cursor: pointer;
}
.status-refresh-select:hover { color: var(--text); border-color: var(--dim); }
.status-refresh-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* --- sonification control (WP-23s), beside the refresh selector --- */
.status-sound { display: inline-flex; align-items: center; gap: 6px; margin-left: 8px; }
.status-sound-btn {
  font: 400 10.5px "JetBrains Mono"; color: var(--faint);
  background: var(--panel2); border: 1px solid var(--border); border-radius: 6px;
  padding: 1px 7px; cursor: pointer;
}
.status-sound-btn:hover { color: var(--text); border-color: var(--dim); }
.status-sound-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.status-sound-btn--on { color: var(--accent); border-color: var(--accent); background: var(--accentSoft); }
.status-sound-vol { width: 66px; accent-color: var(--accent); cursor: pointer; }
.status-sound-vol:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .status-pulse { animation: none; }
  .status-tip, .status-info-mark { transition: none; }
}
@media (max-width: 820px) {
  .status-activity { grid-template-columns: 1fr; }
  .status-verdict { min-width: 100%; }
}

/* ================================================================== WP-25 */
/* The Jupyter-clean notebook surface (docs/webui/WP-25-notebook-restyle.md,
 * canonical mock docs/webui/design-mock/notebook-restyle.html): a two-column
 * prompt-gutter + body grid per cell, no cards / no borders, at-rest prompts +
 * tags, a single left edge bar for the selected / edit mode, dataframe output,
 * and a hairline between-cell insert. Class names mirror the mock; values bind
 * to the WP-25 console tokens so both themes track. The ADQL highlighter hues
 * (.tok-*) carry over unchanged; a {{ }} reference is a quiet inline token
 * (teal + dotted underline, no pill). The toolbar is stage C; the WP-24 rail is
 * retained as-is (owner reversed the drawers plan) — the header helpers below
 * are content-level carryovers, not restyled here.
 *
 * Fonts: every rule in this block uses var(--sans)/var(--mono) (decision #8),
 * overriding the global .mono utility for the notebook surface only. */

/* the notebook column — the mock's .doc-nb. WP-26 fix #4: no horizontal cap so
 * the notebook fills the window; the 20px side padding leaves the ~20px margin. */
.notebook-slot { max-width: none; margin: 0 auto; padding: 10px 20px 12px; }

/* --- header additions (§5.5, content-level only) --- */
.title-pencil {
  background: none;
  border: none;
  color: var(--faint);
  font-size: 12px;
  cursor: pointer;
  padding: 2px 4px;
  flex: none;
}
.title-pencil:hover { color: var(--accent); }
.title-input {
  width: 280px;
  padding: 5px 9px;
  background: var(--panel2);
  border: 1px solid var(--accent);
  border-radius: 8px;
  color: var(--text);
  font: 600 12.5px "Geist";
  outline: none;
}
.hdr-run-all { padding: 6px 12px; font: 600 11.5px "Geist"; border-radius: 8px; }

/* rail item cell count (§5.5: item = name + cell count) */
.thread-cells { font: 400 9.5px "JetBrains Mono"; color: var(--faint); flex: none; }

.empty-cta { display: flex; justify-content: center; }
#empty-nonotebooks, #empty-cells { display: flex; flex-direction: column; align-items: center; }

/* --- the cell: a 64 px prompt gutter + body grid (WP-25 §4.1) --- */
.cell {
  position: relative;
  display: grid;
  grid-template-columns: 64px 1fr;
  /* 8px left padding gives the In/Out prompt room from the mode edge bar; kept
     on the base cell (not .sel-cmd) so selecting/deselecting doesn't shift the
     content — the 3px border is always reserved, just transparent when idle. */
  padding: 5px 0 5px 8px;
  border-left: 3px solid transparent; /* the mode edge bar (§4.3) */
}
.cell.sel-cmd { border-left-color: var(--cmd); }  /* command-mode selection */
.cell.sel-edit { border-left-color: var(--edit); } /* editor focused */
.cell:hover { background: color-mix(in srgb, var(--muted) 5%, transparent); }
/* WP-30: a faint whole-cell tint on pending cells (kernel accent) — the
 * executing cell slightly stronger, a queued cell fainter. Static (no motion). */
.cell.running { background: color-mix(in srgb, var(--kernel) 7%, transparent); }
.cell.queued { background: color-mix(in srgb, var(--kernel) 4%, transparent); }
.cell.dragging { opacity: 0.45; }
.cell.drop-above { box-shadow: 0 -9px 0 -7px var(--in); }
.cell.drop-below { box-shadow: 0 9px 0 -7px var(--in); }

/* prompt gutter — In[n]:/Out[n]:, the In prompt is the drag-reorder handle */
.prompt {
  padding: 9px 10px 0 0;
  text-align: right;
  font: 400 11px/1.55 var(--mono);
  color: var(--in);
  white-space: nowrap;
  user-select: none;
}
/* WP-26 fix #1: the Out prompt also carries the .out class (used by the output
 * container), whose later `.out { padding: 6px 0 4px }` clobbers .prompt's
 * padding-right — pulling the Out[n]: colon 10px right of In[n]:. Restore the
 * gutter's right padding here (higher specificity) so both colons right-align. */
.prompt.out { color: var(--out); padding-right: 10px; }
.prompt.star { color: var(--kernel); }
/* WP-30: a QUEUED cell's In[*]/Out[*] is dimmed vs the solid executing star,
 * so a ⇧⏎ burst shows which cell runs now (solid) vs waits (hollow). */
.prompt.star.star-queued { opacity: 0.45; }
.cell:not(.md-cell) .prompt:not(.out) { cursor: grab; }
.cell:not(.md-cell) .prompt:not(.out):active { cursor: grabbing; }

.body { min-width: 0; position: relative; }

/* at-rest cell tag + hover-revealed tools, top-right of the body (§4.1) */
.btop {
  position: absolute;
  top: 5px;
  right: 6px;
  display: flex;
  align-items: center;
  gap: 5px;
  z-index: 3;
}
.tag {
  font: 500 10.5px var(--mono);
  color: var(--muted);
  background: var(--line2);
  padding: 1px 7px;
  border-radius: 9px;
  opacity: 0.85;
  cursor: text;
  white-space: nowrap;
  border: 1px solid transparent;
}
.tag:hover { border-color: var(--line); color: var(--text); }
.md-cell .tag { opacity: 0; transition: opacity 0.12s ease; }
.md-cell:hover .tag { opacity: 0.85; }
.tag-input {
  width: 13ch;
  font: 500 10.5px var(--mono);
  color: var(--text);
  background: var(--app);
  border: 1px solid var(--in);
  border-radius: 9px;
  padding: 1px 7px;
  outline: none;
}
.tag-invalid { border-color: var(--err); color: var(--err); }
.ctools { display: flex; align-items: center; gap: 3px; opacity: 0; transition: opacity 0.12s ease; }
.cell:hover .ctools, .cell.sel-cmd .ctools, .cell.sel-edit .ctools { opacity: 1; }
@media (hover: none) { .ctools { opacity: 1; } }
.ctool {
  border: none;
  background: none;
  color: var(--muted);
  font: 500 10.5px var(--sans);
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 5px;
  white-space: nowrap;
}
.ctool:hover { background: var(--line2); color: var(--text); }
.iconbtn {
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  color: var(--faint);
  border-radius: 5px;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
}
.iconbtn:hover { background: var(--line2); color: var(--text); }

/* --- the input: the only framed element (§4.1). The in-flow highlight <pre>
 * sits under a transparent-text textarea; the two layers MUST share the exact
 * metrics or the caret drifts, so the {{ }} token stays metric-neutral. --- */
.input {
  background: var(--code);
  border: 1px solid var(--codeline);
  border-radius: 5px;
  padding: 9px 12px;
  overflow-x: auto;
}
.cell.sel-edit .input {
  border-color: color-mix(in srgb, var(--edit) 55%, var(--codeline));
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--edit) 14%, transparent);
}
.cell-editor-wrap { position: relative; }
.cell-hl {
  display: block;
  margin: 0;
  padding: 0;
  min-height: 1.55em;
  font: 400 12.5px/1.55 var(--mono);
  white-space: pre-wrap;
  word-break: break-word;
  tab-size: 2;
  color: var(--text);
  pointer-events: none;
}
.cell-hl-md { color: var(--muted); }
.cell-editor {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  font: 400 12.5px/1.55 var(--mono);
  white-space: pre-wrap;
  word-break: break-word;
  tab-size: 2;
  border: none;
  outline: none;
  resize: none;
  overflow: hidden;
  background: transparent;
  color: transparent;
  caret-color: var(--text);
}
.tok-kw { color: var(--kw); }
.tok-fn { color: var(--fn); }
.tok-str { color: var(--str); }
.tok-num { color: var(--num); }
.tok-punc { color: var(--punc); }
/* a {{ }} cross-cell reference — quiet inline token, metric-neutral (§4.1) */
.tmpl { color: var(--tmpl); border-bottom: 1px dotted color-mix(in srgb, var(--tmpl) 60%, transparent); }
.tmpl-err { color: var(--err); border-bottom: 1px dotted color-mix(in srgb, var(--err) 65%, transparent); }

/* --- markdown at rest (§4.1 / decision #8): rendered content in the body
 * column, empty prompt gutter, system fonts. Markup comes ONLY from
 * js/markdown.js (raw HTML disabled); .md-src is the plain-text load flash. --- */
.md-rendered { padding: 8px 6px 10px 2px; cursor: text; font: 400 13px/1.6 var(--sans); color: var(--text); }
.md-empty { color: var(--muted); font-style: italic; }
.md-src { margin: 0; font: 400 13px/1.6 var(--mono); white-space: pre-wrap; word-break: break-word; color: var(--text); }
.md-rendered h1,
.md-rendered h2,
.md-rendered h3,
.md-rendered h4,
.md-rendered h5,
.md-rendered h6 { margin: 0 0 6px; font-family: var(--sans); font-weight: 600; letter-spacing: -0.01em; line-height: 1.3; }
.md-rendered h1 { font-size: 20px; }
.md-rendered h2 { font-size: 17px; }
.md-rendered h3 { font-size: 15.5px; }
.md-rendered h4,
.md-rendered h5,
.md-rendered h6 { font-size: 13.5px; }
.md-rendered * + h1,
.md-rendered * + h2,
.md-rendered * + h3,
.md-rendered * + h4 { margin-top: 12px; }
.md-rendered p { margin: 0 0 8px; color: var(--text); }
.md-rendered .sub, .md-rendered em { color: var(--muted); }
.md-rendered strong { color: var(--text); }
.md-rendered ul,
.md-rendered ol { margin: 0 0 8px; padding-left: 22px; color: var(--text); }
.md-rendered li { margin: 2px 0; }
.md-rendered code {
  font: 400 11.5px var(--mono);
  background: var(--code);
  border: 1px solid var(--codeline);
  border-radius: 4px;
  padding: 1px 5px;
  color: var(--tmpl);
}
.md-rendered pre {
  margin: 0 0 8px;
  padding: 10px 12px;
  background: var(--code);
  border: 1px solid var(--codeline);
  border-radius: 6px;
  overflow-x: auto;
}
.md-rendered pre code { border: none; background: none; padding: 0; color: var(--text); font: 400 11.5px/1.6 var(--mono); }
.md-rendered blockquote { margin: 0 0 8px; padding: 2px 0 2px 12px; border-left: 3px solid var(--line); color: var(--muted); }
.md-rendered a { color: var(--in); text-decoration: underline; text-underline-offset: 2px; }
.md-rendered hr { border: none; border-top: 1px solid var(--line); margin: 10px 0; }
.md-rendered table { border-collapse: collapse; margin: 0 0 8px; display: block; overflow-x: auto; }
.md-rendered th,
.md-rendered td { border: 1px solid var(--line); padding: 4px 10px; font-size: 12px; text-align: left; }
.md-rendered th { background: var(--code); font-weight: 600; }
.md-rendered > :last-child { margin-bottom: 0; }

/* --- output area (§4.2): no head bar, no chip, no card --- */
.out { position: relative; padding: 6px 0 4px; }
.out-meta { font: 400 10.5px var(--mono); color: var(--muted); padding: 2px 2px 6px; overflow-wrap: anywhere; }
.out-meta:empty { display: none; }

/* hover-revealed output tools (the ↓ download menu behind a single icon) */
.otools { position: absolute; top: 2px; right: 2px; z-index: 3; opacity: 0; transition: opacity 0.12s ease; }
.cell:hover .otools { opacity: 1; }
@media (hover: none) { .otools { opacity: 1; } }
.out .pill-btn {
  padding: 3px 7px;
  background: none;
  border: none;
  border-radius: 5px;
  color: var(--faint);
  font: 400 13px var(--mono);
  line-height: 1;
}
.out .pill-btn:hover { background: var(--line2); color: var(--text); }
.dl-menu { bottom: auto; top: 28px; right: 0; }

/* one quiet mono line for stale / clip / running notices — no ribbon block */
.note { display: flex; align-items: center; gap: 7px; font: 400 11px var(--mono); padding: 3px 2px; }
.note.stale, .note.clip { color: var(--stale); }
.note .relink { color: inherit; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.run-note { color: var(--muted); }
.cancel {
  margin-left: 2px;
  border: none;
  background: none;
  color: var(--muted);
  font-size: 10px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 5px;
  border-radius: 5px;
}
.cancel:hover { background: var(--line2); color: var(--err); }
.cancel:disabled { opacity: 0.5; cursor: default; }
.runbar {
  height: 3px;
  border-radius: 2px;
  margin: 5px 2px 3px;
  max-width: 220px;
  background: linear-gradient(90deg, var(--kernel), color-mix(in srgb, var(--kernel) 25%, transparent));
  background-size: 200% 100%;
  animation: nb-runbar 1.1s linear infinite;
}
@keyframes nb-runbar { to { background-position: 200% 0; } }

/* Jupyter-traceback error (§4.3): --err monospace on a faint red wash */
.err-out { background: color-mix(in srgb, var(--err) 9%, transparent); border-radius: 5px; padding: 8px 11px; margin: 2px 0 4px; }
.err-msg { font: 400 11.5px/1.5 var(--mono); color: var(--err); white-space: pre-wrap; overflow-wrap: anywhere; }

/* --- the table: Jupyter-dataframe styling (§4.2). The shared ResultTable
 * component keeps its .result-table markup; these notebook-scoped rules give
 * it the dataframe look (peek/admin/status keep the card look). --- */
.out .table-scroll { overflow: auto; max-height: min(360px, 46vh); margin-top: 2px; }
.out .result-table { border-collapse: collapse; font: 400 11.5px var(--mono); font-variant-numeric: tabular-nums; width: max-content; min-width: min(100%, 540px); }
.out .result-table thead tr { position: sticky; top: 0; z-index: 1; }
.out .result-table th {
  background: var(--app);
  border-bottom: 1.5px solid var(--muted);
  padding: 5px 14px 5px 0;
  text-align: right;
  white-space: nowrap;
  cursor: pointer;
}
.out .result-table th:first-child, .out .result-table td:first-child { text-align: left; padding-left: 2px; }
.out .th-name { font: 600 11px var(--mono); color: var(--text); }
.out .th-unit { font: 400 9px var(--mono); color: var(--faint); height: 11px; }
.out .result-table th:hover .th-name { color: var(--in); }
.out .result-table td { padding: 3px 14px 3px 0; text-align: right; white-space: nowrap; border-bottom: 1px solid var(--line2); color: var(--text); }
.out .result-table tbody tr:hover { background: color-mix(in srgb, var(--in) 7%, transparent); }
.out .td-null { color: var(--faint); font-style: italic; }

/* pagination — quiet text buttons under the table */
.out .result-foot { display: flex; align-items: center; gap: 10px; padding: 6px 2px 2px; font: 400 10.5px var(--mono); color: var(--muted); }
.out .page-label { color: var(--muted); }
.out .page-btn { border: none; background: none; color: var(--in); font: 400 10.5px var(--mono); cursor: pointer; padding: 2px 6px; border-radius: 4px; }
.out .page-btn:not(:disabled):hover { background: var(--line2); }
.out .page-btn:disabled { color: var(--faint); opacity: 0.6; cursor: default; }
.out .result-loading { padding: 8px 2px; font: 400 11px var(--mono); color: var(--muted); }
/* WP-27 §4.2: savedOnly — the header column is not sortable, and the inline
 * re-run prompt shown when paging/sort is attempted on the page-1 snapshot */
.out .result-table th.th-nosort { cursor: default; }
.out .result-table th.th-nosort:hover .th-name { color: var(--text); }
.note.saved-note { color: var(--muted); }

/* --- between-cell insert (§4.5): a hairline reveal with a circled + --- */
.ins { position: relative; height: 12px; display: flex; align-items: center; justify-content: center; }
.ins-end { height: 22px; }
.ins::before {
  content: "";
  position: absolute;
  left: 64px;
  right: 8px;
  height: 1px;
  background: var(--in);
  opacity: 0;
  transition: opacity 0.12s ease;
}
.ins:hover::before { opacity: 0.35; }
.ins-drop::before { opacity: 0.7; height: 2px; }
.ins-anchor { position: relative; z-index: 40; }
.ins-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--app);
  color: var(--in);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s ease;
}
.ins:hover .ins-btn, .ins-drop .ins-btn { opacity: 1; }
.ins-btn:hover { background: var(--line2); }
.ins-menu { left: 50%; right: auto; transform: translateX(-50%); top: 26px; bottom: auto; min-width: 210px; z-index: 40; }

/* the ⋮ menu opens downward from the cell's top-right tools */
.cell-menu { bottom: auto; top: 26px; right: 0; min-width: 190px; z-index: 40; }
.menu-ic { color: var(--in); display: inline-block; width: 16px; text-align: center; }
.menu-item:disabled { color: var(--faint); cursor: default; }
.menu-item:disabled:hover { background: transparent; }
.menu-item-danger { color: var(--err); }
.menu-item-danger:hover { background: color-mix(in srgb, var(--err) 12%, transparent); }

/* footer keyboard strip — one quiet line (§4.4) */
.foot { max-width: none; margin: 14px auto 0; padding: 8px 20px 4px; font: 400 11.5px var(--mono); color: var(--muted); display: flex; flex-wrap: wrap; gap: 6px 18px; }
.foot b { color: var(--text); font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  .runbar { animation: none; }
  .ctools, .otools, .tag, .ins-btn, .ins::before { transition: none; }
}

/* ================================================================== WP-26 */
/* The Plot cell (docs/webui/WP-26-plot-cell.md §4; canonical mock
 * docs/webui/design-mock/plot-cell.html). Rendered in the shipped WP-25
 * console tokens; the accent is the mppdb blue --accent. The whole cell is an
 * imperative controller (js/plot-cell.js) inside the stable .pcell mount. */
.pcell {
  /* soft/line accent washes the mock uses — derived so both themes track --accent */
  --accent-soft: color-mix(in srgb, var(--accent) 12%, transparent);
  --accent-line: color-mix(in srgb, var(--accent) 42%, transparent);
  border: 1px solid var(--codeline);
  border-radius: 8px;
  background: var(--app);
  overflow: visible;
}
.plot-cell-row .body { min-width: 0; }
.pcell-loading { padding: 14px 16px; font: 400 12px var(--mono); color: var(--muted); }
/* the ⋮ tools sit above the pcell like other cells; no cell tag row */
.plot-cell-row .btop { min-height: 0; }

.pchead {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 12px; border-bottom: 1px solid var(--line2); cursor: pointer;
}
.pchead .phdrctrls { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; }
.pchead .hsrc { flex: 0 1 200px; }
.pchead .grow { flex: 1; }
.caret { color: var(--accent); font-size: 11px; width: 11px; display: inline-block; flex: none; }
.picon { color: var(--accent); display: inline-flex; align-items: center; flex: none; }
.picon svg { width: 14px; height: 14px; }
.psummary {
  font: 400 12px var(--mono); color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 560px;
}
.pcedit { font-size: 11px; color: var(--accent); }
.pctag {
  font: 500 11px var(--mono); color: var(--muted);
  background: var(--line2); border-radius: 9px; padding: 1px 8px;
}

.pcgrid { display: grid; grid-template-columns: minmax(0, 1fr) 396px; }
.pcbody { overflow: hidden; }
@media (prefers-reduced-motion: no-preference) {
  .pcbody { transition: height 0.24s ease, opacity 0.2s ease; }
}
.pctrl { padding: 14px 16px; border-right: 1px solid var(--line2); }
.pprev {
  padding: 14px 16px; background: var(--app);
  display: flex; flex-direction: column; min-width: 0;
}

.seg {
  display: inline-flex; background: var(--code); border: 1px solid var(--codeline);
  border-radius: 9px; padding: 3px; gap: 2px;
}
.segb {
  display: inline-flex; align-items: center; gap: 6px; border: none; background: none;
  cursor: pointer; border-radius: 7px; padding: 6px 11px;
  font: 600 12.5px var(--sans); color: var(--muted);
}
.segb svg { width: 15px; height: 15px; }
.segb.on { background: var(--app); color: var(--accent); box-shadow: 0 1px 2px rgba(20, 20, 40, 0.12); }
.segb:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.sel-wrap { flex: 1; min-width: 0; position: relative; }
.pcell select.msel {
  width: 100%; appearance: none; border: 1px solid var(--codeline); border-radius: 8px;
  padding: 7px 30px 7px 12px; font: 400 12.5px var(--mono); color: var(--text);
  background: var(--app); cursor: pointer;
}
.pcell select.msel:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.pcell .caretdn {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  color: var(--faint); pointer-events: none; font-size: 10px;
}

.pcell .subhd {
  font: 600 10px var(--sans); letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--muted); margin: 2px 0 7px;
}
.pprev-head { display: flex; align-items: center; gap: 9px; }
.flavrow { display: flex; gap: 8px; margin-bottom: 14px; }
.flav {
  flex: 1; cursor: pointer; border-radius: 8px; padding: 8px 10px;
  font: 500 12px var(--sans); border: 1px solid var(--codeline);
  background: var(--app); color: var(--muted);
}
.flav.on { border-color: var(--accent-line); background: var(--accent-soft); color: var(--accent); }
.flav.flav-disabled, .flav:disabled { opacity: 0.5; cursor: not-allowed; }
.flav:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.pcell .frow { display: flex; align-items: center; gap: 10px; margin-bottom: 9px; position: relative; }
.pcell .flabel {
  width: 74px; font: 500 12.5px var(--sans); color: var(--text);
  flex: none; display: flex; align-items: center; gap: 5px;
}
.pcell .flabel .opt { font-size: 9.5px; color: var(--faint); font-weight: 400; }
.fbox { flex: 1; min-width: 60px; position: relative; }
.finput {
  display: flex; align-items: center; border: 1px solid var(--codeline);
  border-radius: 8px; background: var(--app); padding-right: 8px;
}
.finput:focus-within { border-color: var(--accent-line); box-shadow: 0 0 0 2px var(--accent-soft); }
.finput input {
  flex: 1; min-width: 0; border: none; background: transparent; padding: 7px 11px;
  font: 400 12.5px var(--mono); color: var(--text);
}
.finput input:focus { outline: none; }
.finput .dd { color: var(--faint); cursor: pointer; font-size: 10px; }

.plot-menu {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; background: var(--app);
  border: 1px solid var(--codeline); border-radius: 8px; box-shadow: var(--shadow);
  z-index: 40; padding: 4px; max-height: 210px; overflow: auto;
}
.plot-menu .mitem {
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 10px; border-radius: 6px; cursor: pointer;
  font: 400 12.5px var(--mono); color: var(--text);
}
.plot-menu .mitem:hover, .plot-menu .mitem.hi { background: var(--accent-soft); }
.plot-menu .mitem .b { font-size: 10px; color: var(--faint); }
.plot-menu .mempty { padding: 8px 10px; font-size: 12px; color: var(--faint); }

.limbox { position: relative; flex: none; width: 80px; }
.limbox .finput input { padding: 7px 8px; font-size: 12px; }
.pcell .labinput {
  flex: 1; min-width: 0; border: 1px solid var(--codeline); border-radius: 8px;
  background: var(--app); padding: 7px 11px; font: 400 12.5px var(--sans); color: var(--text);
}
.pcell .labinput.labinput-inline { flex: none; max-width: 130px; }
.pcell .labinput:focus { outline: none; border-color: var(--accent-line); box-shadow: 0 0 0 2px var(--accent-soft); }

.errchips { display: flex; gap: 8px; margin: 4px 0 4px 84px; }
.echip {
  cursor: pointer; border-radius: 7px; padding: 5px 11px; font: 500 11.5px var(--mono);
  border: 1px solid var(--codeline); background: var(--app); color: var(--muted);
}
.echip.on { border-color: var(--accent-line); background: var(--accent-soft); color: var(--accent); }

.hpx { margin-top: 4px; padding-top: 12px; border-top: 1px dashed var(--line2); }
.hpxrow { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.hpx input[type="range"] { flex: 1; accent-color: var(--accent); }
.hpxval { font: 400 12.5px var(--mono); color: var(--accent); width: 40px; text-align: right; }

.prevcanvaswrap {
  border: 1px solid var(--codeline); border-radius: 8px; background: var(--app);
  padding: 8px; display: flex; align-items: center; justify-content: center; min-height: 150px;
}
.prevcanvaswrap canvas { display: block; max-width: 100%; }
.prevbadge {
  display: inline-flex; align-items: center; gap: 6px; font: 500 10.5px var(--mono);
  color: var(--accent); background: var(--accent-soft); border: 1px solid var(--accent-line);
  border-radius: 6px; padding: 2px 7px; text-transform: none; letter-spacing: 0;
}
.prevnote { font: 400 11px/1.55 var(--mono); color: var(--muted); margin-top: 8px; white-space: pre-wrap; }
.plot-source-err { color: var(--stale); }

.pcfoot {
  display: flex; align-items: center; gap: 12px; padding: 9px 14px;
  border-top: 1px solid var(--line2); background: var(--app);
}
.pcfoot .grow { flex: 1; }
.pcfoot-hint { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.pcell .kbd {
  font: 400 10.5px var(--mono); background: var(--app); border: 1px solid var(--codeline);
  border-radius: 5px; padding: 2px 6px;
}
.runbtn {
  display: inline-flex; align-items: center; gap: 7px; background: var(--accent); color: #fff;
  border: none; border-radius: 8px; padding: 8px 16px; font: 600 12.5px var(--sans); cursor: pointer;
}
.runbtn:disabled { opacity: 0.55; cursor: not-allowed; }
.runbtn:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
.runbtn svg { width: 11px; height: 11px; }

@media (max-width: 720px) {
  .pcgrid { grid-template-columns: 1fr; }
  .pctrl { border-right: none; border-bottom: 1px solid var(--line2); }
}

/* --- Plot cell Out[n]: the committed server render (WP-26 §5, the mock's
 * output block). The meta line states the all-data server render; the PNG sits
 * in a framed box with expand (⤢) + download (⬇) tools and a "rendering
 * server-side…" overlay while the async render job runs. */
/* WP-26 fix #3: match the table output's meta baseline so the plot meta's first
 * line lines up with the Out[n]: prompt (padding-top 6px like .out, meta pad-top
 * 2px like .out-meta, and flex-start so the meta isn't centred within the taller
 * tools row). */
.plot-out { padding-top: 6px; }
.plot-out .outhead { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 8px; }
.plot-out .out-meta { padding: 2px 2px; flex: 0 1 auto; }
.plot-out .outhead .grow { flex: 1; }
.plot-out .outtools {
  display: flex; gap: 12px; align-items: center; color: var(--faint); font-size: 14px;
  opacity: 0; transition: opacity 0.12s ease;
}
.cell:hover .plot-out .outtools { opacity: 1; }
@media (hover: none) { .plot-out .outtools { opacity: 1; } }
.plot-out .otool {
  color: var(--faint); cursor: pointer; text-decoration: none; line-height: 1;
  background: none; border: none; padding: 0;
}
.plot-out .otool:hover { color: var(--accent); }
/* WP-26 fix #2: centre the render frame (progress overlay + committed PNG) in
 * the output — was a left-hugging inline-block. */
.plot-out .outframe {
  position: relative; display: block; width: fit-content; max-width: 100%; margin-inline: auto;
  border: 1px solid var(--codeline); border-radius: 10px; background: var(--app); padding: 14px;
}
.plot-out .plotimg { display: block; max-width: 100%; height: auto; border-radius: 4px; }
.plot-out .plotimg-ph { width: 360px; height: 200px; background: var(--line2); border-radius: 4px; }
/* WP-27 §4.2: the friendly note shown in place of the plot when the save was
 * dropped (§3.2) or the job is gone with no embedded PNG */
.plot-out .plot-note {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  padding: 14px; text-align: center; background: var(--app);
}
.plot-out .plot-note .note-msg { font: 400 11px var(--mono); color: var(--muted); max-width: 300px; }
.plot-out .plot-note .relink { color: var(--in); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; font: 400 11px var(--mono); }
.plot-out .plot-overlay {
  position: absolute; inset: 0; border-radius: 10px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  background: color-mix(in srgb, var(--app) 74%, transparent);
  font: 500 12.5px var(--mono); color: var(--accent);
}
.plot-out .plot-overlay .runbar { width: 60%; }
.plot-out .menu-anchor { position: relative; display: inline-flex; }
