/* ═══════════════════════════════════════════════════════════════
   Spider control console — design system
   Tokens → primitives → layout → views → responsive
   ═══════════════════════════════════════════════════════════════ */

:root {
  /* surface ramp */
  --bg: #05070c;
  --bg-2: #070a11;
  --surface: rgba(13, 18, 29, 0.66);
  --surface-2: rgba(18, 24, 38, 0.72);
  --surface-3: rgba(24, 31, 47, 0.8);
  --line: rgba(234, 240, 251, 0.075);
  --line-2: rgba(234, 240, 251, 0.13);
  --line-3: rgba(234, 240, 251, 0.22);

  /* ink */
  --ink: #eaf0fb;
  --ink-2: #99a2b6;
  --ink-3: #626b81;
  --ink-4: #454c5e;

  /* brand + semantics */
  --amber: #ffb347;
  --ember: #ff6a00;
  --cyan: #5ec8ff;
  --violet: #9b7bff;
  --mint: #7cf5c8;
  --rose: #ff8fb1;
  --ok: #3ddea4;
  --warn: #f0c24b;
  --bad: #ff7a7a;

  /* node colors (shared with the 3D tour legend) */
  --n-hub: #ffb347;
  --n-w1: #6ec5ff;
  --n-w2: #9b7bff;
  --n-w3: #7cf5c8;
  --n-w4: #ff8fb1;

  --r-sm: 9px;
  --r-md: 13px;
  --r-lg: 18px;
  --r-xl: 24px;

  --rail-w: 244px;
  --bar-h: 66px;

  --sans: "Space Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

body { overflow-x: hidden; }

:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 2px;
}

h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -0.022em; text-wrap: balance; }
p { margin: 0; }
code { font-family: var(--mono); font-size: 0.85em; color: var(--ink-2); overflow-wrap: anywhere; }
a { color: inherit; }
::selection { background: rgba(255, 179, 71, 0.28); }

/* ── minimal drifting starfield (logged-in chrome) ──────────── */
.space-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  background:
    radial-gradient(ellipse 80% 50% at 18% -8%, rgba(255, 179, 71, 0.07), transparent 52%),
    radial-gradient(ellipse 55% 40% at 92% 8%, rgba(94, 200, 255, 0.05), transparent 48%),
    radial-gradient(ellipse 120% 80% at 50% -20%, #0a0e18 0%, var(--bg) 55%);
}
.space-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.03;
  background-image: 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'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
.space-nebula {
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(ellipse 40% 28% at 18% 22%, rgba(94, 200, 255, 0.045), transparent 70%),
    radial-gradient(ellipse 36% 30% at 82% 18%, rgba(255, 179, 71, 0.035), transparent 72%),
    radial-gradient(ellipse 50% 40% at 50% 100%, rgba(155, 123, 255, 0.03), transparent 70%);
  animation: nebula-drift 48s ease-in-out infinite alternate;
}
.stars {
  position: absolute;
  inset: -10%;
  background-repeat: repeat;
  opacity: 0.55;
}
.stars.layer-a {
  background-image: radial-gradient(1px 1px at 20px 30px, rgba(234, 240, 251, 0.7), transparent),
    radial-gradient(1px 1px at 80px 120px, rgba(234, 240, 251, 0.45), transparent),
    radial-gradient(1.5px 1.5px at 160px 60px, rgba(255, 179, 71, 0.4), transparent),
    radial-gradient(1px 1px at 240px 180px, rgba(234, 240, 251, 0.55), transparent),
    radial-gradient(1px 1px at 320px 40px, rgba(94, 200, 255, 0.35), transparent),
    radial-gradient(1px 1px at 400px 140px, rgba(234, 240, 251, 0.4), transparent),
    radial-gradient(1.5px 1.5px at 60px 200px, rgba(234, 240, 251, 0.5), transparent),
    radial-gradient(1px 1px at 200px 220px, rgba(234, 240, 251, 0.35), transparent);
  background-size: 440px 260px;
  animation: star-drift-a 90s linear infinite;
}
.stars.layer-b {
  opacity: 0.35;
  background-image: radial-gradient(1px 1px at 40px 70px, rgba(234, 240, 251, 0.55), transparent),
    radial-gradient(1px 1px at 140px 20px, rgba(234, 240, 251, 0.35), transparent),
    radial-gradient(1px 1px at 280px 160px, rgba(255, 179, 71, 0.28), transparent),
    radial-gradient(1.5px 1.5px at 360px 90px, rgba(234, 240, 251, 0.45), transparent),
    radial-gradient(1px 1px at 100px 180px, rgba(124, 245, 200, 0.25), transparent);
  background-size: 480px 300px;
  animation: star-drift-b 140s linear infinite reverse;
}
@keyframes star-drift-a {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-140px, -60px, 0); }
}
@keyframes star-drift-b {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(100px, 40px, 0); }
}
@keyframes nebula-drift {
  from { transform: translate3d(-1.5%, 0, 0) scale(1); opacity: 0.9; }
  to { transform: translate3d(1.5%, -1%, 0) scale(1.04); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .stars, .space-nebula { animation: none !important; }
}

/* ── shell ──────────────────────────────────────────────────── */
.shell {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
  min-height: 100vh;
}

/* ── rail ───────────────────────────────────────────────────── */
.rail {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  display: flex;
  flex-direction: column;
  padding: 1.25rem 0.9rem 1rem;
  border-right: 1px solid var(--line);
  background: rgba(8, 11, 18, 0.92);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
}

.rail-brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.2rem 0.5rem 1.25rem;
}
.mark {
  width: 28px;
  height: 28px;
  flex: none;
  border-radius: 999px;
  color: transparent;
  background: radial-gradient(circle at 40% 35%, #ffb347 0%, #ff6a00 60%, #2a1200 100%);
  box-shadow: 0 0 20px rgba(255, 179, 71, 0.4);
  filter: none;
  position: relative;
  overflow: hidden;
}
.mark svg { display: none; }
.mark::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(circle at 35% 30%, rgba(255, 255, 255, 0.35), transparent 45%);
  animation: mark-breathe 3.4s ease-in-out infinite;
}
@keyframes mark-breathe { 50% { opacity: 0.35; } }
.rail-word { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; gap: 2px; }
.rail-word b { font-size: 0.8rem; font-weight: 700; letter-spacing: 0.26em; }
.rail-word em {
  font-style: normal;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.rail-nav { display: flex; flex-direction: column; gap: 0.12rem; overflow-y: auto; flex: 1; margin: 0 -0.85rem; padding: 0 0.85rem; scrollbar-width: none; }
.rail-nav::-webkit-scrollbar { width: 0; }

.rail-label {
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding: 1.05rem 0.65rem 0.4rem;
}
.rail-label:first-child { padding-top: 0.15rem; }

.nav-item,
.rail-out {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.56rem 0.65rem;
  border-radius: var(--r-sm);
  color: var(--ink-2);
  text-decoration: none;
  font-size: 0.885rem;
  font-weight: 500;
  transition: color 0.16s var(--ease), background 0.16s var(--ease);
}
.nav-item::before { display: none; }
.nav-item:hover { color: var(--ink); background: rgba(234, 240, 251, 0.04); }
.nav-item.active {
  color: var(--ink);
  background: rgba(255, 179, 71, 0.12);
  border: 1px solid rgba(255, 179, 71, 0.22);
  padding: calc(0.56rem - 1px) calc(0.65rem - 1px);
}
.nav-item.active .nav-count { color: var(--amber); }
.nav-item.active::before { display: none; }

.ico {
  width: 17px;
  height: 17px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.55;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.85;
}
.nav-item[data-nav="overview"] .ico,
#map-legend .ico { fill: currentColor; stroke: none; }
.nav-item.active .ico { opacity: 1; color: var(--amber); }

.nav-count {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 0.65rem;
  font-style: normal;
  color: var(--ink-4);
  font-variant-numeric: tabular-nums;
}
.nav-count.bad { color: var(--bad); }
.nav-count.ok { color: var(--ok); }
.nav-count[data-empty="1"] { opacity: 0; }

.rail-foot { display: flex; flex-direction: column; gap: 0.55rem; padding-top: 0.85rem; border-top: 1px solid var(--line); flex: none; }

.bar-health {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgba(234, 240, 251, 0.03);
  max-width: 22ch;
}
.bar-health .rh-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.bar-health .rh-text b { font-size: 0.72rem; font-weight: 600; white-space: nowrap; }
.bar-health .rh-text em {
  font-style: normal;
  font-family: var(--mono);
  font-size: 0.55rem;
  color: var(--ink-4);
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rail-out { font-size: 0.8rem; }
.rail-out:hover { color: var(--ink); background: rgba(234, 240, 251, 0.045); }

/* ── main column ────────────────────────────────────────────── */
.main { min-width: 0; display: flex; flex-direction: column; }

.bar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: var(--bar-h);
  padding: 0.85rem 1.6rem;
  border-bottom: 1px solid var(--line);
  background: rgba(6, 9, 15, 0.62);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}
.rail-toggle {
  display: none;
  width: 34px;
  height: 34px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: rgba(234, 240, 251, 0.03);
  color: var(--ink-2);
  cursor: pointer;
  place-items: center;
}
.rail-toggle svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; }

