/* Mission control — Solid Two Studio's own surface.
 *
 * The brand kit, applied: graphite ground #080B0E, warm paper type #F2EEE6, and Signal
 * #FFC93C as the single accent. Type is the studio site's three faces, self-hosted
 * (Archivo for anything that carries weight, Inter for prose, JetBrains Mono for every
 * hostname, label and number).
 *
 * Four rules the whole page obeys:
 *
 * 1. **Signal is never a status.** The accent marks the current section, focus rings and
 *    the one thing you can click. Health has its own four hues — live #3FC79A, protected
 *    #F0B429, error #FF7A66, down #FF5F52, and grey for "not built / not checked" — and
 *    every one of them is a dot *and* a word, so the page survives colourblindness, a
 *    phone in sunlight, and a greyscale print.
 * 2. **Colour means health.** The decorative washes behind the project cards are strictly
 *    neutral — graphite through slate, differing only in where the light falls — so no
 *    piece of decoration can ever be read as a reading.
 * 3. **Depth comes from one step plus one hairline**, never from a glow. Cards carry a
 *    1px inner top highlight and a soft shadow; data carries neither.
 * 4. **Nothing here draws a number we don't measure.** There are no sparklines, no
 *    latency charts and no uptime bars in this stylesheet, because there is no latency
 *    history or uptime series behind this dashboard — it takes point-in-time scans.
 *
 * Layout is mobile-first; every media query adds, never subtracts. The rail is the nav on
 * a wide screen and becomes a slide-over on a phone, where the dock at the bottom carries
 * the five destinations a thumb wants.
 */

/* ── faces ────────────────────────────────────────────────────────────────── */
@font-face { font-family: Archivo; src: url(/static/Archivo.woff2) format('woff2');
  font-weight: 100 900; font-display: swap; }
@font-face { font-family: InterVar; src: url(/static/Inter.woff2) format('woff2');
  font-weight: 100 900; font-display: swap; }
@font-face { font-family: JetBrainsMonoVar; src: url(/static/JetBrainsMono.woff2) format('woff2');
  font-weight: 100 800; font-display: swap; }

/* ── the two modes ────────────────────────────────────────────────────────────
 *
 * One brand, one type set, one layout: a mode changes *colour* and nothing else. (The
 * night-mode lesson from HelloBusy — giving a mode its own fonts or sizes makes the switch
 * feel like a different product.)
 *
 * `theme.js` writes `data-theme="light|dark"` on <html> before the first paint, so there
 * is never a frame in the wrong mode. `:root` alone is the dark set, which is also the
 * fallback if that script never runs.
 *
 * Three things are split by *role* rather than by hex, and the mapping is the whole trick:
 *   --ink          the neutral every hairline, hover and overlay is mixed from. Paper in
 *                  the dark, graphite in the light — so one `rgba(var(--ink),.05)` is a
 *                  lift at night and a shade by day, everywhere, with no second rule.
 *   --signal       the accent as a *fill* (it keeps the brand's #FFC93C in both modes,
 *                  always under near-black text) …
 *   --signal-ink   … and the accent as *text, icon and indicator*, which has to darken by
 *                  day or it reads at 1.6:1. Night's Signal ↔ day's Amber, deep.
 * Health does the same: the four hues keep their hue and drop in lightness for the light
 * mode, so green is still green and nothing drifts into a new colour.
 */
:root {
  color-scheme: dark;
  --ink: 242,238,230;          /* paper, for hairlines and overlays on a dark ground */

  /* ground */
  --ground:    #080B0E;
  --rail-bg:   #0A0D11;
  --surface:   #0E1217;
  --raised:    #12171E;
  --raised-hi: #171E26;        /* a raised surface, hovered */
  --inset:     #0F141A;
  --inset-hi:  #161C24;
  --line:      rgba(var(--ink),.075);
  --line-firm: rgba(var(--ink),.14);

  --over:      rgba(var(--ink),.055); /* a chip/row lifted off its ground */
  --bar-bg:    rgba(8,11,14,.84);    /* the sticky top bar, behind its blur */
  --dock-bg:   rgba(10,13,17,.92);
  --scrim:     rgba(4,6,8,.62);

  /* type */
  --text:      #F2EEE6;
  --text-2:    #9AA6B4;
  --text-3:    #7C8794;

  /* the one accent, in its two jobs */
  --signal:    #FFC93C;
  --signal-ink:#FFC93C;
  --on-signal: #241A00;
  --signal-dim:#5C4710;
  --signal-wash: rgba(255,201,60,.10);

  /* health — four hues, each with a wash and a line */
  --live:      #3FC79A;  --live-bg:      rgba(63,199,154,.11);  --live-ln:      rgba(63,199,154,.30);
  --protected: #F0B429;  --protected-bg: rgba(240,180,41,.11);  --protected-ln: rgba(240,180,41,.30);
  --error:     #FF7A66;  --error-bg:     rgba(255,122,102,.12); --error-ln:     rgba(255,122,102,.32);
  --down:      #FF5F52;  --down-bg:      rgba(255,95,82,.12);   --down-ln:      rgba(255,95,82,.34);
  --idle:      #78838F;  --idle-bg:      rgba(120,131,143,.10); --idle-ln:      rgba(120,131,143,.26);
  --live-glow: rgba(63,199,154,.5);
  --down-glow: rgba(255,95,82,.5);

  /* the four assistants, as identity and never as a reading — see the tasks section.
     Each is an R,G,B triple for the same reason --ink is one: the chip's text, wash and
     hairline are three strengths of one hue, written once. */
  --ag-wren: 127,166,232;
  --ag-juno: 192,152,236;
  --ag-iris: 92,195,214;
  --ag-ada:  224,154,174;

  --r-sm: 8px; --r-md: 12px; --r-lg: 16px; --r-xl: 20px;

  --lift:  0 1px 2px rgba(0,0,0,.45), 0 10px 28px -18px rgba(0,0,0,.9);
  --lift-2: 0 2px 4px rgba(0,0,0,.5), 0 24px 56px -28px rgba(0,0,0,1);
  --top-hi: inset 0 1px 0 rgba(var(--ink),.045);
  --grain-op: .022;
  --wash-grain-op: .055;
  --hero-wash-a: rgba(120,150,180,.16);
  --hero-wash-b: rgba(255,201,60,.07);

  --display: Archivo, -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --body: InterVar, -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --mono: JetBrainsMonoVar, ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

  --rail-w: 236px;
  --pad: 18px;
  /* The ticker's height, in one place: the rail, the top bar and the frame all start
     below it, so this is the number three other rules read. Two lines on a phone, one
     line from 560px up — see the media query at the foot of this file. */
  --tick-h: 46px;
}

/* Day. Warm paper rather than white, because the brand's light is #F2EEE6 and a pure-white
   dashboard next to a graphite one looks like two products. Every foreground below was
   checked by script against all five grounds; the lowest pair is 4.81:1. */
[data-theme="light"] {
  color-scheme: light;
  --ink: 20,24,30;             /* graphite, for the same hairlines and overlays by day */

  --ground:    #EFEDE7;
  --rail-bg:   #E9E6DF;
  --surface:   #FBFAF7;
  --raised:    #FFFFFF;
  --raised-hi: #F4F2EC;
  --inset:     #F2F0EA;
  --inset-hi:  #FFFFFF;
  --line:      rgba(var(--ink),.12);
  --line-firm: rgba(var(--ink),.24);

  --over:      rgba(255,255,255,.78);
  --bar-bg:    rgba(239,237,231,.84);
  --dock-bg:   rgba(243,241,236,.94);
  --scrim:     rgba(28,30,34,.38);

  --text:      #15181D;
  --text-2:    #454E59;
  --text-3:    #555E6B;

  --signal:    #FFC93C;        /* the fill stays the brand's yellow, under near-black text */
  --signal-ink:#7E5200;        /* the text/icon/indicator job, at 5.4:1 and up */
  --on-signal: #241A00;
  --signal-dim:#C9A24A;
  --signal-wash: rgba(126,82,0,.10);

  --live:      #0A7050;  --live-bg:      rgba(10,112,80,.09);   --live-ln:      rgba(10,112,80,.30);
  --protected: #7E5200;  --protected-bg: rgba(126,82,0,.09);    --protected-ln: rgba(126,82,0,.30);
  --error:     #A8331A;  --error-bg:     rgba(168,51,26,.09);   --error-ln:     rgba(168,51,26,.30);
  --down:      #B51E17;  --down-bg:      rgba(181,30,23,.09);   --down-ln:      rgba(181,30,23,.32);
  --idle:      #555F6A;  --idle-bg:      rgba(85,95,106,.08);   --idle-ln:      rgba(85,95,106,.26);
  --live-glow: rgba(10,112,80,.28);
  --down-glow: rgba(181,30,23,.28);

  /* the same four hues, dropped in lightness for paper. Lowest pair here is 5.6:1. */
  --ag-wren: 42,86,160;
  --ag-juno: 106,58,160;
  --ag-iris: 17,100,118;
  --ag-ada:  148,58,82;

  --lift:  0 1px 2px rgba(23,27,33,.06), 0 10px 28px -18px rgba(23,27,33,.34);
  --lift-2: 0 2px 6px rgba(23,27,33,.08), 0 24px 56px -28px rgba(23,27,33,.5);
  --top-hi: inset 0 1px 0 rgba(255,255,255,.75);
  --grain-op: .016;
  --wash-grain-op: .035;
  --hero-wash-a: rgba(96,126,160,.12);
  --hero-wash-b: rgba(255,201,60,.18);
}

/* A single grain tile, reused by every decorative wash. It is the thing that stops a
   large dark gradient from banding on an OLED phone, and it carries no information. */
:root {
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }
body {
  background: var(--ground);
  color: var(--text);
  font: 400 15px/1.55 var(--body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
  overflow-x: hidden;
}
a { color: var(--signal-ink); text-decoration: none; }
a:hover { text-decoration: underline; }
[hidden] { display: none !important; }
:focus-visible { outline: 2px solid var(--signal-ink); outline-offset: 2px; border-radius: 6px; }

/* Numbers never jitter between refreshes. */
.num, .stat-v, .s-ms, .v-big, .bx-v, .kv-v { font-variant-numeric: tabular-nums; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--signal); color: var(--on-signal); padding: 10px 16px; border-radius: 0 0 8px 0;
  font: 600 13px/1 var(--body);
}
.skip:focus { left: 0; text-decoration: none; }

/* ═══════════════════════════ the ticker ═══════════════════════════
 *
 * A bar across the very top of the page — above the rail, above the top bar, full width —
 * carrying the live state of every monitored box in rotation. It adds a line; it replaces
 * nothing, so every page below it is exactly where it was.
 *
 * Four things keep it a pulse rather than clutter:
 *   * one line, 34px, type at 11.5px mono — the same numbers the panels show, no new ones;
 *   * a value that is not healthy is coloured **and** worded, like everywhere else here;
 *   * Signal is not a status: the dot at the left is the page's own heartbeat, and the
 *     health hues are the only colours in the items;
 *   * the motion is one transform on one element, it pauses on hover and focus, and it
 *     stops entirely for `prefers-reduced-motion` (which steps instead of scrolling).
 */