/* Desktop: scrim never paints. Mobile rules flip it on with body.rail-open. */
.rail-scrim { display: none; }

.bar-title { min-width: 0; flex: 1; }
.bar-title h1 { font-size: 1.06rem; line-height: 1.2; }
.bar-title p {
  font-family: var(--mono);
  font-size: 0.655rem;
  color: var(--ink-4);
  letter-spacing: 0.09em;
  margin-top: 0.15rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.bar-actions { display: flex; align-items: center; gap: 0.55rem; }

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}
.pill.live { color: var(--ok); border-color: rgba(61, 222, 164, 0.28); background: rgba(61, 222, 164, 0.08); }
.pill[hidden] { display: none; }
.pill[data-state="stale"] { color: var(--warn); border-color: rgba(240, 194, 75, 0.32); background: rgba(240, 194, 75, 0.08); }
.pill[data-state="err"] { color: var(--bad); border-color: rgba(255, 122, 122, 0.32); background: rgba(255, 122, 122, 0.08); }
#demo-pill { color: var(--violet); border-color: rgba(155, 123, 255, 0.35); background: rgba(155, 123, 255, 0.08); }

.clock {
  font-family: var(--mono);
  font-size: 0.68rem;
  color: var(--ink-4);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  background: rgba(234, 240, 251, 0.03);
  color: var(--ink-2);
  text-decoration: none;
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.16s, border-color 0.16s, background 0.16s, transform 0.16s;
}
.btn:hover { color: var(--ink); border-color: rgba(255, 179, 71, 0.4); background: rgba(255, 179, 71, 0.07); transform: translateY(-1px); }
.btn.sm { padding: 0.34rem 0.62rem; font-size: 0.74rem; }
.btn .ico { width: 14px; height: 14px; }

/* ── view switching ─────────────────────────────────────────── */
.views { position: relative; }
.view {
  display: none;
  max-width: 1440px;
  margin: 0 auto;
  padding: 1.6rem 1.6rem 3rem;
  animation: view-in 0.32s var(--ease) both;
}
.view.on { display: block; }
.view-tour { max-width: none; }
@keyframes view-in { from { opacity: 0; transform: translateY(7px); } }

.section-lead { max-width: 60ch; margin-bottom: 1.5rem; }
.section-lead h2 { font-size: 1.5rem; margin-bottom: 0.35rem; }
.section-lead p { color: var(--ink-2); font-size: 0.92rem; line-height: 1.55; }

/* ── verdict banner ─────────────────────────────────────────── */
.verdict {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  padding: 1.1rem 1.25rem;
  margin-bottom: 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background:
    linear-gradient(100deg, rgba(255, 179, 71, 0.07), transparent 42%),
    var(--surface);
  position: relative;
  overflow: hidden;
}
.verdict::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 2px;
  background: linear-gradient(180deg, var(--amber), transparent);
}
.verdict[data-state="bad"] { background: linear-gradient(100deg, rgba(255, 122, 122, 0.08), transparent 42%), var(--surface); }
.verdict[data-state="bad"]::after { background: linear-gradient(180deg, var(--bad), transparent); }
.verdict[data-state="warn"] { background: linear-gradient(100deg, rgba(240, 194, 75, 0.07), transparent 42%), var(--surface); }
.verdict[data-state="warn"]::after { background: linear-gradient(180deg, var(--warn), transparent); }
.verdict-main { display: flex; align-items: center; gap: 0.95rem; min-width: 0; }
.verdict-dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  flex: none;
  background: var(--ink-3);
  box-shadow: 0 0 0 5px rgba(98, 107, 129, 0.12);
}
.verdict[data-state="ok"] .verdict-dot { background: var(--ok); box-shadow: 0 0 0 5px rgba(61, 222, 164, 0.14); animation: beat 2.4s ease-in-out infinite; }
.verdict[data-state="warn"] .verdict-dot { background: var(--warn); box-shadow: 0 0 0 5px rgba(240, 194, 75, 0.14); }
.verdict[data-state="bad"] .verdict-dot { background: var(--bad); box-shadow: 0 0 0 5px rgba(255, 122, 122, 0.14); }
@keyframes beat { 50% { box-shadow: 0 0 0 11px rgba(61, 222, 164, 0.02); } }
.verdict h2 { font-size: 1.12rem; margin-bottom: 0.2rem; }
.verdict p { color: var(--ink-2); font-size: 0.875rem; line-height: 1.45; }
.verdict-meta { display: flex; gap: 1.4rem; flex-wrap: wrap; }
.vm-item { text-align: right; }
.vm-item b { display: block; font-size: 1.18rem; font-weight: 650; font-variant-numeric: tabular-nums; line-height: 1.2; }
.vm-item em {
  font-style: normal;
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-4);
}

/* ── KPI tiles ──────────────────────────────────────────────── */
.kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(178px, 1fr));
  gap: 0.7rem;
  margin-bottom: 1.1rem;
}
.kpi {
  position: relative;
  padding: 0.85rem 0.95rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
  transition: border-color 0.18s, transform 0.18s var(--ease), background 0.18s;
  animation: rise 0.45s var(--ease) both;
}
.kpi:hover { border-color: var(--line-2); transform: translateY(-2px); background: var(--surface-2); }
.kpi::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--kpi-tint, var(--amber)), transparent);
  opacity: 0.5;
}
@keyframes rise { from { opacity: 0; transform: translateY(9px); } }
.kpi-label {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 0.45rem;
}
.kpi-label .ico { width: 13px; height: 13px; }
.kpi-value {
  font-size: 1.55rem;
  font-weight: 650;
  line-height: 1.05;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  display: flex;
  align-items: baseline;
  gap: 0.28rem;
}
.kpi-value small { font-size: 0.78rem; font-weight: 500; color: var(--ink-3); letter-spacing: 0; }
.kpi-sub { margin-top: 0.3rem; font-size: 0.74rem; color: var(--ink-3); }
.kpi-meter { margin-top: 0.6rem; height: 3px; border-radius: 2px; background: rgba(234, 240, 251, 0.07); overflow: hidden; }
.kpi-meter i { display: block; height: 100%; border-radius: 2px; transition: width 0.6s var(--ease); }
.kpi[data-tone="ok"] { --kpi-tint: var(--ok); }
.kpi[data-tone="ok"] .kpi-value { color: var(--ok); }
.kpi[data-tone="warn"] { --kpi-tint: var(--warn); }
.kpi[data-tone="warn"] .kpi-value { color: var(--warn); }
.kpi[data-tone="bad"] { --kpi-tint: var(--bad); }
.kpi[data-tone="bad"] .kpi-value { color: var(--bad); }
.kpi[data-tone="amber"] { --kpi-tint: var(--amber); }
.kpi[data-tone="amber"] .kpi-value { color: var(--amber); }
.kpi[data-tone="cyan"] { --kpi-tint: var(--cyan); }
.kpi[data-tone="cyan"] .kpi-value { color: var(--cyan); }
.kpi[data-tone="plain"] .kpi-value { color: var(--ink); }