.ticker {
  position: fixed; top: 0; left: 0; right: 0; z-index: 70;
  height: calc(var(--tick-h) + env(safe-area-inset-top));
  padding-top: env(safe-area-inset-top);
  display: flex; align-items: stretch; overflow: hidden;
  /* Opaque, and the rail's ground rather than the page's: it is chrome, it sits above
     everything, and an end-fade can only be exact against a colour that is actually
     there. (The top bar below it keeps its blur — that one does have content sliding
     under it.) */
  background: var(--rail-bg);
  border-bottom: 1px solid var(--line);
}
/* The heartbeat: this page is live, and that is all it says. */
.tk-pulse {
  flex: none; display: grid; place-items: center; width: 34px; position: relative;
  border-right: 1px solid var(--line);
}
.tk-pulse i {
  width: 6px; height: 6px; border-radius: 50%; background: var(--signal-ink);
  animation: tkbeat 2.4s ease-in-out infinite;
}
@keyframes tkbeat {
  0%, 100% { opacity: .35; transform: scale(.8); }
  50%      { opacity: 1;   transform: scale(1); }
}
.tk-win { position: relative; flex: 1; min-width: 0; overflow: hidden; padding: 0 10px; }
.tk-track { position: absolute; inset: 0 10px; }
/* One slide at a time, stacked on the same line. At rest it is static type on a flat
   ground — no fade at the ends, because nothing runs off one. */
.tk-slide {
  position: absolute; inset: 0; display: flex; align-items: center; overflow: hidden;
  opacity: 0; transform: translateY(5px); pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}
/* The outgoing slide leaves before the incoming one arrives. Two lines of type crossing
   at half opacity is a smear; a short gap between them is a clean swap. */
.tk-slide.on {
  opacity: 1; transform: none;
  transition: opacity .3s ease .15s, transform .34s cubic-bezier(.3,.8,.4,1) .15s;
}
.tk-slide.out { opacity: 0; transform: translateY(-5px); }

/* The phone slide: one reading on two lines. Which box and which reading on top, the
   reading itself underneath, where a number belongs — a 360px bar cannot hold all three
   on one line without cutting one of them off, and cutting one off is the bug this
   replaces. */
.tk-slide.tk-tall { flex-direction: column; align-items: flex-start;
  justify-content: center; gap: 3px; }
.tk-top { display: flex; align-items: center; gap: 9px; min-width: 0; }
.tk-bot { display: flex; align-items: center; gap: 8px; min-width: 0; }
.tk-bot svg { width: 13px; height: 13px; flex: none; color: var(--text-3); }
.tk-bot.warn svg, .tk-bot.warn .tk-v { color: var(--protected); }
.tk-bot.bad svg, .tk-bot.bad .tk-v { color: var(--down); }
.tk-bot.ok .tk-v { color: var(--text); }
.tk-bot.ok svg { color: var(--live); }
.tk-tall .tk-box { border: 0; margin: 0; padding: 0; height: auto; }
.tk-tall .tk-k { flex: none; }
/* One reading that is still wider than the bar it has (the load line at 360px) is set a
   step smaller. Measured, applied to that slide only, and never a clipped word. */
.tk-tight .tk-v { font-size: 10.5px; }
.tk-tight .tk-box, .tk-tight .tk-k { letter-spacing: .08em; }
/* The top line of a tall slide is the chip plus one label, and a longer box name than
   today's would run it past the bar. One step down on the chip rather than a word with its
   end cut off — still measured, still applied to that slide only. */
.tk-tight .tk-box { font-size: 9.5px; }

/* A box's name, leading its own run of readings, so a number is never orphaned from the
   machine it belongs to. */
.tk-box {
  display: inline-flex; align-items: center; gap: 7px; height: 100%; flex: none;
  padding: 0 11px 0 0; margin-right: 11px; white-space: nowrap;
  border-right: 1px solid var(--line-firm);
  font: 500 10px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--text);
}
.tk-box .dot { margin-right: 1px; }

.tk-i {
  display: inline-flex; align-items: center; gap: 7px; height: 100%; flex: none;
  padding: 0 11px 0 0; white-space: nowrap; position: relative;
}
/* A separator between readings, never before the first one on a slide. */
.tk-i + .tk-i { padding-left: 11px; }
.tk-i + .tk-i::before {
  content: ''; position: absolute; left: 0; top: 50%; width: 3px; height: 3px;
  margin-top: -1.5px; border-radius: 50%; background: rgba(var(--ink),.3);
}
.tk-i svg { width: 13px; height: 13px; flex: none; color: var(--text-3); }
.tk-k {
  font: 500 9px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-3);
}
.tk-v { font: 400 11.5px/1 var(--mono); color: var(--text-2);
  font-variant-numeric: tabular-nums; }
/* Not healthy is a colour *and* the word already in the value. */
.tk-i.warn svg, .tk-i.warn .tk-v { color: var(--protected); }
.tk-i.bad  svg, .tk-i.bad  .tk-v { color: var(--down); }
.tk-i.ok   .tk-v { color: var(--text); }
.tk-i.ok   svg { color: var(--live); }

.tk-open {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  padding: 0 12px; background: none; border: 0; border-left: 1px solid var(--line);
  color: var(--text-3); cursor: pointer; font: 500 9.5px/1 var(--mono);
  letter-spacing: .14em; text-transform: uppercase;
}
.tk-open svg { width: 13px; height: 13px; }
.tk-open:hover { color: var(--text); background: var(--over); }
.tk-open .tk-open-t { display: none; }

/* ═══════════════════════════ the shell ═══════════════════════════ */

.frame {
  min-height: 100vh;
  display: flex; flex-direction: column;
  padding-top: calc(var(--tick-h) + env(safe-area-inset-top));
  padding-bottom: calc(62px + env(safe-area-inset-bottom));   /* the dock */
}

/* ── the rail ─────────────────────────────────────────────────────────────── */
.rail {
  /* Starts below the ticker: the bar is full-width across the top of the whole page, so
     nothing — not even the navigation — sits beside it. */
  position: fixed; inset: calc(var(--tick-h) + env(safe-area-inset-top)) auto 0 0;
  width: var(--rail-w); z-index: 60;
  background: var(--rail-bg);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
  padding: 0 0 env(safe-area-inset-bottom);
  transform: translateX(-100%);
  transition: transform .22s cubic-bezier(.3,.8,.4,1);
}
.rail.open { transform: none; }
.scrim {
  position: fixed; inset: calc(var(--tick-h) + env(safe-area-inset-top)) 0 0 0; z-index: 55;
  background: var(--scrim);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}