/* First-paint placeholder — replaced by buildKpis() on the first /api/status. */
.kpi.skeleton { pointer-events: none; }
.kpi.skeleton .kpi-meter i { width: 0 !important; }
.sk-line {
  border-radius: 4px;
  background: linear-gradient(
    90deg,
    rgba(234, 240, 251, 0.05) 0%,
    rgba(234, 240, 251, 0.11) 50%,
    rgba(234, 240, 251, 0.05) 100%
  );
  background-size: 200% 100%;
  animation: sk-shimmer 1.6s var(--ease) infinite;
}
.sk-line.sm { width: 45%; height: 9px; margin-bottom: 0.75rem; }
.sk-line.lg { width: 62%; height: 22px; margin-bottom: 0.55rem; }
.sk-line.md { width: 78%; height: 9px; }
@keyframes sk-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ── panels ─────────────────────────────────────────────────── */
.grid-2 {
  display: grid;
  grid-template-columns: minmax(0, 1.42fr) minmax(0, 1fr);
  gap: 0.85rem;
  align-items: start;
}
.stack { display: flex; flex-direction: column; gap: 0.85rem; }

.panel {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  overflow: hidden;
}
.panel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.95rem 1.1rem 0.85rem;
  border-bottom: 1px solid var(--line);
}
.panel-head h3 { font-size: 0.96rem; }
.panel-head p { margin-top: 0.22rem; color: var(--ink-3); font-size: 0.78rem; line-height: 1.45; }
.tally {
  font-family: var(--mono);
  font-size: 0.68rem;
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--ink-3);
  flex: none;
}
.tally.bad { color: var(--bad); border-color: rgba(255, 122, 122, 0.32); background: rgba(255, 122, 122, 0.08); }
.tally.ok { color: var(--ok); border-color: rgba(61, 222, 164, 0.28); background: rgba(61, 222, 164, 0.07); }

/* ── topology map ───────────────────────────────────────────── */
.legend-inline { display: flex; flex-wrap: wrap; gap: 0.5rem 0.85rem; flex: none; }
.legend-inline span { display: inline-flex; align-items: center; gap: 0.35rem; font-family: var(--mono); font-size: 0.63rem; color: var(--ink-3); }
.legend-inline i { width: 7px; height: 7px; border-radius: 2px; }

.map-wrap {
  position: relative;
  background:
    radial-gradient(circle at 50% 46%, rgba(255, 179, 71, 0.09), transparent 46%),
    radial-gradient(circle at 50% 46%, rgba(94, 200, 255, 0.05), transparent 68%);
}
#mesh-svg { width: 100%; height: auto; display: block; }
.map-empty {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--ink-4);
  pointer-events: none;
}
/* `display: grid` would otherwise beat the UA rule for [hidden]. */
.map-empty[hidden] { display: none; }

/* svg primitives */
.spoke { stroke: rgba(94, 200, 255, 0.3); stroke-width: 1.3; fill: none; stroke-dasharray: 3 6; animation: dash 16s linear infinite; }
.spoke.stale { stroke: rgba(240, 194, 75, 0.4); }
.spoke.down { stroke: rgba(255, 122, 122, 0.28); stroke-dasharray: 2 8; }
.spoke.planned { stroke: rgba(98, 107, 129, 0.32); stroke-dasharray: 2 8; }
@keyframes dash { to { stroke-dashoffset: -180; } }

.topo-ring { fill: none; stroke: rgba(234, 240, 251, 0.055); }
.topo-label { fill: var(--ink-4); font-family: var(--mono); font-size: 9px; letter-spacing: 0.16em; }
.topo-node-name { fill: var(--ink); font-family: var(--sans); font-size: 12.5px; font-weight: 600; }
.topo-node-sub { fill: var(--ink-4); font-family: var(--mono); font-size: 9px; letter-spacing: 0.05em; }
.topo-card { fill: rgba(16, 22, 35, 0.9); stroke: var(--line-2); stroke-width: 1; transition: stroke 0.2s, fill 0.2s; }
.node { cursor: pointer; }
.node:hover .topo-card { stroke: var(--line-3); fill: rgba(22, 29, 45, 0.95); }
.node.sel .topo-card { stroke: var(--amber); fill: rgba(28, 24, 20, 0.92); }
.node.hub-node.sel .hub-halo { stroke: rgba(255, 211, 140, 0.95); stroke-width: 2; }
.node.dim { opacity: 0.35; }
.hub-halo { transform-box: fill-box; transform-origin: center; animation: halo 3.6s ease-in-out infinite; }
@keyframes halo { 0%, 100% { opacity: 0.5; transform: scale(1); } 50% { opacity: 0.08; transform: scale(1.5); } }
.hub-spin { transform-box: fill-box; transform-origin: center; animation: spin 44s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.flow-dot { fill: var(--cyan); }

.inspector {
  display: grid;
  gap: 0.75rem;
  padding: 0.95rem 1.1rem;
  border-top: 1px solid var(--line);
  background: rgba(6, 9, 16, 0.4);
  min-height: 92px;
}
.insp-head { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.insp-head h4 { font-size: 0.95rem; }
.insp-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(112px, 1fr)); gap: 0.6rem 1rem; }
.insp-grid div b {
  display: block;
  font-family: var(--mono);
  font-size: 0.56rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 0.22rem;
  font-weight: 500;
}
.insp-grid div span { font-size: 0.82rem; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.app-tags { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.app-tags b {
  font-family: var(--mono);
  font-size: 0.64rem;
  font-weight: 400;
  padding: 0.18rem 0.42rem;
  border: 1px solid var(--line);
  border-radius: 5px;
  color: var(--ink-2);
  background: rgba(234, 240, 251, 0.025);
}
.insp-hint { color: var(--ink-4); font-size: 0.78rem; font-family: var(--mono); letter-spacing: 0.06em; }

/* ── attention feed ─────────────────────────────────────────── */
.feed { list-style: none; margin: 0; padding: 0.5rem; display: flex; flex-direction: column; gap: 0.15rem; max-height: 340px; overflow-y: auto; }
.feed::-webkit-scrollbar { width: 5px; }
.feed::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 3px; }
.feed li {
  display: grid;
  grid-template-columns: 16px 1fr auto;
  gap: 0.6rem;
  align-items: start;
  padding: 0.5rem 0.55rem;
  border-radius: var(--r-sm);
  font-size: 0.82rem;
  line-height: 1.4;
  transition: background 0.15s;
}
.feed li:hover { background: rgba(234, 240, 251, 0.035); }
.feed .ico { width: 14px; height: 14px; margin-top: 0.15rem; }
.feed .sev-ok .ico { color: var(--ok); }
.feed .sev-warn .ico { color: var(--warn); }
.feed .sev-bad .ico { color: var(--bad); }
.feed .sev-info .ico { color: var(--ink-4); }
.feed-text b { font-weight: 600; display: block; }
.feed-text span { color: var(--ink-3); font-size: 0.76rem; }
.feed-time { font-family: var(--mono); font-size: 0.62rem; color: var(--ink-4); white-space: nowrap; }
/* The clear state is a bare text <li>, but `.feed li` is a 3-column grid
   (16px icon · 1fr text · auto time) and outranks a bare class. The text node
   landed in the 16px icon cell and wrapped to three words. Match the selector
   so the grid is actually dropped for this one row. */
.feed li.feed-clear {
  display: block;
  padding: 1.1rem 0.7rem;
  color: var(--ink-4);
  font-size: 0.8rem;
  text-align: center;
}

/* ── console links ──────────────────────────────────────────── */
.link-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 0.5rem; padding: 0.85rem 1rem 1rem; }
.link-card {
  display: flex;
  flex-direction: column;
  gap: 0.28rem;
  padding: 0.65rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  text-decoration: none;
  background: rgba(234, 240, 251, 0.022);
  transition: border-color 0.16s, background 0.16s, transform 0.16s var(--ease);
}
.link-card:hover { border-color: rgba(94, 200, 255, 0.38); background: rgba(94, 200, 255, 0.06); transform: translateY(-1px); }
.link-card .lc-top { display: flex; align-items: center; gap: 0.4rem; }
.link-card b { font-size: 0.83rem; font-weight: 600; }
.link-card em { font-style: normal; font-family: var(--mono); font-size: 0.62rem; color: var(--ink-4); }
.link-card .lc-url { font-family: var(--mono); font-size: 0.6rem; color: var(--ink-3); opacity: 0.75; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.link-card.down { opacity: 0.55; }

/* ── generic rows (mesh / data / storage) ───────────────────── */
.rows { display: flex; flex-direction: column; gap: 0.5rem; }
.row {
  display: grid;
  grid-template-columns: 10px minmax(0, 1.15fr) minmax(0, 0.9fr) minmax(0, 1.35fr) auto;
  gap: 0.85rem;
  align-items: center;
  padding: 0.9rem 1.05rem;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: rgba(13, 18, 29, 0.8);
  animation: rise 0.42s var(--ease) both;
  transition: border-color 0.16s, background 0.16s, transform 0.16s var(--ease);
}
.row.mesh-row {
  grid-template-columns: 10px minmax(7.5rem, 0.85fr) minmax(0, 1.1fr) minmax(0, 1.6fr) auto;
}
.row:hover { border-color: color-mix(in srgb, var(--node-c, var(--amber)) 35%, var(--line-2)); background: var(--surface-2); transform: translateY(-1px); }
.row .meta {
  color: var(--ink-3);
  font-size: 0.79rem;
}
.row.mesh-row .meta {
  font-family: var(--mono);
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}
.row .name { font-weight: 600; font-size: 0.88rem; display: flex; align-items: center; gap: 0.45rem; flex-wrap: wrap; }
.row .detail {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--ink-2);
  line-height: 1.45;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.row.mesh-row .detail {
  white-space: normal;
  overflow: visible;
  text-overflow: unset;
}
.row .detail .d-main {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.row .detail .d-traffic {
  display: inline-flex;
  gap: 0.65rem;
  margin-top: 0.2rem;
  color: var(--ink-3);
  font-size: 0.68rem;
}
.row .detail .d-traffic b { color: var(--cyan); font-weight: 500; }
.row .actions { display: flex; gap: 0.4rem; justify-content: flex-end; flex-wrap: wrap; }
.row .age {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--ink-3);
  white-space: nowrap;
  text-align: right;
}
.row .age.fresh { color: var(--ok); }
.row .age.stale { color: var(--warn); }
.tag {
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.14rem 0.4rem;
  border: 1px solid var(--line);
  border-radius: 4px;
  color: var(--ink-3);
}
.tag.engine { color: var(--cyan); border-color: rgba(94, 200, 255, 0.28); }
.sub { display: block; margin-top: 0.15rem; color: var(--ink-4); font-size: 0.73rem; font-weight: 400; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.38rem;
  padding: 0.33rem 0.62rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink-2);
  text-decoration: none;
  font-size: 0.76rem;
  background: rgba(234, 240, 251, 0.022);
  white-space: nowrap;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
a.chip:hover { color: var(--ink); border-color: rgba(94, 200, 255, 0.42); background: rgba(94, 200, 255, 0.07); }
.chip-wrap { display: flex; flex-wrap: wrap; gap: 0.42rem; }
.chip-wrap .chip .dot { width: 6px; height: 6px; }

/* ── dots ───────────────────────────────────────────────────── */
.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ink-4); flex: none; display: inline-block; }
.dot.ok { background: var(--ok); box-shadow: 0 0 9px rgba(61, 222, 164, 0.4); }
.dot.warn, .dot.stale, .dot.degraded, .dot.unknown { background: var(--warn); box-shadow: 0 0 9px rgba(240, 194, 75, 0.32); }
.dot.down { background: var(--bad); box-shadow: 0 0 9px rgba(255, 122, 122, 0.34); }
.dot.planned { background: var(--ink-4); }
.dot.pulsing { animation: beat 2s ease-in-out infinite; }

/* ── mesh stat strip ────────────────────────────────────────── */
.mesh-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.6rem; margin-bottom: 1rem; }
.ms {
  padding: 0.75rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
}
.ms b { display: block; font-family: var(--mono); font-size: 0.56rem; letter-spacing: 0.17em; text-transform: uppercase; color: var(--ink-4); font-weight: 500; margin-bottom: 0.35rem; }
.ms span { font-size: 1.18rem; font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.ms.ok span { color: var(--ok); }
.ms.warn span { color: var(--warn); }
.ms.cyan span { color: var(--cyan); }

/* ── vm cards ───────────────────────────────────────────────── */
.vm-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(310px, 1fr)); gap: 0.7rem; }
.vm-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  padding: 1.1rem 1.15rem;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: rgba(13, 18, 29, 0.82);
  overflow: hidden;
  animation: rise 0.45s var(--ease) both;
  transition: border-color 0.18s, transform 0.18s var(--ease), background 0.18s;
}
.vm-card:hover {
  border-color: color-mix(in srgb, var(--node-c) 40%, var(--line-2));
  transform: translateY(-2px);
  background: rgba(18, 24, 38, 0.9);
}
.vm-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: linear-gradient(90deg, var(--node-c, var(--amber)), transparent 78%);
  opacity: 0.8;
}
.vm-card.planned { opacity: 0.72; }
.vm-card.planned::before { opacity: 0.3; }
.vm-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.7rem; }
.vm-top h3 { font-size: 1rem; display: flex; align-items: center; gap: 0.5rem; }
.vm-role {
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--node-c, var(--amber));
  border: 1px solid currentColor;
  padding: 0.1rem 0.35rem;
  border-radius: 4px;
  opacity: 0.8;
  flex: none;
}
.vm-tenancy { font-family: var(--mono); font-size: 0.68rem; color: var(--ink-3); }
.vm-specs { display: grid; grid-template-columns: 1fr 1fr; gap: 0.55rem 0.9rem; }
.vm-specs b { display: block; font-family: var(--mono); font-size: 0.55rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-4); font-weight: 500; margin-bottom: 0.2rem; }
.vm-specs span { font-size: 0.76rem; font-family: var(--mono); color: var(--ink-2); }
.vm-apps { padding-top: 0.65rem; border-top: 1px solid var(--line); flex: 1; }
.vm-apps > b { display: block; font-family: var(--mono); font-size: 0.55rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-4); font-weight: 500; margin-bottom: 0.4rem; }
.vm-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  padding-top: 0.2rem;
}
.vm-note {
  font-size: 0.71rem;
  color: var(--ink-4);
  font-style: italic;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* ── service tiles ──────────────────────────────────────────── */
.svc-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(292px, 1fr)); gap: 0.6rem; }
.svc {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0.85rem 0.95rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  text-decoration: none;
  animation: rise 0.42s var(--ease) both;
  transition: border-color 0.18s, background 0.18s, transform 0.18s var(--ease);
}
a.svc:hover { border-color: rgba(94, 200, 255, 0.4); background: var(--surface-2); transform: translateY(-2px); }
.svc.down { opacity: 0.62; }
.svc-mono {
  width: 38px;
  height: 38px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 10px;
  border: 1px solid var(--line-2);
  background: rgba(234, 240, 251, 0.03);
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-2);
  text-transform: uppercase;
}
.svc-body { min-width: 0; flex: 1; }
.svc-body b { display: block; font-size: 0.9rem; font-weight: 600; }
.svc-body span { display: block; font-size: 0.76rem; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svc-body em { display: block; font-style: normal; font-family: var(--mono); font-size: 0.62rem; color: var(--ink-4); margin-top: 0.18rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svc-go { color: var(--ink-4); flex: none; }
.svc-go .ico { width: 15px; height: 15px; }

/* ── tour view ──────────────────────────────────────────────── */
.view-tour { padding: 0.85rem 0.85rem 1rem; height: calc(100vh - var(--bar-h) - 1.7rem); min-height: 520px; }
.tour-frame {
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #05060b;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
}
.tour-bar {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.55rem 0.8rem;
  border-bottom: 1px solid var(--line);
  background: rgba(10, 14, 24, 0.8);
  flex: none;
}
.tour-title { display: inline-flex; align-items: center; gap: 0.45rem; font-size: 0.82rem; font-weight: 600; }
.tour-note { flex: 1; font-family: var(--mono); font-size: 0.63rem; color: var(--ink-4); letter-spacing: 0.05em; }
.tour-note kbd {
  font-family: var(--mono);
  font-size: 0.9em;
  padding: 0.05rem 0.28rem;
  border: 1px solid var(--line-2);
  border-bottom-width: 2px;
  border-radius: 4px;
  color: var(--ink-3);
}
#tour-frame { flex: 1; width: 100%; border: 0; display: block; background: #05060b; }

/* ── Claude FM (rail toggle · audio only) ───────────────────── */
.rail-fm {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  width: 100%;
  padding: 0.56rem 0.65rem;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: rgba(234, 240, 251, 0.02);
  color: var(--ink-3);
  font: inherit;
  font-size: 0.885rem;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: color 0.16s var(--ease), background 0.16s var(--ease), border-color 0.16s var(--ease);
}
.rail-fm:hover {
  color: var(--ink);
  background: rgba(234, 240, 251, 0.045);
}
.rail-fm.on {
  color: var(--ink);
  border-color: rgba(255, 179, 71, 0.35);
  background: rgba(255, 179, 71, 0.1);
}
.rail-fm-label { flex: 1; min-width: 0; }
.rail-fm-state {
  font-style: normal;
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-4);
  flex: none;
}
.rail-fm.on .rail-fm-state { color: var(--amber); }

.fm-eq {
  display: inline-flex;
  align-items: flex-end;
  gap: 3px;
  height: 14px;
  width: 14px;
  color: var(--ink-4);
  flex: none;
}
.fm-eq i {
  display: block;
  width: 2.5px;
  border-radius: 1px;
  background: currentColor;
  transform-origin: bottom;
  height: 6px;
}
.fm-eq i:nth-child(2) { height: 11px; }
.fm-eq i:nth-child(3) { height: 8px; }
.rail-fm.on .fm-eq { color: var(--amber); }
.rail-fm.on .fm-eq i {
  animation: fm-eq 1.1s ease-in-out infinite;
}
.rail-fm.on .fm-eq i:nth-child(1) { animation-delay: 0s; }
.rail-fm.on .fm-eq i:nth-child(2) { animation-delay: 0.18s; }
.rail-fm.on .fm-eq i:nth-child(3) { animation-delay: 0.36s; }
@keyframes fm-eq {
  0%, 100% { transform: scaleY(0.45); }
  50% { transform: scaleY(1); }
}

/* Off-DOM audio host — never shown */
.fm-host {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
  opacity: 0;
  pointer-events: none;
}

/* ── toast ──────────────────────────────────────────────────── */
.toast {
  position: fixed;
  right: 1.2rem;
  bottom: 1.2rem;
  z-index: 60;
  padding: 0.65rem 0.9rem;
  border: 1px solid rgba(255, 122, 122, 0.35);
  border-radius: var(--r-sm);
  background: rgba(28, 12, 14, 0.9);
  backdrop-filter: blur(10px);
  color: #ffc9c9;
  font-size: 0.82rem;
  max-width: 30ch;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
}
.toast[hidden] { display: none; }

/* ── responsive ─────────────────────────────────────────────── */
@media (max-width: 1180px) {
  .grid-2 { grid-template-columns: 1fr; }
}

@media (max-width: 980px) {
  :root { --rail-w: 0px; }
  .shell { grid-template-columns: 1fr; }
  /* Scrim + rail share .shell's stacking context so the menu stays clickable.
     (A body::after overlay painted above .shell and ate every nav tap.) */
  .rail-scrim {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 35;
    margin: 0;
    padding: 0;
    border: 0;
    background: rgba(4, 6, 10, 0.6);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    cursor: pointer;
  }
  body.rail-open .rail-scrim { display: block; }
  .rail {
    position: fixed;
    z-index: 40;
    width: min(252px, 86vw);
    transform: translateX(-102%);
    transition: transform 0.28s var(--ease);
    box-shadow: 24px 0 60px rgba(0, 0, 0, 0.5);
    pointer-events: auto;
  }
  body.rail-open .rail { transform: none; }
  .rail-toggle { display: grid; position: relative; z-index: 45; }
  .bar { padding: 0.85rem 1rem; }
  .view { padding: 1.1rem 1rem 2.5rem; }

  /* Five pills plus a clock do not fit next to the title at tablet width. The
     freshness pill already carries the hub timestamp, and the demo pill is a
     local-only affordance. */
  .clock { display: none; }
  #demo-pill { display: none; }
  /* Rows collapse to three columns. Every child gets an explicit row here:
     auto-placement used to drop `.meta` into the row-2 slot that `.detail`
     claims explicitly, and the two painted on top of each other. */
  .row {
    grid-template-columns: 10px minmax(0, 1fr) auto;
    gap: 0.55rem 0.75rem;
  }
  .row .dot { grid-row: 1; grid-column: 1; }
  .row .name { grid-row: 1; grid-column: 2; }
  .row .actions { grid-row: 1; grid-column: 3; }
  .row .meta { grid-row: 2; grid-column: 2 / -1; }
  .row .detail {
    grid-row: 3;
    grid-column: 2 / -1;
    white-space: normal;
    /* OCI endpoints and mesh addresses have no break opportunities — without
       this they push the card wider than the viewport on phones. */
    overflow-wrap: anywhere;
  }

  .row.mesh-row .meta { grid-row: 1; grid-column: 2; font-size: 0.78rem; }
  .row.mesh-row .name { grid-row: 2; grid-column: 2; font-size: 0.8rem; }
  .row.mesh-row .detail { grid-row: 3; grid-column: 2 / -1; }
  .row.mesh-row .detail .d-main { white-space: normal; }
  .row.mesh-row .age { grid-row: 1; grid-column: 3; align-self: start; text-align: right; }

  /* Tour: edge-to-edge iframe so the scene isn't crushed by padding/chrome. */
  .view-tour {
    padding: 0;
    height: calc(100dvh - var(--bar-h));
    min-height: 0;
  }
  .tour-frame {
    border-radius: 0;
    border: none;
    box-shadow: none;
  }
  .tour-bar { padding: 0.45rem 0.75rem; }
  .tour-note { display: none; }
}

@media (max-width: 620px) {
  .bar-title p { display: none; }
  .clock { display: none; }
  .btn.ghost { display: none; }

  /* The bar had no room at 390px: the health pill painted over the heading and
     the freshness pill ran off the right edge. The verdict banner directly
     below carries the same health verdict, so drop the duplicate here and keep
     only the compact freshness pill. */
  .bar { gap: 0.6rem; padding: 0.7rem 0.85rem; min-height: 54px; }
  .bar-health { display: none; }
  #demo-pill { display: none; }
  .bar-title h1 { font-size: 0.98rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Tighten the pill so the whole "refreshed HH:MM:SS" still fits at 390px
     instead of clipping to a bare word. */
  #fresh-pill { font-size: 0.55rem; letter-spacing: 0.06em; padding: 0.28rem 0.5rem; }

  .verdict-meta { gap: 1rem; }
  .vm-item { text-align: left; }
  .kpi-value { font-size: 1.32rem; }

  /* Panel heads stack so the title isn't squeezed into a narrow column. */
  .panel-head { flex-direction: column; align-items: stretch; gap: 0.6rem; }
  .legend-inline { gap: 0.4rem 0.7rem; }

  /* Keep the topology legible instead of shrinking it into a thumbnail. */
  .map-wrap { overflow-x: auto; overscroll-behavior-x: contain; }
  #mesh-svg { min-width: 580px; }
  .insp-grid { grid-template-columns: 1fr 1fr; }
  .section-lead h2 { font-size: 1.3rem; }
  .bar-title p#bar-sub { display: block; font-size: 0.62rem; }
  .row { grid-template-columns: 1fr; }
}

.status-line {
  min-height: 1.4rem;
  margin: 0;
  padding: 0.35rem 1.3rem 0;
  color: var(--ink-2);
  font-family: var(--mono);
  font-size: 0.75rem;
}
.confirm {
  position: sticky;
  bottom: 0.8rem;
  z-index: 6;
  display: flex;
  gap: 0.7rem;
  align-items: center;
  margin: 0 1.3rem 1rem;
  border: 1px solid rgba(255, 179, 71, 0.45);
  border-radius: var(--r-md);
  background: #12100c;
  padding: 0.85rem 1rem;
}
.confirm[hidden] { display: none; }
.confirm p { margin: 0; flex: 1; }
.confirm button, .switch {
  border: 0;
  border-radius: 999px;
  padding: 0.55rem 0.95rem;
  background: linear-gradient(135deg, var(--amber), var(--ember));
  color: #1a1005;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
#confirm-no, .switch.sleeping {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line-2);
}
.row {
  display: grid;
  grid-template-columns: minmax(8rem, 0.8fr) minmax(0, 1.4fr) auto;
  gap: 0.8rem;
  align-items: center;
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--line);
}
.hosts a { color: var(--cyan); text-decoration: none; }
.also { display: block; color: var(--ink-3); font-size: 0.78rem; }
.lc-role, .lc-go {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.link-card { text-decoration: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* Sign-in. Full field, one form, consoles as real destinations. */
body.login-body {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 2.5rem 1.25rem;
}
.gate {
  position: relative;
  z-index: 1;
  width: min(1080px, 100%);
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(280px, 420px);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
.gate-mark svg {
  width: 76px;
  height: 76px;
  color: var(--amber);
  filter: drop-shadow(0 0 22px rgba(255, 179, 71, 0.45));
}
.gate-kicker {
  margin: 1.15rem 0 0.35rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.gate h1 {
  margin: 0;
  max-width: 9ch;
  font-size: clamp(2.6rem, 5vw, 4.1rem);
  line-height: 0.92;
  letter-spacing: -0.045em;
}
.gate-host {
  margin: 1.1rem 0 0;
  font-family: var(--mono);
  font-size: 0.92rem;
  color: var(--cyan);
}
.gate-lead {
  margin: 0.45rem 0 0;
  max-width: 34ch;
  color: var(--ink-2);
  line-height: 1.5;
}
.gate .facts {
  display: flex;
  flex-wrap: wrap;
  gap: 1.4rem 1.8rem;
  margin-top: 2.2rem;
}
.gate .fact b {
  display: block;
  margin-bottom: 0.2rem;
  font-family: var(--mono);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.gate .fact span { font-size: 0.95rem; }
.gate-form {
  padding: 1.5rem 1.45rem 1.25rem;
  border: 1px solid var(--line-2);
  border-radius: 22px;
  background: rgba(10, 14, 22, 0.78);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
.gate-form h2 { margin: 0 0 1.15rem; font-size: 1.2rem; }
.gate .field { margin-bottom: 0.9rem; }
.login-body label {
  display: block;
  margin-bottom: 0.4rem;
  font-size: 0.84rem;
  color: var(--ink-2);
}
.login-body input {
  width: 100%;
  padding: 0.85rem 0.9rem;
  border: 1px solid var(--line-2);
  border-radius: 12px;
  background: rgba(5, 7, 12, 0.65);
  color: var(--ink);
  font: inherit;
  transition: border-color 0.16s var(--ease), box-shadow 0.16s var(--ease);
}
.login-body input:focus {
  outline: none;
  border-color: rgba(255, 179, 71, 0.7);
  box-shadow: 0 0 0 4px rgba(255, 179, 71, 0.12);
}
.login-body button[type="submit"] {
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.9rem 1rem;
  border: 0;
  border-radius: 12px;
  cursor: pointer;
  background: linear-gradient(180deg, #ffc56a, var(--ember));
  color: #1a1005;
  font: inherit;
  font-weight: 650;
  box-shadow: 0 8px 24px rgba(255, 106, 0, 0.22);
}
.login-body button[type="submit"]:hover { filter: brightness(1.05); }
.err { min-height: 0; margin: 0 0 0.8rem; color: #ffb4b4; opacity: 0; }
.err.show { opacity: 1; min-height: 1.2em; }
.gate-consoles > p {
  margin: 1.15rem 0 0.55rem;
  font-size: 0.82rem;
  color: var(--ink-3);
}
.foot-links { display: grid; grid-template-columns: 1fr 1fr; gap: 0.45rem; }
.foot-links .gate-link:last-child:nth-child(odd) { grid-column: 1 / -1; }
.gate-link {
  display: flex;
  flex-direction: column;
  gap: 0.12rem;
  min-width: 0;
  padding: 0.65rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  color: inherit;
  text-decoration: none;
  transition: border-color 0.16s var(--ease), background 0.16s var(--ease), transform 0.16s var(--ease);
}
.gate-link:hover {
  border-color: rgba(94, 200, 255, 0.45);
  background: rgba(94, 200, 255, 0.06);
  transform: translateY(-1px);
}
.gate-link span { font-weight: 600; font-size: 0.88rem; }
.gate-link small { color: var(--ink-3); font-size: 0.72rem; line-height: 1.3; }
@media (max-width: 860px) {
  .gate { grid-template-columns: 1fr; width: min(440px, 100%); gap: 1.6rem; }
  .gate-mark svg { width: 52px; height: 52px; }
  .gate h1 { font-size: 2.4rem; }
  .foot-links { grid-template-columns: 1fr; }
}

/* Transitions.dev snippets. Reduced-motion guards stay with each snippet. */


/* 02-number-pop-in.md */
:root {
  --digit-dur: 500ms;
  --digit-distance: 8px;
  --digit-stagger: 70ms;
  --digit-blur: 2px;
  --digit-ease: cubic-bezier(0.34, 1.45, 0.64, 1);
  --digit-dir-x: 0;
  --digit-dir-y: 1;
}

@keyframes t-digit-pop-in {
  0%   {
    transform: translate(
      calc(var(--digit-distance) * var(--digit-dir-x)),
      calc(var(--digit-distance) * var(--digit-dir-y))
    );
    opacity: 0;
    filter: blur(var(--digit-blur));
  }
  100% { transform: translate(0, 0); opacity: 1; filter: blur(0); }
}

.t-digit-group {
  display: inline-flex;
  align-items: baseline;
}
.t-digit {
  display: inline-block;
  will-change: transform, opacity, filter;
}
.t-digit-group.is-animating .t-digit {
  animation: t-digit-pop-in var(--digit-dur) var(--digit-ease) both;
}
.t-digit-group.is-animating .t-digit[data-stagger="1"] {
  animation-delay: var(--digit-stagger);
}
.t-digit-group.is-animating .t-digit[data-stagger="2"] {
  animation-delay: calc(var(--digit-stagger) * 2);
}

@media (prefers-reduced-motion: reduce) {
  .t-digit-group .t-digit { animation: none !important; }
}


/* 04-text-states-swap.md */
:root {
  --text-swap-dur: 150ms;
  --text-swap-translate-y: 4px;
  --text-swap-blur: 2px;
  --text-swap-ease: ease-in-out;
}

.t-text-swap {
  display: inline-block;
  transform: translateY(0);
  filter: blur(0);
  opacity: 1;
  transition:
    transform var(--text-swap-dur) var(--text-swap-ease),
    filter    var(--text-swap-dur) var(--text-swap-ease),
    opacity   var(--text-swap-dur) var(--text-swap-ease);
  will-change: transform, filter, opacity;
}
.t-text-swap.is-exit {
  transform: translateY(calc(var(--text-swap-translate-y) * -1));
  filter: blur(var(--text-swap-blur));
  opacity: 0;
}
.t-text-swap.is-enter-start {
  transform: translateY(var(--text-swap-translate-y));
  filter: blur(var(--text-swap-blur));
  opacity: 0;
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  .t-text-swap { transition: none !important; }
}


/* 28-thinking-states.md */
:root {
  --think-hold: 2000ms;
  --think-swap: 150ms;
  --think-gap: 50ms;
  --think-distance: 8px;
  --think-blur: 2px;
  --think-shimmer: 2000ms;
  --think-base: #7c7c7c;
  --think-highlight: #0d0d0d;
  --think-ease: ease-in-out;
}

/* Set your type on .t-think: the sizer only reports the right
   width if it is set in the same font as the line. */
.t-think { position: relative; display: inline-block; text-align: center; }
.t-think-sizer { display: block; visibility: hidden; white-space: nowrap; }
.t-think-text {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: block;
  color: var(--think-base);
  white-space: nowrap;
  transform: translateY(0);
  filter: blur(0);
  opacity: 1;
  transition:
    transform var(--think-swap) var(--think-ease),
    filter var(--think-swap) var(--think-ease),
    opacity var(--think-swap) var(--think-ease);
  will-change: transform, filter, opacity;
}
/* Shimmer sweeps the glyphs only (background-clip: text). */
.t-think-text::before {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: linear-gradient(90deg,
    transparent 0%, transparent 40%,
    var(--think-highlight) 50%,
    transparent 60%, transparent 100%);
  background-size: 400% 100%;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: t-think-shimmer var(--think-shimmer) linear infinite;
}
@keyframes t-think-shimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: 0% 0; }
}
/* The outgoing line floats over the box so both halves animate. */
.t-think-text.is-exit {
  transform: translateY(calc(var(--think-distance) * -1));
  filter: blur(var(--think-blur));
  opacity: 0;
}
.t-think-text.is-enter-start {
  transition: none;
  transform: translateY(var(--think-distance));
  filter: blur(var(--think-blur));
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .t-think-text { transition: none !important; transform: none !important; filter: none !important; }
  .t-think-text::before { display: none !important; }
}


/* 14-skeleton-reveal.md */
:root {
  --pulse-dur: 1000ms;
  --pulse-count: 1;
  --pulse-min: 0.5;
  --reveal-dur: 400ms;
  --reveal-blur: 2px;
  --reveal-ease: ease-in-out;
}

/* The wrap stacks two layers on the same coordinates. The
   skeleton owns the cold pulse + the fade-out side of the
   reveal; the content owns the fade-in side. They share the
   same duration / ease so the swap reads as one motion. */
.t-skel { position: relative; }
.t-skel-skeleton,
.t-skel-content {
  position: absolute;
  inset: 0;
}

.t-skel-skeleton {
  z-index: 1;
  opacity: 1;
  filter: blur(0);
  transition:
    opacity var(--reveal-dur) var(--reveal-ease),
    filter  var(--reveal-dur) var(--reveal-ease);
}
.t-skel-content {
  z-index: 2;
  opacity: 0;
  filter: blur(var(--reveal-blur));
  transition:
    opacity var(--reveal-dur) var(--reveal-ease),
    filter  var(--reveal-dur) var(--reveal-ease);
}
.t-skel.is-revealed .t-skel-skeleton {
  opacity: 0;
  filter: blur(var(--reveal-blur));
}
.t-skel.is-revealed .t-skel-content {
  opacity: 1;
  filter: blur(0);
}
/* Snap-back when replaying: kill transitions so the reverse
   (revealed → skeleton) is instant. Drop `.is-resetting`
   after a forced reflow and the next reveal animates again. */
.t-skel.is-resetting .t-skel-skeleton,
.t-skel.is-resetting .t-skel-content {
  transition: none !important;
}

/* Pulse: place the animation on the bar/avatar children, not
   on the skeleton itself, so the skeleton's opacity / filter
   stay free for the cross-fade transition above. */
.t-skel-skeleton.is-pulsing > * {
  animation: t-skel-pulse var(--pulse-dur) ease-in-out var(--pulse-count);
}
@keyframes t-skel-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: var(--pulse-min); }
}

@media (prefers-reduced-motion: reduce) {
  .t-skel-skeleton, .t-skel-content {
    transition: none !important;
  }
  .t-skel-skeleton.is-pulsing > * { animation: none !important; }
}


/* 07-panel-reveal.md */
:root {
  --panel-open-dur: 400ms;
  --panel-close-dur: 350ms;
  --panel-translate-y: 100px;
  --panel-blur: 2px;
  --panel-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

.t-panel-slide {
  transform: translateY(var(--panel-translate-y));
  opacity: 0;
  filter: blur(var(--panel-blur));
  pointer-events: none;
  transition:
    transform var(--panel-close-dur) var(--panel-ease),
    opacity   var(--panel-close-dur) var(--panel-ease),
    filter    var(--panel-close-dur) var(--panel-ease);
  will-change: transform, opacity, filter;
}
.t-panel-slide[data-open="true"] {
  transform: translateY(0);
  opacity: 1;
  filter: blur(0);
  pointer-events: auto;
  transition:
    transform var(--panel-open-dur) var(--panel-ease),
    opacity   var(--panel-open-dur) var(--panel-ease),
    filter    var(--panel-open-dur) var(--panel-ease);
}

@media (prefers-reduced-motion: reduce) {
  .t-panel-slide { transition: none !important; }
}


/* 22-toast.md */
:root {
  --toast-open: 350ms;
  --toast-close: 250ms;
  --toast-distance: 16px;
  --toast-blur: 2px;
  --toast-scale: 0.97;
  --toast-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

.t-toast {
  opacity: 0;
  transform: translateY(var(--toast-distance)) scale(var(--toast-scale));
  filter: blur(var(--toast-blur));
  will-change: transform, opacity, filter;
  transition:
    opacity var(--toast-close) var(--toast-ease),
    transform var(--toast-close) var(--toast-ease),
    filter var(--toast-close) var(--toast-ease);
}
.t-toast.is-open {
  opacity: 1;
  transform: translateY(0) scale(1);
  filter: blur(0);
  transition:
    opacity var(--toast-open) var(--toast-ease),
    transform var(--toast-open) var(--toast-ease),
    filter var(--toast-open) var(--toast-ease);
}

@media (prefers-reduced-motion: reduce) {
  .t-toast { transition: none !important; }
}


/* 12-error-state-shake.md */
:root {
  --shake-distance: 6px;
  --shake-overshoot: 4px;
  --shake-dur-a: 80ms;
  --shake-dur-b: 60ms;
  --shake-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --revert-hold: 3000ms;
  --revert-dur: 280ms;
}

/* Border-color tween. Define your input's default / focused
   / error border-color in your own component CSS — this rule
   only owns the interpolation. Use a constant border-width
   across states so the tween never shifts inner content. */
.t-input {
  transition: border-color 150ms ease-out;
  will-change: transform;
}
.t-input.is-error {
  /* Error border auto-reverts on the hold timer, so the
     fade-out uses the slower revert duration (matches the
     message fade). */
  transition: border-color var(--revert-dur, 280ms) ease-out;
}

/* Error message reveal. Visibility is delayed by --revert-dur
   on hide so the message stays painted for the full opacity
   fade-out. Entering .is-error drops the delay to 0 so the
   message becomes visible immediately. */
.t-error-msg {
  opacity: 0;
  visibility: hidden;
  transition:
    opacity    var(--revert-dur, 280ms) ease-out,
    visibility 0s linear var(--revert-dur, 280ms);
}
.t-input-wrap.is-error .t-error-msg {
  opacity: 1;
  visibility: visible;
  transition:
    opacity    var(--revert-dur, 280ms) ease-out,
    visibility 0s linear 0s;
}

/* Multi-segment keyframe with per-stop easing so each leg
   of the shake follows its own cubic-bezier independently.
   %-stops are cumulative durations as a fraction of the
   total (80, 60, 80, 60 = 280ms): 28.57%, 57.14%, 78.57%,
   100%. Recompute if any segment duration changes. */
.t-input.is-shaking {
  animation: t-input-shake calc(
      var(--shake-dur-a) * 2 + var(--shake-dur-b) * 2
    ) linear;
}
@keyframes t-input-shake {
  0%      { transform: translateX(0);                                 animation-timing-function: var(--shake-ease); }
  28.57%  { transform: translateX(var(--shake-distance));             animation-timing-function: var(--shake-ease); }
  57.14%  { transform: translateX(calc(var(--shake-distance) * -1)); animation-timing-function: var(--shake-ease); }
  78.57%  { transform: translateX(var(--shake-overshoot));            animation-timing-function: var(--shake-ease); }
  100%    { transform: translateX(0); }
}

@media (prefers-reduced-motion: reduce) {
  .t-input { animation: none !important; transform: none !important; }
}


/* 10-success-check.md */
:root {
  --check-opacity-dur: 500ms;
  --check-rotate-dur: 500ms;
  --check-rotate-from: 80deg;
  --check-bob-dur: 500ms;
  --check-y-amount: 40px;
  --check-blur-dur: 500ms;
  --check-blur-from: 10px;
  --check-path-dur: 500ms;
  --check-path-delay: 80ms;
  --check-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --check-ease-opacity: cubic-bezier(0.22, 1, 0.36, 1);
  --check-ease-rotate: cubic-bezier(0.22, 1, 0.36, 1);
  --check-ease-bob: cubic-bezier(0.34, 1.35, 0.64, 1);
  --check-ease-path: cubic-bezier(0.22, 1, 0.36, 1);
}

/* Wrapper drives the appear animation; it doesn't own any
   sizing or color so you can drop in any icon. */
.t-success-check {
  display: inline-block;
  transform-origin: center;
  opacity: 0;
  will-change: transform, opacity, filter;
}
/* overflow: visible keeps the stroke from clipping while it
   draws; display: block kills the inline whitespace under SVGs. */
.t-success-check svg { display: block; overflow: visible; }
/* Stroke-draw setup. Replace 20 with the result of
   path.getTotalLength() for your path; round caps mean any
   sub-pixel overshoot is invisible. */
.t-success-check svg path {
  stroke-dasharray: 20;
  stroke-dashoffset: 20;
}

.t-success-check[data-state="in"] {
  animation:
    t-check-fade   var(--check-opacity-dur) var(--check-ease-opacity) forwards,
    t-check-rotate var(--check-rotate-dur)  var(--check-ease-rotate)  forwards,
    t-check-blur   var(--check-blur-dur)    var(--check-ease-out)     forwards,
    t-check-bob    var(--check-bob-dur)     var(--check-ease-bob)     forwards;
}
.t-success-check[data-state="in"] svg path {
  animation: t-check-draw var(--check-path-dur) var(--check-ease-path) var(--check-path-delay, 0ms) forwards;
}

@keyframes t-check-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes t-check-rotate {
  from { transform: rotate(var(--check-rotate-from)); }
  to   { transform: rotate(0deg); }
}
@keyframes t-check-blur {
  from { filter: blur(var(--check-blur-from)); }
  to   { filter: blur(0); }
}
@keyframes t-check-bob {
  from { translate: 0 var(--check-y-amount); }
  to   { translate: 0 0; }
}
@keyframes t-check-draw { to { stroke-dashoffset: 0; } }

@media (prefers-reduced-motion: reduce) {
  .t-success-check { animation: none !important; opacity: 1; }
  .t-success-check svg path { animation: none !important; stroke-dashoffset: 0 !important; }
}


/* 03-notification-badge.md */
:root {
  --badge-slide-dur: 260ms;
  --badge-pop-dur: 500ms;
  --badge-pop-close-dur: 180ms;
  --badge-fade-dur: 400ms;
  --badge-fade-close-dur: 180ms;
  --badge-blur: 2px;
  --badge-offset-x: -8.2px;
  --badge-offset-y: 12.4px;
  --badge-slide-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --badge-pop-ease: cubic-bezier(0.34, 1.36, 0.64, 1);
  --badge-close-ease: cubic-bezier(0.4, 0, 0.2, 1);
}

@keyframes t-badge-slide-in {
  from { transform: translate(var(--badge-offset-x), var(--badge-offset-y)); }
  to   { transform: translate(0, 0); }
}

/* .t-badge is the absolutely-positioned wrapper for the dot.
   Adjust top/right (or left/bottom) to anchor it on your trigger. */
.t-badge {
  position: absolute;
  top: -6px;
  right: -8px;
  pointer-events: none;
  will-change: transform;
}
.t-badge[data-open="true"] {
  animation: t-badge-slide-in var(--badge-slide-dur) var(--badge-slide-ease);
}

.t-badge-dot {
  display: block;
  transform-origin: center;
  transform: scale(1);
  opacity: 1;
  filter: blur(0);
  transition:
    transform var(--badge-pop-dur)  var(--badge-pop-ease),
    opacity   var(--badge-fade-dur) var(--badge-pop-ease),
    filter    var(--badge-pop-dur)  var(--badge-pop-ease);
  will-change: transform, opacity, filter;
}
.t-badge[data-open="false"] .t-badge-dot {
  transform: scale(0);
  opacity: 0;
  filter: blur(var(--badge-blur));
  transition:
    transform var(--badge-pop-close-dur)  var(--badge-close-ease),
    opacity   var(--badge-fade-close-dur) var(--badge-close-ease),
    filter    var(--badge-pop-close-dur)  var(--badge-close-ease);
}

@media (prefers-reduced-motion: reduce) {
  .t-badge, .t-badge-dot { animation: none !important; transition: none !important; }
}


/* 19-card-tilt.md */
:root {
  --tilt-perspective: 1000px;
  --tilt-return: 1000ms;
  --tilt-return-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --tilt-follow: 400ms;
  --tilt-follow-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --tilt-glare-opacity: 0.22;
  --tilt-glare-fade: 300ms;
  --tilt-glare-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* The outer wrapper is the flat hit area; touch-action:none
   lets a finger drag tilt the card instead of scrolling the
   page, so tap-hold-drag works on mobile. */
.t-tilt { touch-action: none; }
/* The card tilts toward the pointer via rotateX/rotateY fed
   from JS; on leave it eases back to flat. A separate
   .is-tilting class swaps in a short linear follow while the
   pointer moves so the tilt tracks the cursor 1:1. */
.t-tilt-card {
  position: relative;
  border-radius: 12px;
  overflow: hidden;
  transform:
    perspective(var(--tilt-perspective))
    rotateX(var(--tilt-rx, 0deg))
    rotateY(var(--tilt-ry, 0deg));
  transform-style: preserve-3d;
  transition: transform var(--tilt-return) var(--tilt-return-ease);
  will-change: transform;
}
.t-tilt-card.is-tilting {
  transition: transform var(--tilt-follow) var(--tilt-follow-ease);
}
/* Cursor-tracked glare: layered soft circles that add like
   light (screen blend) at the pointer position. */
.t-tilt-glare {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: screen;
  background:
    radial-gradient(circle 95px at var(--tilt-gx, 50%) var(--tilt-gy, 50%),
      rgba(255,255,255,0.48), rgba(255,255,255,0.06) 52%, rgba(255,255,255,0) 84%),
    radial-gradient(circle 200px at var(--tilt-gx, 50%) var(--tilt-gy, 50%),
      rgba(255,255,255,0.22), rgba(255,255,255,0.04) 58%, rgba(255,255,255,0) 78%),
    radial-gradient(circle 360px at var(--tilt-gx, 50%) var(--tilt-gy, 50%),
      rgba(255,255,255,0.10), rgba(255,255,255,0) 88%);
  transition: opacity var(--tilt-glare-fade) var(--tilt-glare-ease);
}
.t-tilt.is-hover .t-tilt-glare { opacity: var(--tilt-glare-opacity); }

@media (prefers-reduced-motion: reduce) {
  .t-tilt-card { transform: none !important; transition: none !important; }
}


/* 24-learn-more-hover.md */
:root {
  --learn-shift: 2px;
  --learn-spread: 8deg;
  --learn-in: 350ms;
  --learn-out: 350ms;
  --learn-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

.t-learn-chevron {
  display: inline-flex;
  transform: translateX(0);
  transition: transform var(--learn-out) var(--learn-ease);
}
.t-learn-arm {
  transform-box: view-box;
  transform-origin: 10px 8px;
  vector-effect: non-scaling-stroke;
  transition: transform var(--learn-out) var(--learn-ease);
}
.t-learn:hover .t-learn-chevron { transform: translateX(var(--learn-shift)); transition-duration: var(--learn-in); }
.t-learn:hover .t-learn-arm { transition-duration: var(--learn-in); }
.t-learn:hover .t-learn-arm-top { transform: rotate(var(--learn-spread)); }
.t-learn:hover .t-learn-arm-bot { transform: rotate(calc(var(--learn-spread) * -1)); }

@media (prefers-reduced-motion: reduce) {
  .t-learn-chevron, .t-learn-arm { transition: none !important; }
}


/* Libraries.dev Border beam, CSS port. No React. */
.border-beam { position: relative; }
.border-beam::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: conic-gradient(from var(--beam-angle, 0deg), transparent 0 70%, var(--amber) 85%, transparent 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  animation: beam-spin 4.5s linear infinite;
  pointer-events: none;
}
@property --beam-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}
@keyframes beam-spin { to { --beam-angle: 360deg; } }
.t-tilt { touch-action: auto; }
#kpi-skel { min-height: 168px; }
.nav-count.is-pop { animation: t-badge-slide-in var(--badge-slide-dur) var(--badge-slide-ease); }
.status-row {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 1.6rem;
  padding: 0.15rem 1.6rem 0;
}
.status-row .status-line { padding: 0; }
#status-check { display: inline-flex; margin: 0; color: var(--ok); }
#verdict.border-beam::before { animation-play-state: paused; opacity: 0.28; }
#verdict.border-beam:hover::before { animation-play-state: running; opacity: 1; }
.nav-item.active {
  border: 0;
  padding: 0.56rem 0.65rem;
  background: linear-gradient(90deg, rgba(255, 179, 71, 0.16), transparent 72%);
  box-shadow: inset 2px 0 0 var(--amber);
}
.confirm button { background: linear-gradient(180deg, #ffc56a, var(--ember)); color: #1a1005; border: 0; }
.switch {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line-2);
}
.switch:hover { border-color: rgba(255, 179, 71, 0.55); color: var(--amber); }
#app-rows .panel, .projects .panel { border-radius: 16px; overflow: hidden; }
.section-lead p { color: var(--ink-2); line-height: 1.5; }
[data-role="rail-status"].is-thinking {
  background-image: linear-gradient(90deg, var(--ink-3) 0%, var(--ink) 45%, var(--ink-3) 80%);
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: t-think-shimmer 2.4s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .border-beam::before { animation: none; opacity: 0.45; }
}