.rail-brand {
  display: flex; align-items: center; gap: 11px;
  /* No safe-area inset here any more: the ticker above the rail already clears the notch. */
  padding: 16px 16px 16px;
}
.rail-brand .mark { height: 32px; width: 32px; flex: none; border-radius: 7.5px; }
.rail-brand .lockup { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.r-title {
  font: 800 15px/1.1 var(--display); letter-spacing: -.015em;
  font-variation-settings: 'wdth' 112; white-space: nowrap;
}
.r-sub {
  font: 400 9px/1.1 var(--mono); letter-spacing: .16em;
  text-transform: uppercase; color: var(--text-3); white-space: nowrap;
}

/* `align-content: start` is doing real work: without it the grid stretches its seven rows
   to fill the flex height and the nav reads as seven unrelated items instead of a list. */
.rail-nav { flex: 1; overflow-y: auto; padding: 6px 10px; display: grid; gap: 2px;
  align-content: start; }
.nav-i {
  display: flex; align-items: center; gap: 11px; width: 100%;
  background: none; border: 0; color: var(--text-2); cursor: pointer;
  padding: 0 11px; height: 42px; border-radius: 10px;
  font: 500 13.5px/1 var(--body); text-align: left;
  position: relative;
  transition: background .14s, color .14s;
}
.nav-i svg { width: 17px; height: 17px; flex: none; opacity: .85; }
.nav-i .n-t { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }
.nav-i .n-n {
  font: 500 10.5px/1 var(--mono); color: var(--text-3);
  background: var(--over); border-radius: 999px; padding: 4px 7px;
}
.nav-i:hover { background: var(--over); color: var(--text); }
.nav-i.on { background: var(--over); color: var(--text); }
.nav-i.on svg { opacity: 1; color: var(--signal-ink); }
.nav-i.on::before {
  content: ''; position: absolute; left: -10px; top: 11px; bottom: 11px; width: 2.5px;
  background: var(--signal-ink); border-radius: 0 3px 3px 0;
}
.nav-i.on .n-n { background: var(--signal-wash); color: var(--signal-ink); }
.nav-sep { height: 1px; background: var(--line); margin: 7px 11px; }

.rail-foot { padding: 12px 14px calc(14px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line); }
.r-stamp {
  margin-top: 9px; font: 400 10px/1.5 var(--mono); color: var(--text-3);
  letter-spacing: .02em;
}

/* ── the top bar ──────────────────────────────────────────────────────────── */
.top {
  /* Sticks *below* the ticker, which owns the top edge and the notch. */
  position: sticky; top: calc(var(--tick-h) + env(safe-area-inset-top)); z-index: 40;
  display: flex; align-items: center; gap: 10px;
  padding: 10px var(--pad);
  border-bottom: 1px solid var(--line);
  background: var(--bar-bg);
  -webkit-backdrop-filter: saturate(170%) blur(16px);
  backdrop-filter: saturate(170%) blur(16px);
}
.top-title {
  font: 700 15px/1.2 var(--display); letter-spacing: -.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.icon-btn {
  background: var(--raised); border: 1px solid var(--line-firm); color: var(--text-2);
  width: 38px; height: 38px; flex: none; border-radius: 11px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: border-color .15s, color .15s, background .15s;
}
.icon-btn svg { width: 16px; height: 16px; }
.icon-btn:hover { border-color: var(--text-3); color: var(--text); background: var(--raised-hi); }
.icon-btn:disabled { opacity: .5; cursor: default; }
.icon-btn.spin svg { animation: spin .9s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.search { position: relative; flex: 1; min-width: 0; display: flex; align-items: center; }
.search .s-ico {
  position: absolute; left: 12px; width: 15px; height: 15px; color: var(--text-3);
  pointer-events: none;
}
.search input {
  width: 100%; height: 38px; border-radius: 11px;
  background: var(--raised); border: 1px solid var(--line);
  color: var(--text); font: 400 13.5px/1 var(--body);
  padding: 0 46px 0 35px;
  transition: border-color .15s, background .15s;
}
.search input::placeholder { color: var(--text-3); }
.search input:focus { outline: none; border-color: var(--line-firm); background: var(--inset-hi); }
.search input::-webkit-search-cancel-button { -webkit-appearance: none; }
.hint {
  position: absolute; right: 10px; font: 400 10.5px/1 var(--mono); color: var(--text-3);
  border: 1px solid var(--line); border-radius: 5px; padding: 4px 5px;
  pointer-events: none;
}
.results {
  position: absolute; top: 46px; left: 0; right: 0; z-index: 50;
  background: var(--surface); border: 1px solid var(--line-firm); border-radius: var(--r-md);
  box-shadow: var(--lift-2); overflow: hidden; max-height: 58vh; overflow-y: auto;
}
.res {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: 0; cursor: pointer; text-align: left;
  padding: 9px 12px; color: var(--text); border-bottom: 1px solid var(--line);
}
.res:last-child { border-bottom: 0; }
.res:hover, .res.cur { background: rgba(var(--ink),.05); }
.res-t { flex: 1; min-width: 0; font: 400 13px/1.35 var(--mono);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.res-s { font: 400 11px/1 var(--body); color: var(--text-3); white-space: nowrap; }
.res-none { padding: 14px 12px; color: var(--text-3); font-size: 13px; }

/* ── the dock (phone) ─────────────────────────────────────────────────────── */
.dock {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  display: flex; align-items: stretch;
  border-top: 1px solid var(--line);
  background: var(--dock-bg);
  -webkit-backdrop-filter: saturate(170%) blur(16px);
  backdrop-filter: saturate(170%) blur(16px);
  padding-bottom: env(safe-area-inset-bottom);
}
.dock-i {
  flex: 1; min-width: 0; background: none; border: 0; cursor: pointer;
  color: var(--text-3); padding: 8px 2px 7px;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
}
.dock-i svg { width: 19px; height: 19px; }
.dock-i span { font: 500 9.5px/1 var(--body); letter-spacing: .01em; }
.dock-i.on { color: var(--signal-ink); }

/* ═══════════════════════════ page furniture ═══════════════════════════ */

main { flex: 1; width: 100%; max-width: 1240px; margin: 0 auto;
  padding: 20px var(--pad) 40px; }

.foot {
  max-width: 1240px; margin: 0 auto; width: 100%;
  padding: 20px var(--pad) 28px;
  border-top: 1px solid var(--line);
  color: var(--text-3); font: 400 11.5px/1.65 var(--body);
}

.banner {
  background: var(--error-bg); border: 1px solid var(--error-ln); color: var(--text);
  border-radius: var(--r-md); padding: 11px 14px; font-size: 13px; margin-bottom: 16px;
}

/* A grid item's default `min-width: auto` refuses to shrink below its content, so one
   long Caddy path inside a surface row pushes the whole page sideways on a phone — and
   with `overflow-x: hidden` on the body that is not a scrollbar, it is text cut off at
   the right edge with no way to reach it, which is exactly what Anton photographed. Every
   grid on this page holds text that is allowed to wrap or truncate, so every one of them
   says so once, here, rather than being remembered per component. */
.grid > *, .stats > *, .bx-grid > *, .surfaces > *, .logs > *, .feed > *, .pcols > *,
.feed .fe > *, .sugs > *, .accs > *, .lx > *, .lx-row > *, .lx-specs > *, .kv > *,
.facts > *, .seg > *, .side > *, .section-head > *, .changes > *, .flips > *, .decs > *,
.dec > *, .rc-body > *, .home-top > * { min-width: 0; }
/* The same thing one level down: a flex child defaults to not shrinking below its
   content either, and these are the ones that hold a hostname or a sentence. */
.acc > summary > *, .surf > summary > *, .log > summary > * { min-width: 0; }

.section-head {
  display: flex; align-items: center; gap: 12px; margin: 30px 0 13px; min-width: 0;
}
.section-head:first-child { margin-top: 4px; }
/* The title wraps rather than running off the edge: "Claude login — Clood's credentials"
   is wider than a 360px phone on its own. */
.section-head h2 {
  font: 500 10px/1.5 var(--mono); letter-spacing: .19em; text-transform: uppercase;
  color: var(--text-3); overflow-wrap: anywhere;
}
.section-head .rule { flex: 1; height: 1px; background: var(--line); }
.section-head .sh-x { font: 400 11px/1 var(--mono); color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.page-intro { color: var(--text-2); font-size: 13.5px; max-width: 72ch; margin: -2px 0 6px;
  overflow-wrap: anywhere; }

/* ── status primitives: a dot AND a word, always ──────────────────────────── */
.dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--idle);
  box-shadow: 0 0 0 3px rgba(120,131,143,.10); }
.dot.live { background: var(--live); box-shadow: 0 0 0 3px rgba(63,199,154,.13); }
.dot.protected { background: var(--protected); box-shadow: 0 0 0 3px rgba(240,180,41,.13); }
.dot.error { background: var(--error); box-shadow: 0 0 0 3px rgba(255,122,102,.14); }
.dot.down { background: var(--down); box-shadow: 0 0 0 3px rgba(255,95,82,.14); }

.badge {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  border-radius: 999px; padding: 4px 10px 4px 8px;
  font: 500 10.5px/1 var(--mono); letter-spacing: .09em; text-transform: uppercase;
  background: var(--idle-bg); border: 1px solid var(--idle-ln); color: var(--text-2);
}
.badge.live { background: var(--live-bg); border-color: var(--live-ln); color: var(--live); }
.badge.protected { background: var(--protected-bg); border-color: var(--protected-ln);
  color: var(--protected); }
.badge.error { background: var(--error-bg); border-color: var(--error-ln); color: var(--error); }
.badge.down { background: var(--down-bg); border-color: var(--down-ln); color: var(--down); }
/* A state element is coloured by the component that owns it, never by an ancestor's
   state class — otherwise a healthy dot inside an `error` card repaints red and quietly
   contradicts the word next to it. */
.badge .dot { background: currentColor; box-shadow: none; width: 6px; height: 6px; }

.chev { width: 15px; height: 15px; flex: none; color: var(--text-3);
  transition: transform .16s; }
details[open] > summary .chev { transform: rotate(90deg); }

/* ═══════════════════════════ the hero ═══════════════════════════ */

.hero {
  position: relative; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--r-xl);
  background: var(--surface);
  box-shadow: var(--lift), var(--top-hi);
}
/* Decoration, and nothing else: a single wide light source behind the verdict. It carries
   no reading — the verdict's own colour is the dot and the word. */
.hero::before {
  content: ''; position: absolute; inset: -40% -10% auto -10%; height: 220%;
  background:
    radial-gradient(60% 70% at 22% 10%, var(--hero-wash-a), transparent 70%),
    radial-gradient(45% 60% at 85% 0%, var(--hero-wash-b), transparent 72%);
  pointer-events: none;
}
.hero::after {
  content: ''; position: absolute; inset: 0; background-image: var(--grain);
  background-size: 140px 140px; opacity: var(--grain-op); pointer-events: none;
}
.hero-top { position: relative; padding: 6px 11px; display: flex;
  align-items: center; gap: 8px; }
.ring {
  width: 16px; height: 16px; flex: none; border-radius: 50%;
  border: 1.5px solid var(--idle-ln);
  display: grid; place-items: center;
}
.ring i { width: 6px; height: 6px; border-radius: 50%; background: var(--idle); }
.hero.ok .ring { border-color: var(--live-ln); }
.hero.ok .ring i { background: var(--live); box-shadow: 0 0 14px var(--live-glow); }
.hero.bad .ring { border-color: var(--down-ln); }
.hero.bad .ring i { background: var(--down); box-shadow: 0 0 14px var(--down-glow); }

/* Verdict and its detail share one line — "All clear · 42 of 43 answering, all under 1s". */
.v-text { min-width: 0; display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.v-big {
  font: 700 13px/1.2 var(--display); letter-spacing: -.01em;
  font-variation-settings: 'wdth' 104;
}
.v-sub { color: var(--text-2); font-size: 11.5px; margin-top: 0; }
.v-sub::before { content: '·'; margin-right: 8px; color: var(--text-3); }
.v-jump {
  background: none; border: 0; color: var(--text-2); cursor: pointer; padding: 0;
  font: inherit; border-bottom: 1px dashed var(--line-firm);
}
.v-jump code { font: 400 12.5px/1 var(--mono); color: var(--down); }
.v-jump:hover { color: var(--text); }

.stats {
  position: relative; display: grid; grid-template-columns: 1fr 1fr;
  border-top: 1px solid var(--line);
}
.stat { padding: 11px 15px; border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line); }
.stat:nth-child(2n) { border-right: 0; }
.stat:nth-last-child(-n+2) { border-bottom: 0; }
.stat-k { font: 500 9px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase;
  color: var(--text-3); }
.stat-v { font: 700 18px/1.15 var(--display); letter-spacing: -.02em; margin: 6px 0 3px; }
.stat-s { font: 400 11px/1.4 var(--body); color: var(--text-3); }

/* ═══════════════════════════ Home's top row ═══════════════════════════
 *
 * The verdict and "Running now", side by side where there is room for both and stacked
 * where there isn't. The card is a fixed 300px rather than a fraction: it holds a chip, a
 * task name and a clock, and that is the width those three want — letting it grow on a
 * 27-inch screen would only stretch the gap between them.
 *
 * It sits on the same two-column breakpoint as a project page's side column (1200px), so
 * a desktop window that is too narrow for the rail *and* two columns gets one column,
 * which is the same answer the rest of the page gives.
 */
.home-top { display: grid; gap: 10px; align-items: start; }
.home-top > * { min-width: 0; }

.runcard {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-xl);
  box-shadow: var(--lift), var(--top-hi); overflow: hidden;
  display: flex; flex-direction: column;
}
.rc-head { display: flex; align-items: center; gap: 9px; padding: 12px 14px 10px; }
.rc-k { font: 500 9.5px/1 var(--mono); letter-spacing: .17em; text-transform: uppercase;
  color: var(--text-3); }
/* The count is Signal's own job — liveness, not health. See rule 1 at the top. */
.rc-n { font: 500 10px/1 var(--mono); color: var(--signal-ink);
  background: var(--signal-wash); border: 1px solid rgba(var(--ink),.08);
  border-radius: 999px; padding: 3px 7px; }
.rc-body { display: grid; gap: 1px; background: var(--line); }
.rc-row {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: var(--raised); border: 0; color: var(--text); cursor: pointer;
  padding: 10px 14px; font: inherit; min-width: 0;
}
.rc-row:hover { background: var(--raised-hi); }
.rc-t { flex: 1; min-width: 0; display: block; }
.rc-name { display: block; font: 400 12.5px/1.35 var(--mono); overflow-wrap: anywhere; }
.rc-m { display: flex; align-items: center; gap: 8px; margin-top: 4px;
  font: 400 11px/1.4 var(--mono); color: var(--text-3); }
.rc-el { color: var(--text-2); font-variant-numeric: tabular-nums; }
.rc-ago::before { content: '·'; margin-right: 7px; color: var(--text-3); }
.rc-idle { color: var(--text-3); font-size: 12.5px; padding: 4px 14px 14px;
  background: var(--surface); }
.rc-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  background: none; border: 0; border-top: 1px solid var(--line); cursor: pointer;
  color: var(--text-3); padding: 11px 14px; font: 500 11.5px/1 var(--body);
  width: 100%; text-align: left;
}
.rc-foot:hover { color: var(--text); background: rgba(var(--ink),.025); }
.rc-foot .chev { width: 14px; height: 14px; }

/* ═══════════════════════════ portfolio cards ═══════════════════════════ */

.grid { display: grid; gap: 10px; grid-template-columns: repeat(2, 1fr); }

.ptile {
  position: relative; overflow: hidden; text-align: left; cursor: pointer;
  background: var(--raised); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 0; color: var(--text); display: flex; flex-direction: row; align-items: stretch;
  box-shadow: var(--top-hi);
  transition: border-color .15s, transform .15s, box-shadow .15s;
}
.ptile:hover { border-color: var(--line-firm); transform: translateY(-1px);
  box-shadow: var(--lift), var(--top-hi); }
.ptile:active { transform: none; }

/* The project's colour, now a slim stripe down the side rather than a tall empty band —
   the identity stays, the wasted space is gone. Every wash is neutral (graphite through
   slate) so decoration can never be mistaken for a measurement. */
.wash { position: relative; width: 5px; flex: none; overflow: hidden;
  border-right: 1px solid var(--line); }
.wash::after {
  content: ''; position: absolute; inset: 0; background-image: var(--grain);
  background-size: 140px 140px; opacity: var(--wash-grain-op);
}
/* One hairline of light along the top edge, shared by every wash — the detail that makes
   a flat dark rectangle look like a surface rather than a hole. */
.wash::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(var(--ink),.14), transparent);
}
.w0 { background: radial-gradient(120% 170% at 10% -10%, #3A4654, #0C1015 66%); }
.w1 { background: radial-gradient(130% 180% at 90% 0%, #414C58, #0B0F13 64%); }
.w2 { background: linear-gradient(118deg, #273340 0%, #0C1015 55%, #222C37 100%); }
.w3 { background: radial-gradient(110% 160% at 50% 130%, #36434F, #0B0F14 68%); }
.w4 { background: linear-gradient(200deg, #3C4652 0%, #0D1116 60%); }
.w5 { background: radial-gradient(140% 140% at -5% 120%, #2F3A45, #0F141A 62%); }
.w6 { background: linear-gradient(145deg, #1A222A 0%, #3D4854 46%, #0C1015 100%); }
.w7 { background: radial-gradient(100% 170% at 80% 125%, #36414D, #0B0F13 68%); }
.w8 { background: linear-gradient(95deg, #0C1015 0%, #35404C 70%, #1B232B 100%); }
/* The studio's own tile is the one place Signal appears as decoration — the brand kit's
   rule, and it marks "this is us", not a state. */
.w-studio { background:
  radial-gradient(120% 170% at 12% -10%, rgba(255,201,60,.26), transparent 60%),
  linear-gradient(150deg, #2C3138, #0B0F13 68%); }

/* The project tiles' decorative bands by day. Same neutral family and the same light
   positions as the night set — slate through paper — so no wash can ever read as a
   measurement in either mode. */
[data-theme="light"] .w0 { background: radial-gradient(120% 170% at 10% -10%, #C9D2DC, #F3F2EE 66%); }
[data-theme="light"] .w1 { background: radial-gradient(130% 180% at 90% 0%, #C3CCD7, #F4F3EF 64%); }
[data-theme="light"] .w2 { background: linear-gradient(118deg, #CFD9E4 0%, #F3F2EE 55%, #D8DFE7 100%); }
[data-theme="light"] .w3 { background: radial-gradient(110% 160% at 50% 130%, #CCD5DF, #F4F3EF 68%); }
[data-theme="light"] .w4 { background: linear-gradient(200deg, #C7D0DB 0%, #F2F1ED 60%); }
[data-theme="light"] .w5 { background: radial-gradient(140% 140% at -5% 120%, #D2DAE3, #F3F2EE 62%); }
[data-theme="light"] .w6 { background: linear-gradient(145deg, #E2E6EA 0%, #C6CFDA 46%, #F3F2EE 100%); }
[data-theme="light"] .w7 { background: radial-gradient(100% 170% at 80% 125%, #CCD5E0, #F4F3EF 68%); }
[data-theme="light"] .w8 { background: linear-gradient(95deg, #F3F2EE 0%, #CDD6E0 70%, #E3E7EB 100%); }
[data-theme="light"] .w-studio { background:
  radial-gradient(120% 170% at 12% -10%, rgba(255,201,60,.55), transparent 62%),
  linear-gradient(150deg, #E6E3DB, #F4F3EF 68%); }
[data-theme="light"] .wash::before {
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.8), transparent); }

.t-body { padding: 11px 14px; display: flex; flex-direction: row; align-items: center;
  gap: 12px; flex: 1; min-width: 0; }
.t-name {
  font: 700 14.5px/1.2 var(--display); letter-spacing: -.012em; flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.t-meta { display: flex; align-items: center; gap: 7px; min-width: 0; flex: none; }
.t-word { font: 500 10px/1 var(--mono); letter-spacing: .13em; text-transform: uppercase;
  color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ptile.live .t-word { color: var(--live); }
.ptile.protected .t-word { color: var(--protected); }
.ptile.error .t-word { color: var(--error); }
.ptile.down .t-word { color: var(--down); }
.t-n { margin-left: auto; font: 400 11px/1 var(--mono); color: var(--text-3);
  white-space: nowrap; flex: none; display: inline-flex; gap: 4px; }
.t-n b { font-weight: 400; }
.t-n i { font-style: normal; display: none; }
.t-seal { font: 500 9px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-3); border: 1px solid var(--line-firm); border-radius: 999px;
  padding: 3px 6px; align-self: center; flex: none; }

/* ── portfolio as a table: rows and columns (`ptbl`, kept clear of the `.ptab` tab bar) ── */
.ptbl { border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
  background: var(--raised); box-shadow: var(--top-hi); }
.ptbl-h, .ptbl-r {
  display: grid; grid-template-columns: 18px minmax(0, 1fr) 96px 78px;
  align-items: center; gap: 10px; padding: 0 15px;
}
.ptbl-h { height: 32px; border-bottom: 1px solid var(--line);
  font: 500 9px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase;
  color: var(--text-3); }
.ptbl-r { height: 42px; width: 100%; text-align: left; cursor: pointer; color: var(--text);
  background: none; border: 0; border-top: 1px solid var(--line); font: inherit;
  transition: background .13s; }
.ptbl-r:first-of-type { border-top: 0; }
.ptbl-r:hover { background: var(--raised-hi, rgba(var(--ink), .035)); }
.pr-dot { display: inline-flex; }
.pr-name { font: 700 14px/1.2 var(--display); letter-spacing: -.012em; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  display: flex; align-items: center; gap: 8px; }
.pr-seal { font: 500 8.5px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-3); border: 1px solid var(--line-firm); border-radius: 999px;
  padding: 3px 6px; flex: none; }
.pr-word { font: 500 10px/1 var(--mono); letter-spacing: .13em; text-transform: uppercase;
  color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ptbl-r.live .pr-word { color: var(--live); }
.ptbl-r.protected .pr-word { color: var(--protected); }
.ptbl-r.error .pr-word { color: var(--error); }
.ptbl-r.down .pr-word { color: var(--down); }
.pr-n { font: 400 12px/1 var(--mono); color: var(--text-3); text-align: right;
  justify-self: end; white-space: nowrap; }

/* ═══════════════════════════ this box ═══════════════════════════ */

.bx-grid { display: grid; gap: 12px; grid-template-columns: 1fr; }
.bx-cell {
  background: var(--raised); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 15px 16px 16px; box-shadow: var(--top-hi);
}
.bx-k { font: 500 9.5px/1 var(--mono); letter-spacing: .17em; text-transform: uppercase;
  color: var(--text-3); }
.bx-v { font: 700 24px/1.15 var(--display); letter-spacing: -.022em; margin: 9px 0 11px; }
.bx-s { font: 400 11px/1.5 var(--mono); color: var(--text-3); margin-top: 9px; }
/* A state cell: the dot needs a flex parent to have a size at all, and the gap keeps it
   off the word rather than against it. */
.bx-v.with-dot { display: flex; align-items: center; gap: 11px; }
.meter { height: 5px; border-radius: 3px; background: rgba(var(--ink),.07); overflow: hidden; }
.meter-f { display: block; height: 100%; border-radius: 3px; background: var(--idle); }
.meter-f.ok { background: var(--live); }
.meter-f.warn { background: var(--protected); }
.meter-f.bad { background: var(--down); }

.bx-notes { list-style: none; margin-top: 12px; display: grid; gap: 8px; }
.bx-notes li {
  background: var(--protected-bg); border: 1px solid var(--protected-ln);
  border-radius: var(--r-md); padding: 10px 13px; font-size: 12.5px; color: var(--text);
}
.bx-foot { margin-top: 12px; font: 400 11px/1.6 var(--mono); color: var(--text-3); }

/* Home's copy of This box is a slim glance — the full-size readings live on Infra. Scoped
   to `.home-box` so the Infra copy of the identical boxRow is untouched. */
.home-box .bx-grid { gap: 10px; }
.home-box .bx-cell { padding: 11px 13px 12px; }
.home-box .bx-v { font-size: 17px; margin: 4px 0 8px; }
.home-box .bx-s { font-size: 10px; margin-top: 7px; }
.home-box .meter { height: 4px; }
.home-box .bx-notes { margin-top: 10px; gap: 6px; }
.home-box .bx-notes li { padding: 8px 11px; font-size: 11.5px; }

.fcast {
  margin-top: 12px; background: var(--inset); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 15px 16px;
}
.fc-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.fc-k { font: 500 9.5px/1 var(--mono); letter-spacing: .17em; text-transform: uppercase;
  color: var(--text-3); }
.fc-tag { font: 400 10px/1 var(--mono); color: var(--text-3);
  border: 1px solid var(--line-firm); border-radius: 999px; padding: 4px 8px; }
.fc-big { font: 700 18px/1.25 var(--display); letter-spacing: -.015em; margin: 10px 0 7px; }
.fc-d { color: var(--text-2); font-size: 13px; max-width: 78ch; }
.fc-s { margin-top: 9px; font: 400 10.5px/1 var(--mono); color: var(--text-3); }
/* The same forecast, inside a project's Metrics: it is one reading among several there,
   not the page's subject, so it loses the inset ground and keeps the words. */
.fcast.flat { margin-top: 0; background: none; border: 0; padding: 0; }
.fcast.flat .fc-big { font-size: 16px; }

/* ═══════════════════════════ infra: one panel stack per box ═══════════════════
 *
 * Infra is panels, read top to bottom. Each monitored box is a heading, a one-line
 * identity, its own readings, its runway, and then the host's side of it.
 */
.boxsec + .boxsec { margin-top: 34px; padding-top: 4px; }
.boxsec-id {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  margin: -4px 0 13px; font: 400 11.5px/1.5 var(--mono); color: var(--text-3);
}
.boxsec-label { color: var(--text-2); }
.boxsec-meta { min-width: 0; overflow-wrap: anywhere; }

/* ═══════════════════════════ accordion rows ═══════════════════════════
 *
 * The portfolio is a list of rows: the collapsed line is the whole headline — the project,
 * its state in a word, and the numbers you came to check — and the open body is that
 * project's own readings, including the box it runs on if it has one of its own.
 *
 * It is the same furniture as a surface row on purpose (one hairline-separated list, one
 * chevron, one hit area), because they are the same gesture: read the line, open the one
 * that needs reading.
 */
.accs { border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
  background: var(--line); display: grid; gap: 1px; }
.acc { background: var(--raised); }
.acc > summary {
  display: flex; align-items: center; gap: 13px; padding: 14px 15px; cursor: pointer;
  list-style: none; min-height: 60px;
}
.acc > summary::-webkit-details-marker { display: none; }
.acc > summary:hover { background: rgba(var(--ink),.025); }
.acc-t { flex: 1; min-width: 0; }
.acc-name { display: flex; align-items: center; gap: 9px; min-width: 0;
  font: 700 15px/1.25 var(--display); letter-spacing: -.012em; }
.acc-name > span { min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
.acc-label { font: 400 11px/1 var(--mono); color: var(--text-3); flex: none; }
.acc-sub { margin-top: 4px; font: 400 11.5px/1.45 var(--mono); color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The part of a sub-line that only exists when there is room for it. */
.acc-wide { display: none; }
/* The collapsed numbers. Hidden on a phone, where the row's two lines are already the
   headline and a third would wrap into a paragraph. */
.acc-nums { display: none; flex: none; gap: 20px; }
.acc-num { text-align: right; }
.acc-num b { display: block; font: 600 13.5px/1.15 var(--display);
  font-variant-numeric: tabular-nums; letter-spacing: -.01em; white-space: nowrap; }
.acc-num i { font-style: normal; display: block; margin-top: 3px;
  font: 500 9px/1 var(--mono); letter-spacing: .15em; text-transform: uppercase;
  color: var(--text-3); }
.acc-num.warn b { color: var(--protected); }
.acc-num.bad b { color: var(--down); }
.acc-state { flex: none; text-align: right; }
.acc-word { font: 500 9.5px/1 var(--mono); letter-spacing: .13em; text-transform: uppercase;
  color: var(--text-3); }
.acc.ok .acc-word { color: var(--live); }
.acc.warn .acc-word { color: var(--protected); }
.acc.bad .acc-word { color: var(--down); }
.acc-open { padding: 2px 15px 17px; }
.acc-open > .section-head:first-child { margin-top: 10px; }
.acc.live .acc-word { color: var(--live); }
.acc.protected .acc-word { color: var(--protected); }
.acc.error .acc-word { color: var(--error); }
.acc.down .acc-word { color: var(--down); }
.acc-go { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.acc-go button.ghost { max-width: 100%; overflow: hidden; text-overflow: ellipsis;
  display: block; line-height: 36px; }

/* ── a monitored box inside a project's Metrics ───────────────────────────────
   The Chicago box's readings, shown on the HelloBusy project page because that is whose
   box it is. Same cells as Infra, one card around them, and the runway underneath. */
.hostbox { background: var(--raised); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--lift); overflow: hidden; }
.hb-head { display: flex; align-items: center; gap: 12px; padding: 15px 16px;
  border-bottom: 1px solid var(--line); flex-wrap: wrap; }
/* Wide enough that the box's name and its label stay on one line before the pips are
   allowed to take the rest of the row. */
.hb-id { min-width: 0; flex: 1 1 240px; }
.hb-name { display: flex; align-items: baseline; gap: 9px; min-width: 0;
  font: 700 15px/1.2 var(--display); letter-spacing: -.012em; }
.hb-name > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hb-name .dot { align-self: center; }
.hb-meta { margin-top: 4px; font: 400 11.5px/1.45 var(--mono); color: var(--text-3); }
.hb-pips { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.hb-body { padding: 15px 16px; }
.hb-body .bx-grid { gap: 11px; }
.hb-run { margin-top: 13px; padding-top: 13px; border-top: 1px solid var(--line); }

/* ═══════════════════════════ activity feed ═══════════════════════════ */

.feed { display: grid; gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; }
.fe {
  display: grid; grid-template-columns: 58px 16px 1fr; gap: 10px; align-items: start;
  background: var(--raised); padding: 12px 14px;
}
.fe-at { font: 400 11px/1.5 var(--mono); color: var(--text-3); white-space: nowrap;
  padding-top: 1px; }
.fe-ic { display: grid; place-items: center; padding-top: 5px; }
.fe-ic svg { width: 13px; height: 13px; color: var(--text-3); }
.fe-b { min-width: 0; }
.fe-t { font-size: 13.5px; line-height: 1.45; overflow-wrap: anywhere; }
.fe-t code { font: 400 12.5px/1 var(--mono); color: var(--text-2); }
.fe-s { margin-top: 3px; font-size: 12px; color: var(--text-3); line-height: 1.5;
  overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; }
/* Narrow: the project name drops under the entry it belongs to, in the entry's own
   column. Wide: it moves to a column of its own on the right. */
.fe-p { grid-column: 3; margin-top: 5px;
  font: 400 10.5px/1 var(--mono); color: var(--text-3); letter-spacing: .04em; }

/* ═══════════════════════════ surfaces ═══════════════════════════ */

.surfaces { border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
  background: var(--line); display: grid; gap: 1px; }
.surf { background: var(--raised); }
.surf > summary {
  display: flex; align-items: center; gap: 11px; padding: 12px 14px; cursor: pointer;
  list-style: none; min-height: 56px;
}
.surf > summary::-webkit-details-marker { display: none; }
.surf > summary:hover { background: rgba(var(--ink),.025); }
.s-body { flex: 1; min-width: 0; }
.s-host { font: 400 13.5px/1.35 var(--mono); display: flex; align-items: center; gap: 9px;
  min-width: 0; }
.s-host > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-width: 0; }
/* The alias shrinks with the hostname it belongs to rather than pushing it off the
   edge: two full domains do not fit one 320px line. */
.s-host .alias { color: var(--text-3); font-size: 11.5px; min-width: 0; }
.s-label { font-size: 12px; color: var(--text-2); margin-top: 2px; padding-left: 16px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.s-proj + .s-label { margin-top: 1px; }
.s-where { display: flex; align-items: center; gap: 7px; margin-top: 5px; min-width: 0;
  padding-left: 16px; }
.hb { font: 500 9.5px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-2); background: var(--over);
  border-radius: 5px; padding: 4px 6px; flex: none; }
.s-detail { font: 400 11px/1.3 var(--mono); color: var(--text-3); min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.s-right { text-align: right; flex: none; }
.s-ms { font: 600 14px/1.1 var(--display); letter-spacing: -.01em; }
.s-ms small { font: 400 10px/1 var(--mono); color: var(--text-3); margin-left: 1px; }
.s-ms.slow { color: var(--protected); }
.s-word { display: block; margin-top: 3px; font: 500 9.5px/1 var(--mono);
  letter-spacing: .12em; text-transform: uppercase; color: var(--text-3); }
.surf.live .s-word { color: var(--live); }
.surf.protected .s-word { color: var(--protected); }
.surf.error .s-word { color: var(--error); }
.surf.down .s-word { color: var(--down); }

.s-open { padding: 0 14px 14px; }
.why { border-radius: var(--r-md); padding: 13px 14px; border: 1px solid var(--line);
  background: var(--inset); }
.why.live { border-color: var(--live-ln); background: var(--live-bg); }
.why.protected, .why.by-design { border-color: var(--protected-ln);
  background: var(--protected-bg); }
.why.error { border-color: var(--error-ln); background: var(--error-bg); }
.why.down { border-color: var(--down-ln); background: var(--down-bg); }
.why-head { display: flex; gap: 9px; align-items: baseline; flex-wrap: wrap; }
/* These two were the page's last AA miss at 4.08:1 — a label small enough to be set in
   9.5px mono has to be `--text-2`, not `--text-3`. */
.why-k { font: 500 9.5px/1 var(--mono); letter-spacing: .15em; text-transform: uppercase;
  color: var(--text-2); flex: none; }
.why-h { font: 600 13.5px/1.4 var(--body); }
.why-d { margin-top: 7px; font-size: 13px; color: var(--text-2); line-height: 1.6;
  overflow-wrap: anywhere; }
.why-d code { font: 400 12px/1 var(--mono); }
.facts { margin-top: 11px; display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: 4px 14px; font: 400 11.5px/1.5 var(--mono); }
.facts dt { color: var(--text-2); overflow-wrap: anywhere; }
.facts dd { color: var(--text-2); overflow-wrap: anywhere; }
.why-fix { margin-top: 11px; padding-top: 10px; border-top: 1px solid var(--line);
  font-size: 12.5px; color: var(--text-2); }
.why-fix-k { font: 500 9.5px/1 var(--mono); letter-spacing: .15em; text-transform: uppercase;
  color: var(--signal-ink); margin-right: 8px; }

.hist { margin-top: 11px; display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.hist-k { font: 500 9.5px/1 var(--mono); letter-spacing: .15em; text-transform: uppercase;
  color: var(--text-3); }
.hist-line { display: flex; gap: 3px; }
.pip { width: 7px; height: 14px; border-radius: 2px; background: var(--idle); }
.pip.live { background: var(--live); }
.pip.protected { background: var(--protected); }
.pip.error { background: var(--error); }
.pip.down { background: var(--down); }
.hist-s { font: 400 11px/1 var(--mono); color: var(--text-3); }
.s-stamp { margin-top: 9px; font: 400 10.5px/1 var(--mono); color: var(--text-3); }

.recs { margin-top: 11px; }
.recs summary { cursor: pointer; font: 400 11.5px/1 var(--mono); color: var(--text-3);
  padding: 7px 0; list-style: none; display: flex; align-items: center; gap: 6px; }
.recs summary::-webkit-details-marker { display: none; }
.recs table { width: 100%; border-collapse: collapse; margin-top: 6px; }
.recs td { font: 400 11.5px/1.5 var(--mono); color: var(--text-2); padding: 4px 10px 4px 0;
  vertical-align: top; overflow-wrap: anywhere; }
.recs td:first-child { color: var(--text-2); overflow-wrap: anywhere; width: 1%; }

/* ── the surfaces page: filter chips ──────────────────────────────────────── */
.chips { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 13px; }
.chip {
  background: var(--raised); border: 1px solid var(--line); color: var(--text-2);
  border-radius: 999px; padding: 0 13px; height: 34px; cursor: pointer;
  font: 500 12px/1 var(--body); display: inline-flex; align-items: center; gap: 7px;
}
.chip:hover { border-color: var(--line-firm); color: var(--text); }
.chip.on { border-color: var(--signal-ink); color: var(--text); background: var(--signal-wash); }
.chip .c-n { font: 400 11px/1 var(--mono); color: var(--text-3); }
.s-proj { font: 400 10.5px/1.5 var(--mono); color: var(--text-3); letter-spacing: .04em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.s-body > .s-proj { padding-left: 16px; margin-top: 3px; }

/* ═══════════════════════════ project detail ═══════════════════════════ */

.pdetail { display: grid; gap: 18px; }

.back {
  background: none; border: 0; color: var(--text-3); cursor: pointer; padding: 6px 0;
  font: 400 12.5px/1 var(--body); display: inline-flex; align-items: center; gap: 7px;
  margin-bottom: 2px;
}
.back:hover { color: var(--text); }
.back svg { width: 13px; height: 13px; transform: rotate(180deg); }

.phead {
  position: relative; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--r-xl); background: var(--surface);
  box-shadow: var(--lift), var(--top-hi);
}
.phead-wash { height: 76px; position: relative; border-bottom: 1px solid var(--line); }
.phead-wash::after { content: ''; position: absolute; inset: 0;
  background-image: var(--grain); background-size: 140px 140px; opacity: .045; }
.phead-body { padding: 16px 20px 16px; display: flex; align-items: flex-start; gap: 14px;
  flex-wrap: wrap; }
/* The wash is positioned, so it paints over anything static that follows it — the tile
   has to claim a layer of its own or it is sliced in half by the band it overlaps. */
.p-mono {
  position: relative; z-index: 1;
  width: 44px; height: 44px; flex: none; border-radius: 13px; display: grid;
  place-items: center; font: 800 16px/1 var(--display); letter-spacing: -.02em;
  background: var(--raised); border: 1px solid var(--line-firm); color: var(--text-2);
  margin-top: -40px; box-shadow: var(--lift);
}
.phead-t { flex: 1; min-width: 180px; }
.p-name-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.p-name { font: 800 22px/1.15 var(--display); letter-spacing: -.025em; }
.p-dom { font: 400 12px/1 var(--mono); color: var(--text-3); }
/* A blurb is prose somebody wrote, and one of them says "platform/admin/station/room/
   podium" — a 34-character run with nowhere to wrap, which a 360px column cannot hold.
   Breaking inside a word that long is better than a sentence with its end cut off, and it
   only ever applies to a word no column could fit. */
.blurb { margin-top: 8px; color: var(--text-2); font-size: 13.5px; max-width: 74ch;
  overflow-wrap: break-word; }
.note {
  margin-top: 9px; background: var(--protected-bg); border: 1px solid var(--protected-ln);
  border-radius: var(--r-md); padding: 9px 12px; font-size: 12.5px;
}
.sealed-note {
  background: var(--inset); border: 1px solid var(--line-firm); border-radius: var(--r-md);
  padding: 13px 15px; font-size: 13px; color: var(--text-2); line-height: 1.6;
}

/* Four tabs do not fit one 360px line, and a tab strip you have to discover by swiping is
   a tab you can't see. On a phone they wrap; from 560px up they are one row again. */
.ptabs { display: flex; gap: 3px; flex-wrap: wrap; scrollbar-width: none;
  border-bottom: 1px solid var(--line); padding: 0 6px; }
.ptabs::-webkit-scrollbar { display: none; }
.ptab {
  background: none; border: 0; cursor: pointer; color: var(--text-3);
  padding: 12px 13px 11px; font: 500 13px/1 var(--body); white-space: nowrap;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  display: inline-flex; align-items: center; gap: 7px;
}
.ptab:hover { color: var(--text-2); }
.ptab.on { color: var(--text); border-bottom-color: var(--signal-ink); }
.ptab .n { font: 400 10.5px/1 var(--mono); color: var(--text-3);
  background: var(--over); border-radius: 999px; padding: 3px 6px; }

.pcols { display: grid; gap: 18px; margin-top: 22px; }

.side { display: grid; gap: 12px; align-content: start; }
.card {
  background: var(--raised); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 15px 16px; box-shadow: var(--top-hi);
}
.card h3 { font: 500 9.5px/1 var(--mono); letter-spacing: .17em; text-transform: uppercase;
  color: var(--text-3); margin-bottom: 12px; }
.kv { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 9px 14px;
  align-items: baseline; }
.kv dt { font-size: 12.5px; color: var(--text-3); overflow-wrap: anywhere; }
.kv dd { font: 400 12.5px/1.4 var(--mono); color: var(--text-2); text-align: right;
  overflow-wrap: anywhere; }
.kv dd .badge { font-size: 9.5px; }

.acts { display: grid; gap: 7px; }
.act {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: var(--inset); border: 1px solid var(--line); color: var(--text-2);
  border-radius: var(--r-md); padding: 0 13px; height: 42px; cursor: pointer;
  font: 500 12.5px/1 var(--body);
}
.act svg { width: 15px; height: 15px; flex: none; color: var(--text-3); }
.act:hover { border-color: var(--line-firm); color: var(--text); background: #151B22; }
.act[disabled] { opacity: .5; cursor: default; }

/* ═══════════════════════════ logs ═══════════════════════════ */

.logs { border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
  background: var(--line); display: grid; gap: 1px; }
.log { background: var(--raised); }
.log > summary {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px; cursor: pointer;
  list-style: none; min-height: 52px;
}
.log > summary::-webkit-details-marker { display: none; }
.log > summary:hover { background: rgba(var(--ink),.025); }
.log-date { font: 400 11px/1 var(--mono); color: var(--text-3); white-space: nowrap;
  flex: none; width: 48px; }
.log-t { flex: 1; min-width: 0; }
.log-title { font-size: 13.5px; line-height: 1.4; overflow-wrap: anywhere; }
.log-out { font-size: 12px; color: var(--text-3); margin-top: 3px; line-height: 1.5;
  overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; }
.log-flag { font: 500 9.5px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--protected); border: 1px solid var(--protected-ln); border-radius: 999px;
  padding: 4px 7px; flex: none; }
.log-body { padding: 0 14px 14px; }
.log-pre {
  font: 400 11.5px/1.65 var(--mono); color: var(--text-2); white-space: pre-wrap;
  overflow-wrap: anywhere; background: var(--inset); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 13px 14px; max-height: 460px; overflow-y: auto;
}
.log-meta { margin-top: 8px; font: 400 10.5px/1.5 var(--mono); color: var(--text-3); }

.sub { background: var(--raised); border: 1px solid var(--line);
  border-radius: var(--r-lg); margin-top: 12px; }
.sub > summary { cursor: pointer; padding: 13px 15px; font-size: 13px; color: var(--text-2);
  list-style: none; display: flex; align-items: center; gap: 8px; }
.sub > summary::-webkit-details-marker { display: none; }
.changes { list-style: none; padding: 0 15px 14px; display: grid; gap: 6px; }
.changes li { display: flex; align-items: center; gap: 9px; font: 400 11.5px/1.5 var(--mono); }
.ch-path { flex: 1; min-width: 0; color: var(--text-2); overflow-wrap: anywhere; }
.ch-at { color: var(--text-3); white-space: nowrap; }
.ch-state { font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-3); white-space: nowrap; }
.ch-state.live { color: var(--live); }
.ch-state.protected { color: var(--protected); }
.ch-state.error { color: var(--error); }
.ch-state.down { color: var(--down); }

.act-src { margin-top: 10px; font: 400 10.5px/1.6 var(--mono); color: var(--text-3); }
.act-loading, .empty { color: var(--text-3); font-size: 13px; padding: 16px 2px; }

/* ═══════════════════════════ tasks ═══════════════════════════
 *
 * The delegated work. Rows are the logs vocabulary above — same list, same viewer — with
 * two additions, and both of them obey the rules at the top of this file:
 *
 * 1. An agent chip is an **identity, never a reading**, so the four tints are deliberately
 *    off the health palette: blue, violet, cyan and rose, with no green, amber or coral
 *    among them. The outcome sits beside it as a real `.badge`, hue *and* word.
 * 2. The pulse on a running row is the only motion here and it says exactly one thing —
 *    this is still going. It borrows the ticker's heartbeat, down to the keyframes: that
 *    is the one job Signal already has (liveness, not health), and a running task is not
 *    one of the four states. The reduced-motion rule at the foot of this file stops it.
 */
.ag {
  font: 500 10px/1 var(--mono); letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-3); background: var(--over); border: 1px solid var(--line);
  border-radius: 999px; padding: 5px 0; flex: none; width: 54px; text-align: center;
}
.ag-wren { color: rgb(var(--ag-wren)); background: rgba(var(--ag-wren),.12);
  border-color: rgba(var(--ag-wren),.30); }
.ag-juno { color: rgb(var(--ag-juno)); background: rgba(var(--ag-juno),.12);
  border-color: rgba(var(--ag-juno),.30); }
.ag-iris { color: rgb(var(--ag-iris)); background: rgba(var(--ag-iris),.12);
  border-color: rgba(var(--ag-iris),.30); }
.ag-ada  { color: rgb(var(--ag-ada));  background: rgba(var(--ag-ada),.12);
  border-color: rgba(var(--ag-ada),.30); }

.task > summary { gap: 11px; }
.tsk-meta { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-top: 4px;
  font: 400 11px/1.5 var(--mono); color: var(--text-3); }
.tsk-el { color: var(--text-2); font-variant-numeric: tabular-nums; }
.tsk-runs { border: 1px solid var(--line); border-radius: 999px; padding: 2px 7px; }
.tsk-dot { display: grid; place-items: center; width: 7px; height: 7px; flex: none; }
.tsk-dot i {
  width: 7px; height: 7px; border-radius: 50%; background: var(--signal-ink);
  animation: tkbeat 2.4s ease-in-out infinite;
}

/* ═══════════════════════════ requests ═══════════════════════════
 *
 * The only cards on this dashboard with a decision on them, so the only ones that move
 * when you touch them. The flip is one rotation of one element: the two faces are the
 * same box at the same place, back-face hidden, and the turn is .42s on a weighted curve
 * — far enough to read as a physical card turning over, short enough that a yes is still
 * two taps. The reduced-motion rule at the foot of this file collapses it to an instant
 * swap, which is the right answer there and loses nothing.
 *
 * Green on Approve and red on Deny look like the health palette and are deliberately the
 * same two hues: here they are not a reading of anything, they are the two answers, and
 * both carry their word. Nothing else on the page is a question, so there is nothing for
 * them to be confused with.
 *
 * The front sits in flow and so decides how tall the card is — a long detail makes a
 * taller card rather than a scrolling one — and the back is absolute on top of it, which
 * is what keeps the two faces exactly the same size whatever the text does.
 */
.flips { display: grid; gap: 12px; }

/* Both grids, so a short card still fills the row its neighbour made tall — and the
   front, which is the face that sizes the card, is the thing being stretched. */
.flip { perspective: 1200px; display: grid; }
.flip-in {
  position: relative; display: grid; transform-style: preserve-3d;
  transition: transform .42s cubic-bezier(.4,.05,.2,1);
}
.flip.on .flip-in { transform: rotateY(180deg); }
.flip-face {
  position: relative; width: 100%; padding: 15px 16px; color: var(--text);
  background: var(--raised); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--top-hi); text-align: left;
  backface-visibility: hidden; -webkit-backface-visibility: hidden;
}
.flip-front {
  display: flex; flex-direction: column; gap: 8px; min-height: 146px;
  cursor: pointer; font: inherit;
  transition: border-color .15s, box-shadow .15s;
}
.flip-front:hover { border-color: var(--line-firm); box-shadow: var(--lift), var(--top-hi); }
.flip-back {
  position: absolute; inset: 0; transform: rotateY(180deg);
  display: flex; flex-direction: column; justify-content: center; gap: 11px;
}
/* The face turned away takes no clicks; requestCard() takes it out of the tab order. */
.flip:not(.on) .flip-back, .flip.on .flip-front { pointer-events: none; }
/* Decided: out, and then the list redraws with it under Decided. */
.flip.gone { transition: opacity .34s, transform .34s; opacity: 0;
  transform: translateY(-8px) scale(.97); }

.rq-head { display: flex; align-items: center; gap: 9px; }
.rq-tag { font: 500 9px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase;
  color: var(--signal-ink); background: var(--signal-wash); border-radius: 999px;
  padding: 4px 8px; }
.rq-when { font: 400 10.5px/1 var(--mono); color: var(--text-3); }
.rq-t { display: block; font: 600 14.5px/1.4 var(--body); overflow-wrap: anywhere; }
.rq-d { display: block; font: 400 12.5px/1.6 var(--body); color: var(--text-2);
  overflow-wrap: anywhere; }
.rq-hint { margin-top: auto; display: flex; align-items: center; gap: 6px;
  font: 500 10px/1 var(--mono); letter-spacing: .13em; text-transform: uppercase;
  color: var(--text-3); }
.flip-front:hover .rq-hint { color: var(--signal-ink); }
.rq-hint .chev { width: 13px; height: 13px; transition: transform .15s; }
.flip-front:hover .rq-hint .chev { transform: translateX(2px); }

.rq-b-t { font: 400 11.5px/1.5 var(--mono); color: var(--text-3); overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; }
.rq-acts { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.rq-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 44px; border-radius: var(--r-md); cursor: pointer;
  font: 600 13.5px/1 var(--body); border: 1px solid transparent;
  transition: border-color .15s;
}
.rq-btn svg { width: 15px; height: 15px; }
.rq-btn:hover { border-color: currentColor; }
.rq-btn:disabled { opacity: .55; cursor: default; }
.rq-yes { background: var(--live-bg); border-color: var(--live-ln); color: var(--live); }
.rq-no { background: var(--down-bg); border-color: var(--down-ln); color: var(--down); }
.rq-keep {
  align-self: center; background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--text-3); font: 400 11.5px/1.4 var(--body);
  border-bottom: 1px dashed var(--line-firm);
}
.rq-keep:hover { color: var(--text); }
/* No `display` of its own: it is a flex item, so it blockifies anyway, and declaring one
   here would outrank the UA's `[hidden] { display: none }` and leave the empty line in. */
.rq-err { font: 400 11.5px/1.5 var(--body); color: var(--down); overflow-wrap: anywhere; }

.decs { border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
  background: var(--line); display: grid; gap: 1px; }
.dec { background: var(--raised); display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; }
.dec-t { flex: 1; min-width: 0; font-size: 13px; overflow-wrap: anywhere; }
.dec-at { font: 400 11px/1 var(--mono); color: var(--text-3); white-space: nowrap; }

/* ═══════════════════════════ suggestions ═══════════════════════════ */

.sugs { list-style: none; display: grid; gap: 10px; }
.sug {
  background: var(--raised); border: 1px solid var(--line); border-left: 2px solid var(--idle);
  border-radius: var(--r-lg); padding: 14px 16px; box-shadow: var(--top-hi);
}
.sug.sev-critical, .sug.sev-high { border-left-color: var(--error); }
.sug.sev-medium { border-left-color: var(--protected); }
.sug.sev-low { border-left-color: var(--idle); }
.sug-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.sug-sev { font: 500 9.5px/1 var(--mono); letter-spacing: .13em; text-transform: uppercase;
  color: var(--text-3); flex: none; }
.sug.sev-critical .sug-sev, .sug.sev-high .sug-sev { color: var(--error); }
.sug.sev-medium .sug-sev { color: var(--protected); }
.sug-t { font: 600 14px/1.4 var(--body); flex: 1; min-width: 0; overflow-wrap: anywhere; }
.sug-p { font: 400 10.5px/1 var(--mono); color: var(--text-3); }
.sug-d { margin-top: 7px; font-size: 13px; color: var(--text-2); line-height: 1.6;
  max-width: 80ch; overflow-wrap: anywhere; }
.sug-d code { font: 400 12px/1 var(--mono); }
.sug-b { margin-top: 10px; font: 400 11px/1.5 var(--mono); color: var(--text-3);
  display: flex; gap: 9px; }
.sug-b-k { letter-spacing: .15em; text-transform: uppercase; font-size: 9.5px; flex: none;
  padding-top: 2px; }

/* ═══════════════════════════ plain pages ═══════════════════════════ */

.prose { max-width: 74ch; }
.prose p { color: var(--text-2); font-size: 13.5px; line-height: 1.7; margin-bottom: 12px;
  overflow-wrap: anywhere; }
.prose p strong { color: var(--text); font-weight: 600; }
.prose code { font: 400 12.5px/1 var(--mono); color: var(--text-2);
  background: rgba(var(--ink),.05); border-radius: 4px; padding: 2px 5px; }

button.ghost {
  background: var(--raised); border: 1px solid var(--line-firm); color: var(--text-2);
  border-radius: 10px; height: 38px; padding: 0 14px;
  font: 500 12.5px/1 var(--body); cursor: pointer; white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  transition: border-color .15s, color .15s, background .15s;
}
button.ghost:hover { border-color: var(--text-3); color: var(--text); background: var(--raised-hi); }
button.ghost.wide { width: 100%; }

button.primary {
  background: var(--signal); color: var(--on-signal); border: none; border-radius: var(--r-md);
  height: 46px; padding: 0 20px; font: 700 15px/1 var(--display); cursor: pointer;
  width: 100%;
}
button.primary:disabled { opacity: .6; cursor: default; }

/* ═══════════════════════════ the login page ═══════════════════════════ */
/* login.html loads this same stylesheet before a session exists, which is why the three
   faces are served publicly. It is the only other page there is. */
.auth-wrap { min-height: 100vh; display: grid; place-items: center; padding: 24px; }
.auth {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-xl);
  padding: 34px 28px; width: 100%; max-width: 390px; text-align: center;
  box-shadow: var(--lift), var(--top-hi);
}
.auth .mark {
  width: 56px; height: 56px; border-radius: 13px; margin: 0 auto 20px; display: block;
}
.auth h1 {
  font: 800 22px/1.2 var(--display); letter-spacing: -.025em; margin-bottom: 9px;
  font-variation-settings: 'wdth' 110;
}
.auth p { color: var(--text-2); font: 400 13.5px/1.55 var(--body); margin-bottom: 22px; }
.msg { margin-top: 15px; font: 400 12.5px/1.45 var(--mono); color: var(--text-2);
  min-height: 18px; }
.msg.err { color: var(--down); }
.msg.ok { color: var(--live); }
.hidden { display: none !important; }

/* ═══════════════════════════ the theme control ═══════════════════════════ */
/* Three states, not a toggle: System is the default and keeps following the OS, Light and
   Dark are overrides. It lives in the rail foot next to Sign out — the one piece of
   furniture that is on every screen — and `aria-pressed` carries the choice, because the
   selected segment must be readable without colour. */
.seg {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px;
  background: var(--over); border: 1px solid var(--line);
  border-radius: 11px; padding: 2px; margin-bottom: 10px;
}
.seg-i {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; min-height: 42px; padding: 5px 2px;
  background: none; border: 0; border-radius: 9px; cursor: pointer;
  color: var(--text-3); font: 500 9.5px/1 var(--body); letter-spacing: .02em;
  transition: background .14s, color .14s;
}
.seg-i svg { width: 15px; height: 15px; }
.seg-i:hover { color: var(--text); }
.seg-i[aria-pressed="true"] {
  /* a ring, not a border — a border here would resize the segment and shift the row */
  background: var(--raised); color: var(--text);
  box-shadow: var(--top-hi), var(--lift), 0 0 0 1px var(--line);
}
.seg-i[aria-pressed="true"] svg { color: var(--signal-ink); }
.seg-k { font: 500 9px/1 var(--mono); letter-spacing: .15em; text-transform: uppercase;
  color: var(--text-3); margin-bottom: 7px; display: block; }

/* ═══════════════════════════ Linode — the host ═══════════════════════════ */
/* The one panel on this dashboard whose job is reassurance rather than triage: the host is
   either fine, in which case the page should say so in one glance and get out of the way,
   or it is not, in which case the same furniture turns amber or red. So the hierarchy is
   deliberately steep — one hero verdict, then three readings, then the specs, then
   everything else folded away.
   The hero's light source is the only decoration on this page allowed a hue, and it is
   driven by the same state class as the word beside it, so it cannot disagree with it. */

.lx { display: grid; gap: 12px; }

.lx-hero {
  position: relative; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--r-xl);
  background: var(--surface); box-shadow: var(--lift), var(--top-hi);
  padding: 20px 18px;
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
}
.lx-hero::before {
  content: ''; position: absolute; inset: -60% -10% auto -10%; height: 240%;
  background: radial-gradient(52% 62% at 16% 12%, var(--lx-glow), transparent 70%);
  pointer-events: none;
}
.lx-hero::after {
  content: ''; position: absolute; inset: 0; background-image: var(--grain);
  background-size: 140px 140px; opacity: var(--grain-op); pointer-events: none;
}
.lx { --lx-glow: rgba(120,131,143,.10); }
.lx.ok   { --lx-glow: var(--live-bg); }
.lx.warn { --lx-glow: var(--protected-bg); }
.lx.bad  { --lx-glow: var(--down-bg); }

.lx-beacon {
  position: relative; width: 54px; height: 54px; flex: none; border-radius: 50%;
  border: 2px solid var(--idle-ln); display: grid; place-items: center;
}
.lx-beacon i { width: 15px; height: 15px; border-radius: 50%; background: var(--idle); }
.lx.ok .lx-beacon { border-color: var(--live-ln); }
.lx.ok .lx-beacon i { background: var(--live); box-shadow: 0 0 16px var(--live-glow); }
.lx.warn .lx-beacon { border-color: var(--protected-ln); }
.lx.warn .lx-beacon i { background: var(--protected); }
.lx.bad .lx-beacon { border-color: var(--down-ln); }
.lx.bad .lx-beacon i { background: var(--down); box-shadow: 0 0 16px var(--down-glow); }
/* One piece of motion on the page, and it is the only thing here that is genuinely live:
   a slow ring leaving the beacon while the host is up. It stops the moment it isn't, and
   `prefers-reduced-motion` switches it off entirely. */
.lx.ok .lx-beacon::after {
  content: ''; position: absolute; inset: -2px; border-radius: 50%;
  border: 2px solid var(--live); opacity: 0;
  animation: lx-ping 3s cubic-bezier(.22,.6,.3,1) infinite;
}
@keyframes lx-ping {
  0%   { transform: scale(1);    opacity: .5; }
  70%  { transform: scale(1.52); opacity: 0; }
  100% { transform: scale(1.52); opacity: 0; }
}

.lx-hero > * { position: relative; }
.lx-id { min-width: 0; }
.lx-eyebrow {
  font: 500 9.5px/1 var(--mono); letter-spacing: .17em; text-transform: uppercase;
  color: var(--text-3);
}
.lx-verdict {
  font: 800 32px/1.04 var(--display); letter-spacing: -.028em; margin: 9px 0 7px;
  font-variation-settings: 'wdth' 108; text-transform: capitalize;
}
.lx.ok .lx-verdict   { color: var(--live); }
.lx.warn .lx-verdict { color: var(--protected); }
.lx.bad .lx-verdict  { color: var(--down); }
.lx-who { color: var(--text-2); font-size: 13px; }
.lx-who b { font-weight: 600; color: var(--text); }
.lx-where { display: inline-flex; align-items: center; gap: 6px; margin-top: 7px;
  font: 400 11.5px/1 var(--mono); color: var(--text-3); }
.lx-where svg { width: 14px; height: 14px; flex: none; }

.lx-pips { position: relative; display: flex; flex-wrap: wrap; gap: 8px; margin-left: auto; }
.lx-pip {
  display: inline-flex; align-items: center; gap: 7px; flex: none;
  min-height: 34px; padding: 7px 13px 7px 11px; border-radius: 999px;
  border: 1px solid var(--idle-ln); background: var(--idle-bg); color: var(--text-2);
  font: 500 11.5px/1 var(--body);
}
.lx-pip svg { width: 15px; height: 15px; flex: none; }
.lx-pip.ok   { border-color: var(--live-ln); background: var(--live-bg); color: var(--live); }
.lx-pip.warn { border-color: var(--protected-ln); background: var(--protected-bg);
  color: var(--protected); }
.lx-pip.bad  { border-color: var(--down-ln); background: var(--down-bg); color: var(--down); }

/* ── the three readings ── */
.lx-row { display: grid; gap: 12px; grid-template-columns: 1fr; }
.lx-card {
  background: var(--raised); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 15px 16px 16px; box-shadow: var(--top-hi); min-width: 0;
}
.lx-k {
  display: flex; align-items: center; gap: 8px;
  font: 500 9.5px/1 var(--mono); letter-spacing: .17em; text-transform: uppercase;
  color: var(--text-3);
}
.lx-tag {
  font: 500 9px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-3); border: 1px solid var(--line); border-radius: 999px;
  padding: 3px 7px; flex: none;
}
.lx-s { font: 400 11px/1.55 var(--mono); color: var(--text-3); }

/* transfer, as a ring. The arc is what has been spent; the empty three hundred and fifty
   degrees is the point of the drawing. */
.lx-tr-body { display: flex; align-items: center; gap: 18px; margin-top: 14px;
  flex-wrap: wrap; }
.lx-ring { width: 104px; height: 104px; flex: none; }
.lx-ring .trk { stroke: rgba(var(--ink),.09); }
.lx-ring .arc { stroke: var(--live); transition: stroke-dashoffset .9s cubic-bezier(.3,.8,.4,1); }
.lx-ring.warn .arc { stroke: var(--protected); }
.lx-ring.bad .arc { stroke: var(--down); }
.lx-ring .n {
  font: 700 21px/1 var(--display); letter-spacing: -.02em; fill: var(--text);
  font-variant-numeric: tabular-nums;
}
.lx-ring .u {
  font: 500 8.5px/1 var(--mono); letter-spacing: .18em; fill: var(--text-3);
  text-transform: uppercase;
}
.lx-tr-text { min-width: 0; }
.lx-n { font: 700 24px/1.1 var(--display); letter-spacing: -.022em;
  font-variant-numeric: tabular-nums; }
.lx-n small { font: 400 12px/1 var(--mono); color: var(--text-3); letter-spacing: 0;
  margin-left: 6px; }
.lx-free svg { width: 13px; height: 13px; flex: none; }
.lx-free {
  display: inline-flex; align-items: center; gap: 6px; margin: 10px 0 8px;
  font: 500 11.5px/1 var(--body); color: var(--live);
  background: var(--live-bg); border: 1px solid var(--live-ln);
  border-radius: 999px; padding: 6px 11px;
}

/* backups: a protected state, not a percentage */
.lx-shield { display: flex; align-items: center; gap: 13px; margin: 14px 0 12px; }
.lx-shield svg { width: 34px; height: 34px; flex: none; color: var(--live); }
.lx-bk.warn .lx-shield svg, .lx-bk.warn .lx-state { color: var(--protected); }
.lx-bk.bad .lx-shield svg, .lx-bk.bad .lx-state { color: var(--down); }
.lx-state { font: 700 22px/1.1 var(--display); letter-spacing: -.02em; color: var(--live); }
.lx-when { font: 400 11.5px/1.4 var(--body); color: var(--text-2); margin-top: 4px; }

/* CPU, as a bullet against this plan's real ceiling. Linode sums the vCPUs, so the scale
   runs to 400% here and the ticks are the vCPUs — a peak over 100% is not an error and
   the axis says so out loud rather than being quietly rescaled. */
.lx-bullet { margin: 16px 0 10px; }
.lx-track {
  position: relative; height: 12px; border-radius: 6px;
  background: rgba(var(--ink),.07); overflow: hidden;
}
.lx-fill { position: absolute; inset: 0 auto 0 0; border-radius: 6px; background: var(--live);
  transition: width .9s cubic-bezier(.3,.8,.4,1); }
.lx-fill.warn { background: var(--protected); }
.lx-fill.bad { background: var(--down); }
.lx-tick { position: absolute; top: 0; bottom: 0; width: 1px;
  background: rgba(var(--ink),.22); }
.lx-peak {
  position: absolute; top: -3px; bottom: -3px; width: 2px; border-radius: 2px;
  background: var(--text); transform: translateX(-1px);
}
.lx-axis {
  display: flex; justify-content: space-between; margin-top: 7px;
  font: 400 9.5px/1 var(--mono); color: var(--text-3);
}
.lx-legend { display: flex; flex-wrap: wrap; gap: 14px; margin: 11px 0 9px;
  font: 400 11.5px/1 var(--body); color: var(--text-2); }
.lx-legend span { display: inline-flex; align-items: center; gap: 7px; }
.lx-swatch { display: inline-block; width: 10px; height: 10px; border-radius: 3px;
  background: var(--live); flex: none; }
.lx-swatch.warn { background: var(--protected); }
.lx-swatch.bad { background: var(--down); }
.lx-swatch.peak { width: 3px; height: 13px; border-radius: 2px; background: var(--text); }

/* the spec strip — four facts, scannable, not a table */
.lx-specs {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px;
  background: var(--line); border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden;
}
.lx-spec {
  background: var(--raised); padding: 14px 15px; display: flex; align-items: center;
  gap: 11px; min-width: 0;
}
.lx-spec svg { width: 19px; height: 19px; flex: none; color: var(--text-3); }
.lx-spec-v { font: 700 16px/1.1 var(--display); letter-spacing: -.015em;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.lx-spec-k { font: 500 9px/1 var(--mono); letter-spacing: .15em; text-transform: uppercase;
  color: var(--text-3); margin-top: 5px; }

/* ── Clood's Claude login: one card, one date ──
   Borrows .lx-card, .lx-k, .lx-tag, .lx-when and .lx-s wholesale — it is the same kind of
   reading as the backups card and has no business looking different. The only new thing
   is the countdown, which takes the health hues the rest of the page already uses so that
   green/amber/red mean here exactly what they mean three cards up. Signal yellow stays
   out of it, same rule as everywhere. */
.cl-body { display: flex; align-items: center; gap: 13px; margin: 14px 0 12px; }
.cl-body > svg { width: 30px; height: 30px; flex: none; color: var(--live); }
.cl-big { font: 700 22px/1.15 var(--display); letter-spacing: -.02em; color: var(--live);
  font-variant-numeric: tabular-nums; }
.cl.warn .cl-body > svg, .cl.warn .cl-big { color: var(--protected); }
.cl.bad .cl-body > svg, .cl.bad .cl-big { color: var(--down); }

.lx-more { border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--raised); box-shadow: var(--top-hi); }
.lx-more > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: 10px;
  padding: 13px 15px; font: 500 12.5px/1 var(--body); color: var(--text-2);
}
.lx-more > summary::-webkit-details-marker { display: none; }
.lx-more > summary:hover { color: var(--text); }
.lx-more > summary .chev { margin-left: auto; }
.lx-more .kv { padding: 2px 15px 15px; }

/* ── the one line Home gets ── */
.hostline {
  display: flex; align-items: center; gap: 10px 16px; flex-wrap: wrap; width: 100%;
  text-align: left; cursor: pointer;
  background: var(--raised); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--top-hi); color: var(--text); padding: 13px 15px; margin-top: 12px;
  transition: border-color .15s, background .15s;
}
.hostline:hover { border-color: var(--line-firm); background: var(--raised-hi); }
.hostline .hl-t { font: 600 13px/1 var(--body); display: inline-flex; align-items: center;
  gap: 9px; flex: none; }
.hostline .hl-i { display: inline-flex; align-items: center; gap: 7px;
  font: 400 11.5px/1 var(--mono); color: var(--text-3); min-width: 0; }
.hostline .hl-i svg { width: 14px; height: 14px; flex: none; color: var(--text-3); }
.hostline .chev { margin-left: auto; flex: none; }

/* ═══════════════════════════ wider screens ═══════════════════════════ */

@media (min-width: 560px) {
  :root { --pad: 24px; --tick-h: 34px; }
  .acc-wide { display: inline; }
  .ptabs { flex-wrap: nowrap; overflow-x: auto; }
  .tk-open .tk-open-t { display: inline; }
  .acc-nums { display: flex; }
  .stats { grid-template-columns: repeat(4, 1fr); }
  .stat { border-bottom: 0; }
  .stat:nth-child(2n) { border-right: 1px solid var(--line); }
  .stat:last-child { border-right: 0; }
  .grid { grid-template-columns: repeat(3, 1fr); }
  .bx-grid { grid-template-columns: repeat(3, 1fr); }
  .t-n i { display: inline; }
  .hero-top { padding: 15px 16px 14px; }
  .lx-specs { grid-template-columns: repeat(4, 1fr); }
  .lx-hero { padding: 26px 24px; gap: 20px; }
  .lx-verdict { font-size: 38px; }
}

/* Transfer and backups sit side by side as soon as there is room for the ring and a
   sentence; the CPU bullet always keeps the full width, because an axis that short is
   unreadable. */
@media (min-width: 820px) {
  .lx-row { grid-template-columns: 1fr 1fr; }
  .lx-row > .lx-cpu { grid-column: 1 / -1; }
}

@media (min-width: 900px) {
  .grid { grid-template-columns: repeat(4, 1fr); }
  .fe { grid-template-columns: 72px 16px 1fr 120px; align-items: center; }
  .fe-p { grid-column: auto; margin-top: 0; text-align: right; }
  /* Two requests abreast as soon as a card is still wide enough to read a sentence in. */
  .flips { grid-template-columns: repeat(2, 1fr); }
}

/* The rail takes over from the dock. One breakpoint, one swap — the dock is never on
   screen at the same time as the rail, so there is only ever one navigation. */
@media (min-width: 1040px) {
  :root { --pad: 32px; }
  .rail { transform: none; }
  .scrim, .dock, .only-phone { display: none !important; }
  .frame { margin-left: var(--rail-w); padding-bottom: 0; }
  .search { max-width: 460px; }
  .top-title { display: none; }
}

@media (min-width: 1200px) {
  .pcols { grid-template-columns: minmax(0, 1fr) 302px; }
  .home-top { grid-template-columns: minmax(0, 1fr) 300px; }
}

/* ── motion, honoured ─────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}
