/* ============================================================
   VayuPress VayuOS — Design System
   Sovereign · Self-hosted · Zero-CDN · Strict-CSP
   All layout and component styles. No inline-style required.
   Scope: .vp-os body class (coexists with v2 without conflict)
   ============================================================ */

/* ── Fonts ─────────────────────────────────────────────────── */
/* Space Grotesk — the brand face, served from the SAME embedded files the public
   theme uses (internal/theme/vayu.css). These three weights are compiled into the
   binary and allowlisted at /static/fonts, so they work on every install.

   This previously pointed at /os/static/fonts/space-grotesk.woff2 — a file that
   exists nowhere in the repo and is embedded in no binary, so every console page
   load fired a 404 and fell through to the system stack. Inter and JetBrains Mono
   were declared the same way and are gone entirely: shipping ~200 KB of fonts
   inside a single-binary product to restyle an admin panel that already reads
   correctly is the wrong trade, and their family names stay first in the stacks
   below so anyone who has them installed locally still gets them. */
@font-face { font-family: "Space Grotesk"; font-style: normal; font-weight: 500; font-display: swap; src: url("/static/fonts/space-grotesk-latin-500.woff2") format("woff2"); }
@font-face { font-family: "Space Grotesk"; font-style: normal; font-weight: 600; font-display: swap; src: url("/static/fonts/space-grotesk-latin-600.woff2") format("woff2"); }
@font-face { font-family: "Space Grotesk"; font-style: normal; font-weight: 700; font-display: swap; src: url("/static/fonts/space-grotesk-latin-700.woff2") format("woff2"); }

/* ── Design Tokens ──────────────────────────────────────────── */
.vp-os {
  /* Backgrounds — a calm, clean dark navy. Surfaces lift from the base in small,
     even steps. */
  --bg-base:      #080e1a;
  --bg-surface:   #0f1827;
  --bg-surface-2: #172135;
  --bg-surface-3: #1e2d47;
  --bg-glass:     rgba(15, 24, 39, 0.80);

  /* Cards — solid surface panels with a soft border. */
  --card-bg:      #0f1827;
  --card-border:  rgba(99, 130, 174, 0.18);
  --card-border-strong: rgba(99, 130, 174, 0.32);

  /* Borders */
  --border:       rgba(99, 130, 174, 0.18);
  --border-strong:rgba(99, 130, 174, 0.32);

  /* Text — muted tiers lifted for readability (AA against every dark surface).
     --text-2/--text-3 drive nearly all secondary/helper/placeholder copy app-
     wide, so raising them here brightens the whole console, not just one page. */
  --text:         #eef2f8;
  --text-2:       #b8c6dd;
  --text-3:       #93a6c4;
  /* Aliases: some components reference --text-1/--surface-2 (undefined before).
     Defined via var() indirection so they follow the light-theme overrides of
     --text/--bg-surface-2 automatically. Without these, `fill: var(--text-1)`
     in SVG fell back to the initial value (black) → invisible chart tooltips. */
  --text-1:       var(--text);
  --surface-2:    var(--bg-surface-2);

  /* Brand */
  --brand:        #0ea5e9;
  --brand-dim:    rgba(14, 165, 233, 0.18);
  --brand-glow:   rgba(14, 165, 233, 0.28);
  --accent:       #a78bfa;
  --accent-dim:   rgba(167, 139, 250, 0.18);

  /* Semantic */
  --ok:           #34d399;
  --ok-dim:       rgba(52, 211, 153, 0.18);
  --warn:         #fbbf24;
  --warn-dim:     rgba(251, 191, 36, 0.18);
  --danger:       #f87171;
  --danger-dim:   rgba(248, 113, 113, 0.18);
  --info:         #60a5fa;
  --info-dim:     rgba(96, 165, 250, 0.18);

  /* Typography */
  --font-head: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  --font-body: "Inter", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "JetBrains Mono", "SF Mono", ui-monospace, monospace;

  /* Type scale */
  --text-xs:   0.75rem;
  --text-sm:   0.8125rem;
  --text-base: 0.9375rem;
  --text-lg:   1.0625rem;
  --text-xl:   1.25rem;
  --text-2xl:  1.5rem;
  --text-3xl:  2rem;

  /* Spacing */
  --sp-1: 0.25rem;  --sp-2: 0.5rem;   --sp-3: 0.75rem;
  --sp-4: 1rem;     --sp-5: 1.25rem;  --sp-6: 1.5rem;
  --sp-8: 2rem;     --sp-10: 2.5rem;  --sp-12: 3rem;

  /* Radius */
  --r-sm: 6px;   --r: 10px;   --r-md: 14px;
  --r-lg: 20px;  --r-full: 9999px;

  /* Shadows */
  --sh-sm: 0 1px 3px rgba(0,0,0,0.45), 0 1px 2px rgba(0,0,0,0.35);
  --sh:    0 4px 16px rgba(0,0,0,0.55), 0 1px 4px rgba(0,0,0,0.35);
  --sh-lg: 0 12px 40px rgba(0,0,0,0.65);

  /* Transitions */
  --t-fast:   80ms  cubic-bezier(0.4, 0, 0.2, 1);
  --t:        160ms cubic-bezier(0.4, 0, 0.2, 1);
  --t-slow:   280ms cubic-bezier(0.4, 0, 0.2, 1);
  --t-spring: 350ms cubic-bezier(0.34, 1.56, 0.64, 1);
  --t-enter:  220ms cubic-bezier(0, 0, 0.2, 1);
  --t-exit:   160ms cubic-bezier(0.4, 0, 1, 1);

  /* Layout */
  --sidebar-w: 232px;
  --topbar-h:  56px;
}

/* Light mode override. "auto" is intentionally NOT forced light here — it
   follows the system via the prefers-color-scheme media query below, so a
   dark-preference OS keeps the dark base tokens. */
.vp-os[data-theme="light"] {
  --bg-base:      #f8fafc;
  --bg-surface:   #ffffff;
  --bg-surface-2: #f1f5f9;
  --bg-surface-3: #e2e8f0;
  --bg-glass:     rgba(248, 250, 252, 0.88);
  --card-bg:      #ffffff;
  --card-border:  rgba(15, 23, 42, 0.12);
  --card-border-strong: rgba(15, 23, 42, 0.22);
  --border:       rgba(15, 23, 42, 0.12);
  --border-strong:rgba(15, 23, 42, 0.24);
  --text:         #0f172a;
  --text-2:       #475569;
  --text-3:       #64748b;
  --brand:        #0284c7;
  --brand-dim:    rgba(2, 132, 199, 0.10);
  --brand-glow:   rgba(2, 132, 199, 0.20);
  --accent:       #7c3aed;
  --sh-sm: 0 1px 3px rgba(0,0,0,0.10), 0 1px 2px rgba(0,0,0,0.08);
  --sh:    0 4px 16px rgba(0,0,0,0.12), 0 1px 4px rgba(0,0,0,0.08);
  --sh-lg: 0 12px 40px rgba(0,0,0,0.16);
}
@media (prefers-color-scheme: light) {
  .vp-os[data-theme="auto"] {
    --bg-base:      #f8fafc;
    --bg-surface:   #ffffff;
    --bg-surface-2: #f1f5f9;
    --bg-surface-3: #e2e8f0;
    --bg-glass:     rgba(248, 250, 252, 0.88);
    --card-bg:      #ffffff;
    --card-border:  rgba(15, 23, 42, 0.12);
    --card-border-strong: rgba(15, 23, 42, 0.22);
    --border:       rgba(15, 23, 42, 0.12);
    --border-strong:rgba(15, 23, 42, 0.24);
    --text:         #0f172a;
    --text-2:       #475569;
    --text-3:       #64748b;
    --brand:        #0284c7;
    --brand-dim:    rgba(2, 132, 199, 0.10);
    --brand-glow:   rgba(2, 132, 199, 0.20);
    --accent:       #7c3aed;
    --sh-sm: 0 1px 3px rgba(0,0,0,0.10), 0 1px 2px rgba(0,0,0,0.08);
    --sh:    0 4px 16px rgba(0,0,0,0.12), 0 1px 4px rgba(0,0,0,0.08);
    --sh-lg: 0 12px 40px rgba(0,0,0,0.16);
  }
}

/* ── Reset ───────────────────────────────────────────────────── */
.vp-os *, .vp-os *::before, .vp-os *::after { box-sizing: border-box; margin: 0; padding: 0; }
.vp-os {
  font-family: var(--font-body); font-size: var(--text-base); color: var(--text);
  background: var(--bg-base);
  line-height: 1.55; -webkit-font-smoothing: antialiased; min-height: 100vh;
}
/* The decorative backdrop layers were removed (they read as noise); the markup
   still emits these hooks, so keep them inert. */
.vp-os .vp-grid, .vp-os .vp-aurora { display: none; }
.vp-os a { color: var(--brand); text-decoration: none; }
.vp-os a:hover { text-decoration: underline; }
.vp-os img, .vp-os svg { display: block; }
.vp-os button { cursor: pointer; border: none; background: none; font: inherit; color: inherit; }
.vp-os input, .vp-os select, .vp-os textarea { font: inherit; color: inherit; }
.vp-os h1, .vp-os h2, .vp-os h3, .vp-os h4 { font-family: var(--font-head); font-weight: 600; line-height: 1.2; letter-spacing: -0.018em; color: var(--text); }

/* Skip link */
.vp-os .skip-link {
  position: absolute; left: -9999px; top: var(--sp-2); z-index: 9999;
  padding: var(--sp-2) var(--sp-4); background: var(--brand); color: #fff;
  border-radius: var(--r-sm);
}
.vp-os .skip-link:focus { left: var(--sp-2); }

/* Visually-hidden but exposed to assistive tech (aria-live announcements). */
.vp-os .vp-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── Shell layout ────────────────────────────────────────────── */
.vp-os .shell {
  display: flex;
  min-height: 100vh;
}
.vp-os .main {
  flex: 1;
  min-width: 0;
  margin-left: var(--sidebar-w);
  display: flex;
  flex-direction: column;
  transition: margin-left var(--t-slow);
}
.vp-os .content {
  flex: 1;
  padding: var(--sp-6) var(--sp-8);
  max-width: 1280px;
  width: 100%;
}

/* ── Sidebar ─────────────────────────────────────────────────── */
.vp-os .sidebar {
  position: fixed;
  top: 0; left: 0;
  width: var(--sidebar-w);
  height: 100vh;
  background: var(--bg-surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  z-index: 200;
  overflow-y: auto;
  scrollbar-width: none;
  transition: transform var(--t-slow);
}
.vp-os .sidebar::-webkit-scrollbar { display: none; }

.vp-os .sidebar-brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
  font-family: var(--font-head);
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--text);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.vp-os .sidebar-brand img { width: 28px; height: 28px; border-radius: var(--r-sm); }
.vp-os .sidebar-brand-name { color: var(--text); }
.vp-os .sidebar-brand-os {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px 7px;
}

.vp-os .sidebar-nav {
  flex: 1;
  padding: var(--sp-3) var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.vp-os .sidebar-section-label {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
  padding: var(--sp-3) var(--sp-3) var(--sp-2);
  margin-top: var(--sp-2);
}

/* One-click Clearnet⟷Tor world switch, pinned to the top of the sidebar
   (ADR-0141) — styled like the marketing site's world toggle: a pill with a
   sliding thumb that sits under the active world and springs across on hover to
   preview the switch. Clearnet rides a sky-blue thumb, Tor a violet one. */
.vp-os .space-switch-wrap { padding: var(--sp-3) var(--sp-3) 0; }
.vp-os .space-switch {
  --clearnet-accent: #38bdf8;
  --tor-accent: #a78bfa;
  position: relative;
  display: flex;
  padding: 3px;
  background: var(--bg-surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  box-shadow: inset 0 1px 3px rgba(2, 8, 20, 0.35);
}
.vp-os .space-switch.is-busy { opacity: 0.6; pointer-events: none; }
/* The sliding thumb — absolutely positioned under the segments, its width one
   half of the inner track; it translates by its own width to reach segment 2. */
.vp-os .space-switch__thumb {
  position: absolute;
  top: 3px; bottom: 3px; left: 3px;
  width: calc(50% - 3px);
  border-radius: var(--r-full);
  background: var(--clearnet-accent);
  box-shadow: 0 3px 12px -3px var(--clearnet-accent);
  transition: transform var(--t-spring), background var(--t), box-shadow var(--t);
  z-index: 0;
}
.vp-os .space-switch[data-active="tor"] .space-switch__thumb {
  transform: translateX(100%);
  background: var(--tor-accent);
  box-shadow: 0 3px 12px -3px var(--tor-accent);
}
/* Hover-preview: springs the thumb toward the world you're about to switch to. */
.vp-os .space-switch[data-active="clearnet"]:has(.space-switch__seg[data-world="tor"]:hover) .space-switch__thumb {
  transform: translateX(100%); background: var(--tor-accent); box-shadow: 0 3px 14px -3px var(--tor-accent);
}
.vp-os .space-switch[data-active="tor"]:has(.space-switch__seg[data-world="clearnet"]:hover) .space-switch__thumb {
  transform: translateX(0); background: var(--clearnet-accent); box-shadow: 0 3px 14px -3px var(--clearnet-accent);
}
.vp-os .space-switch__seg {
  position: relative;
  z-index: 1;
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 7px 8px;
  font: 600 var(--text-xs)/1 var(--font-body);
  color: var(--text-2);
  background: transparent;
  border: 0;
  border-radius: var(--r-full);
  cursor: pointer;
  text-decoration: none;
  transition: color var(--t);
}
.vp-os .space-switch__ico {
  width: 14px; height: 14px; flex: 0 0 auto;
  transition: transform var(--t-spring), filter var(--t);
}
/* The segment whose thumb is under it (active, or hover-previewed) gets dark ink
   for contrast against the bright thumb; the other stays muted. */
.vp-os .space-switch__seg.is-active { color: #06121f; }
.vp-os .space-switch[data-active="clearnet"]:has([data-world="tor"]:hover) .space-switch__seg[data-world="tor"] { color: #06121f; }
.vp-os .space-switch[data-active="clearnet"]:has([data-world="tor"]:hover) .space-switch__seg[data-world="clearnet"] { color: var(--text-2); }
.vp-os .space-switch[data-active="tor"]:has([data-world="clearnet"]:hover) .space-switch__seg[data-world="clearnet"] { color: #06121f; }
.vp-os .space-switch[data-active="tor"]:has([data-world="clearnet"]:hover) .space-switch__seg[data-world="tor"] { color: var(--text-2); }
.vp-os .space-switch__seg:hover .space-switch__ico { transform: scale(1.16); }
.vp-os .space-switch__seg[aria-disabled="true"] { cursor: default; opacity: 0.5; }
@media (prefers-reduced-motion: reduce) {
  .vp-os .space-switch__thumb { transition: background var(--t), box-shadow var(--t); }
  .vp-os .space-switch__seg:hover .space-switch__ico { transform: none; }
}
.vp-os .space-switch__status {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 7px var(--sp-3) 2px;
  font-size: var(--text-xs);
  color: var(--text-2);
}
.vp-os .space-switch__status[hidden] { display: none; }
.vp-os .space-dot {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: var(--r-full);
  background: var(--text-3);
}
.vp-os .space-dot--ok { background: var(--ok); box-shadow: 0 0 6px var(--ok-dim); }
.vp-os .space-dot--warn { background: var(--warn); box-shadow: 0 0 6px var(--warn-dim); }
.vp-os .space-switch__copy {
  padding: 0;
  font: inherit;
  color: var(--brand);
  background: none;
  border: 0;
  cursor: pointer;
  text-decoration: underline;
}
.vp-os .space-switch__copy:hover { color: var(--text); }

.vp-os .sidebar-spacer { margin-top: auto; }

.vp-os .nav-link {
  --nav-accent: var(--brand);
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--text-2);
  transition: background var(--t), color var(--t), transform var(--t-spring);
  text-decoration: none;
}
/* Each destination carries its own premium light accent — the icon glows in it
   on hover, and the active rail lights up in it — so the side panel reads as a
   colourful, legible map instead of one flat blue list. */
.vp-os .nav-link[data-nav="dashboard"]  { --nav-accent: #7dd3fc; } /* sky     */
.vp-os .nav-link[data-nav="growth"]     { --nav-accent: #6ee7b7; } /* emerald */
.vp-os .nav-link[data-nav="optimize"]   { --nav-accent: #c4b5fd; } /* violet  */
.vp-os .nav-link[data-nav="operations"] { --nav-accent: #fcd34d; } /* amber   */
.vp-os .nav-link[data-nav="vayuos"]     { --nav-accent: #f9a8d4; } /* rose    */
.vp-os .nav-link[data-nav="talk"]       { --nav-accent: #5eead4; } /* teal    */
.vp-os .nav-link[data-nav="tor"]        { --nav-accent: #c4b5fd; } /* violet  */
.vp-os .nav-link[data-nav="update"]     { --nav-accent: #93c5fd; } /* blue    */
.vp-os .nav-link[data-nav="profile"]    { --nav-accent: #fda4af; } /* rose    */
.vp-os .nav-link__ico {
  display: inline-flex; flex: 0 0 auto;
  color: var(--text-2);
  transition: transform var(--t-spring), filter var(--t), color var(--t);
}
.vp-os .nav-link__label { flex: 1; min-width: 0; }
.vp-os .nav-link svg { width: 16px; height: 16px; flex-shrink: 0; opacity: 0.85; }
.vp-os .nav-link:hover { background: var(--bg-surface-2); color: var(--text); text-decoration: none; transform: translateX(3px); }
.vp-os .nav-link:hover .nav-link__ico {
  color: var(--nav-accent);
  transform: scale(1.22);
  filter: drop-shadow(0 0 5px var(--nav-accent));
}
.vp-os .nav-link:hover .nav-link__ico svg { opacity: 1; }
.vp-os .nav-link.active { background: var(--bg-surface-2); color: var(--text); }
.vp-os .nav-link.active .nav-link__ico { color: var(--nav-accent); filter: drop-shadow(0 0 4px var(--nav-accent)); }
.vp-os .nav-link.active .nav-link__ico svg { opacity: 1; }
/* Glowing accent rail on the active item. */
.vp-os .nav-link.active::before {
  content: "";
  position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 3px; height: 62%;
  border-radius: 0 3px 3px 0;
  background: var(--nav-accent);
  box-shadow: 0 0 8px var(--nav-accent);
}
@media (prefers-reduced-motion: reduce) {
  .vp-os .nav-link:hover { transform: none; }
  .vp-os .nav-link:hover .nav-link__ico, .vp-os .nav-link.active .nav-link__ico { transform: none; }
}
/* Bulk action bar (Posts manager). */
.vp-os .bulk-bar {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3); margin: var(--sp-3) 0;
  background: var(--bg-surface-2); border: 1px solid var(--border-strong); border-radius: var(--r-md);
}
.vp-os .bulk-bar[hidden] { display: none; }

/* SEO search-result preview (post settings → Meta data & SEO). */
.vp-os .seo-snippet {
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: #fff; max-width: 600px;
}
.vp-os[data-admin-theme="dark"] .seo-snippet,
.vp-os .seo-snippet { background: var(--bg-surface-2); }
.vp-os .seo-snippet__url { font-size: 0.75rem; color: #5f6368; margin-bottom: 2px; word-break: break-all; }
.vp-os .seo-snippet__title { font-size: 1.05rem; color: #1a0dab; line-height: 1.3; }
.vp-os[data-admin-theme="dark"] .seo-snippet__title { color: #8ab4f8; }
.vp-os .seo-snippet__desc { font-size: 0.82rem; color: var(--text-2); line-height: 1.4; margin-top: 2px; }

/* Message-detail key/value rows. */
.vp-os .kv-row { display: flex; gap: var(--sp-3); padding: 6px 0; border-bottom: 1px solid var(--border); }
.vp-os .kv-row:last-child { border-bottom: 0; }
.vp-os .kv-key { flex: 0 0 90px; color: var(--text-2); font-size: var(--text-sm); }
.vp-os .kv-val { flex: 1; min-width: 0; word-break: break-word; }

/* Unread badge (e.g. the Messages item). Sits at the far right of the row. */
.vp-os .nav-badge {
  margin-left: auto; flex-shrink: 0;
  min-width: 18px; height: 18px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.68rem; font-weight: 700; line-height: 1;
  color: #fff; background: var(--brand); border-radius: var(--r-full);
}

.vp-os .sidebar-footer {
  padding: var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}
.vp-os .sidebar-user {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.vp-os .sidebar-user-info { font-size: var(--text-xs); }
.vp-os .sidebar-user-name { font-weight: 600; color: var(--text); }
.vp-os .sidebar-user-role { color: var(--text-3); }

/* ── Topbar ──────────────────────────────────────────────────── */
.vp-os .topbar {
  position: sticky;
  top: 0;
  height: var(--topbar-h);
  background: var(--bg-surface);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: 0 var(--sp-8);
  z-index: 100;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.vp-os .topbar-title {
  font-family: var(--font-head);
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--text);
}
.vp-os .topbar-spacer { flex: 1; }
.vp-os .menu-toggle {
  display: inline-flex;
  width: 36px; height: 36px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  color: var(--text-2);
  align-items: center;
  justify-content: center;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast), box-shadow var(--t-fast), transform var(--t-fast);
}
/* Premium collapse button: the icon-shaped glow (shared topbar rule below) does
   the hover treatment; while the sidebar is collapsed the glyph keeps its sky
   accent so the state stays legible. */
.vp-os.nav-collapsed .menu-toggle { color: var(--ico-glow, var(--brand)); }
/* Desktop: the collapse toggle slides the fixed sidebar off-screen and lets the
   content reclaim the full width — a smooth transition, no scroll lock. */
@media (min-width: 769px) {
  .vp-os.nav-collapsed .sidebar { transform: translateX(-100%); }
  .vp-os.nav-collapsed .main { margin-left: 0; }
}

/* Topbar cmd+k hint */
.vp-os .topbar-cmd {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  font-size: var(--text-xs);
  color: var(--text-3);
  cursor: pointer;
  background: var(--bg-surface-2);
  width: 210px;
  transition: width 0.32s cubic-bezier(0.16, 0.84, 0.44, 1),
    border-color var(--t-fast), color var(--t-fast), box-shadow var(--t), background var(--t-fast);
}
/* Expand on hover/focus into a wider search affordance — the flex spacer to its
   left absorbs the delta, so it grows leftward and the right-side controls stay
   put. A soft brand ring + icon nudge make it feel alive. */
.vp-os .topbar-cmd:hover,
.vp-os .topbar-cmd:focus-visible {
  width: 320px;
  color: var(--text);
  border-color: var(--brand);
  background: var(--bg-surface);
  box-shadow: 0 0 0 3px var(--brand-dim), 0 8px 22px -14px var(--brand-glow);
}
.vp-os .topbar-cmd svg { transition: transform var(--t), color var(--t-fast); }
.vp-os .topbar-cmd:hover svg { transform: scale(1.12) rotate(-6deg); color: var(--brand); }
.vp-os .topbar-cmd-text { flex: 1; text-align: left; }
.vp-os .topbar-cmd kbd { transition: border-color var(--t-fast), color var(--t-fast); }
.vp-os .topbar-cmd:hover kbd { border-color: var(--brand); color: var(--brand); }
@media (prefers-reduced-motion: reduce) {
  .vp-os .topbar-cmd { transition: border-color var(--t-fast), color var(--t-fast); width: 260px; }
  .vp-os .topbar-cmd:hover, .vp-os .topbar-cmd:focus-visible { width: 260px; }
  .vp-os .topbar-cmd:hover svg { transform: none; }
}

/* ── Premium theme toggle (sun / moon / auto) ────────────────────────────────
   The button cycles light → dark → auto; the three glyphs are stacked and the
   active one (keyed off <body data-theme>) rotates + fades in. Auto is the
   default, so an unexpected value still shows a glyph rather than a blank. */
/* No overflow:hidden — it would clip the icon-shaped drop-shadow glow. */
.vp-os .topbar-theme-btn { position: relative; }
.vp-os .theme-ico {
  position: absolute; inset: 0; margin: auto; width: 18px; height: 18px;
  transition: opacity var(--t), transform var(--t);
}
/* Default = auto visible; light/dark glyphs parked (rotated out). */
.vp-os .theme-ico--light, .vp-os .theme-ico--dark { opacity: 0; transform: rotate(-120deg) scale(0.4); }
.vp-os .theme-ico--auto { opacity: 1; transform: rotate(0) scale(1); }
.vp-os[data-theme="light"] .theme-ico--auto,
.vp-os[data-theme="dark"] .theme-ico--auto { opacity: 0; transform: rotate(120deg) scale(0.4); }
.vp-os[data-theme="light"] .theme-ico--light,
.vp-os[data-theme="dark"] .theme-ico--dark { opacity: 1; transform: rotate(0) scale(1); }
@media (prefers-reduced-motion: reduce) {
  .vp-os .theme-ico { transition: opacity var(--t-fast); }
  .vp-os .theme-ico--light, .vp-os .theme-ico--dark,
  .vp-os[data-theme="light"] .theme-ico--auto, .vp-os[data-theme="dark"] .theme-ico--auto { transform: none; }
  .vp-os[data-theme="light"] .theme-ico--light, .vp-os[data-theme="dark"] .theme-ico--dark { transform: none; }
}

/* ── Notification centre (topbar bell + expandable panel) ────────────────────
   The bell replaced the New Post shortcut: a count badge + a dropdown of
   actionable notifications, each a direct link to the page that clears it. */
.vp-os .topbar-notif { position: relative; display: inline-flex; }
.vp-os .topbar-notif__btn { position: relative; color: var(--text-2); }
.vp-os .topbar-notif__btn--active { color: var(--brand); }
/* A soft pulse ring while there are unread notifications. */
.vp-os .topbar-notif__btn--active::after {
  content: ""; position: absolute; inset: -3px; border-radius: var(--r-sm);
  border: 1px solid var(--brand); opacity: 0; animation: vp-notif-pulse 2.4s ease-out infinite;
}
@keyframes vp-notif-pulse {
  0% { opacity: 0.5; transform: scale(0.85); }
  70% { opacity: 0; transform: scale(1.15); }
  100% { opacity: 0; transform: scale(1.15); }
}
@media (prefers-reduced-motion: reduce) {
  .vp-os .topbar-notif__btn--active::after { animation: none; }
}

/* ── Feedback affordance (topbar "report a bug / suggest an improvement") ─────
   One button that opens the composer in feedback mode; on hover/focus a small
   premium popover explains it. Pure CSS, so it works in both consoles. */
.vp-os .topbar-feedback { position: relative; display: inline-flex; }
.vp-os .topbar-feedback__btn { position: relative; color: var(--text-2); }

/* Unified topbar icon buttons (hamburger · feedback · notifications · theme):
   identical 36×36 boxes, each glowing in its OWN premium light colour on hover.
   The glow follows the GLYPH shape (filter: drop-shadow on a transparent button),
   NOT a rectangle — so there is no box ring, just the lit icon, gently enlarged.
   Each button declares its accent via --ico-glow. */
.vp-os .topbar .btn--icon        { --ico-glow: var(--brand); }
.vp-os .menu-toggle              { --ico-glow: #7dd3fc; } /* sky    */
.vp-os .topbar-feedback__btn     { --ico-glow: #fcd34d; } /* amber  */
.vp-os .topbar-notif__btn        { --ico-glow: #f9a8d4; } /* rose   */
.vp-os .topbar-theme-btn         { --ico-glow: #c4b5fd; } /* violet */
.vp-os .topbar .btn--icon:hover, .vp-os .topbar .btn--icon:focus-visible {
  color: var(--ico-glow);
  border-color: transparent;
  background: transparent;
  box-shadow: none;
  transform: translateY(-1px) scale(1.14);
  filter: drop-shadow(0 0 3px var(--ico-glow)) drop-shadow(0 0 8px var(--ico-glow));
}
.vp-os .topbar .btn--icon:active { transform: translateY(0) scale(1.04); }
@media (prefers-reduced-motion: reduce) {
  .vp-os .topbar .btn--icon:hover, .vp-os .topbar .btn--icon:focus-visible { transform: none; }
}
.vp-os .topbar-feedback__pop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  width: 264px; padding: var(--sp-3) var(--sp-4);
  background: var(--bg-surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); box-shadow: 0 18px 46px -18px rgba(2, 8, 20, 0.7);
  opacity: 0; visibility: hidden; transform: translateY(-6px) scale(0.98);
  transform-origin: top right; pointer-events: none;
  transition: opacity 0.16s ease, transform 0.16s cubic-bezier(0.16, 0.84, 0.44, 1), visibility 0.16s;
}
.vp-os .topbar-feedback:hover .topbar-feedback__pop,
.vp-os .topbar-feedback:focus-within .topbar-feedback__pop {
  opacity: 1; visibility: visible; transform: none; pointer-events: auto;
}
.vp-os .topbar-feedback__title { font-weight: 700; font-size: var(--text-sm); margin-bottom: 4px; color: var(--text); }
.vp-os .topbar-feedback__desc { font-size: var(--text-xs); line-height: 1.55; color: var(--text-3); margin: 0 0 8px; }
.vp-os .topbar-feedback__cta { font-size: var(--text-xs); font-weight: 700; color: var(--brand); }
@media (prefers-reduced-motion: reduce) {
  .vp-os .topbar-feedback__pop { transition: opacity 0.12s ease, visibility 0.12s; transform: none; }
}
@media (max-width: 640px) {
  .vp-os .topbar-feedback__pop { position: fixed; top: 56px; right: var(--sp-3); left: var(--sp-3); width: auto; }
}

/* ── Feedback compose banner ─────────────────────────────────────────────── */
.vp-os .vm-feedback-banner {
  margin-bottom: var(--sp-4); padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  background: var(--bg-surface-2); color: var(--text-2);
  font-size: var(--text-sm); line-height: 1.5;
}
.vp-os .topbar-notif__badge {
  position: absolute; top: -3px; right: -3px;
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: var(--r-full);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.62rem; font-weight: 700; line-height: 1; color: #fff;
  background: var(--accent); box-shadow: 0 0 0 2px var(--bg-surface);
}
.vp-os .topbar-notif__panel {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  width: 340px; max-width: calc(100vw - 2 * var(--sp-4));
  background: var(--bg-surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); box-shadow: 0 18px 46px -18px rgba(2, 8, 20, 0.7);
  overflow: hidden;
  transform-origin: top right;
  animation: vp-notif-in 0.16s cubic-bezier(0.16, 0.84, 0.44, 1);
}
@keyframes vp-notif-in { from { opacity: 0; transform: translateY(-6px) scale(0.98); } to { opacity: 1; transform: none; } }
.vp-os .topbar-notif__head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--border);
  font-size: var(--text-sm); font-weight: 700; color: var(--text);
}
.vp-os .topbar-notif__count {
  font-size: var(--text-xs); font-weight: 700; color: var(--accent);
}
.vp-os .topbar-notif__list { max-height: 60vh; overflow-y: auto; padding: var(--sp-2); }
.vp-os .topbar-notif__empty {
  padding: var(--sp-6) var(--sp-4); text-align: center;
  font-size: var(--text-sm); color: var(--text-3);
}
.vp-os .notif-item {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3); border-radius: var(--r-sm);
  text-decoration: none; color: var(--text);
  transition: background var(--t);
}
.vp-os .notif-item:hover { background: var(--bg-surface-2); text-decoration: none; }
.vp-os .notif-item + .notif-item { margin-top: 2px; }
.vp-os .notif-item__icon {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-dim); color: var(--brand);
}
.vp-os .notif-item__icon svg { width: 17px; height: 17px; }
.vp-os .notif-item__icon--mail    { background: var(--brand-dim);  color: var(--brand); }
.vp-os .notif-item__icon--comment { background: var(--accent-dim); color: var(--accent); }
.vp-os .notif-item__icon--message { background: var(--ok-dim);     color: var(--ok); }
.vp-os .notif-item__icon--domain  { background: var(--warn-dim);   color: var(--warn); }
.vp-os .notif-item__icon--update  { background: var(--brand-dim);  color: var(--brand); }
.vp-os .notif-item__body { flex: 1; min-width: 0; }
.vp-os .notif-item__title { display: block; font-size: var(--text-sm); font-weight: 600; color: var(--text); }
.vp-os .notif-item__detail { display: block; margin-top: 1px; font-size: var(--text-xs); color: var(--text-3); }
.vp-os .notif-item__count {
  flex: 0 0 auto; min-width: 20px; height: 20px; padding: 0 6px; border-radius: var(--r-full);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-head); font-variant-numeric: tabular-nums;
  font-size: 0.68rem; font-weight: 700; color: var(--text-2); background: var(--bg-surface-2);
}
@media (max-width: 480px) {
  .vp-os .topbar-notif__panel { position: fixed; top: 56px; right: var(--sp-3); left: var(--sp-3); width: auto; }
}

/* ── Page header ─────────────────────────────────────────────── */
.vp-os .page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--sp-6);
  gap: var(--sp-4);
}
.vp-os .page-header h1 {
  font-size: var(--text-2xl);
  font-weight: 700;
}
.vp-os .page-actions { display: flex; gap: var(--sp-3); align-items: center; }

/* Premium page subtitle under the header (Monetization-console style), shared by
   every /os workspace page. When it directly follows a .page-header the header's
   own bottom margin is tightened so the subtitle tucks in under the title. */
.vp-os .page-sub {
  margin: 0 0 var(--sp-6);
  max-width: 78ch;
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--text-2);
}
.vp-os .page-sub a { color: var(--brand); }
.vp-os .page-header:has(+ .page-sub) { margin-bottom: var(--sp-2); }

/* ── Buttons ─────────────────────────────────────────────────── */
.vp-os .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: 0.5rem 1rem;
  border-radius: var(--r-sm);
  font-size: var(--text-sm);
  font-weight: 500;
  white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast), box-shadow var(--t-fast), transform var(--t-fast);
  cursor: pointer;
  text-decoration: none;
  border: 1px solid transparent;
  line-height: 1;
  -webkit-user-select: none;
  user-select: none;
}
.vp-os .btn:hover { text-decoration: none; transform: translateY(-1px); }
.vp-os .btn:active { transform: translateY(0); }

.vp-os .btn--primary {
  background: var(--brand);
  color: #fff;
  border-color: var(--brand);
}
.vp-os .btn--primary:hover { filter: brightness(1.06); }

.vp-os .btn--accent {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.vp-os .btn--accent:hover { opacity: 0.9; box-shadow: 0 4px 12px var(--accent-dim); }

.vp-os .btn--ghost {
  background: var(--bg-surface-2);
  color: var(--text-2);
  border-color: var(--border);
}
.vp-os .btn--ghost:hover { background: var(--bg-surface-3); color: var(--text); border-color: var(--border-strong); }

.vp-os .btn--danger {
  background: var(--danger-dim);
  color: var(--danger);
  border-color: var(--danger);
}
.vp-os .btn--danger:hover { background: var(--danger); color: #fff; }

.vp-os .btn--sm { padding: 0.35rem 0.75rem; font-size: var(--text-xs); }
.vp-os .btn--lg { padding: 0.75rem 1.5rem; font-size: var(--text-base); }
.vp-os .btn--icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0; border-radius: var(--r-sm);
  border: 1px solid transparent; background: transparent; color: var(--text-2);
  line-height: 0; cursor: pointer; text-decoration: none;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast), box-shadow var(--t-fast), transform var(--t-spring), filter var(--t);
}
/* Every topbar glyph renders at exactly 18×18 regardless of the SVG's own
   width/height attrs — this is what keeps the bell the same size as the rest. */
.vp-os .btn--icon svg { display: block; width: 18px; height: 18px; }
/* The PWA install button stays hidden until the browser reports installability;
   without this, the inline-flex above would defeat the [hidden] attribute. */
.vp-os .btn--icon[hidden] { display: none; }
/* Install app: brand-accented so it reads as an action, with its own hover glow. */
.vp-os .topbar-install-btn { color: var(--brand); --ico-glow: var(--brand); }
.vp-os .btn--icon-lg { width: 42px; height: 42px; padding: 0; }
.vp-os .btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; }

/* ── Payment gateway cards + setup guide (premium) ───────────────────────────
   The connect cards (Stripe · PayPal · BTCPay) share a premium frame with a
   thin accent bar; the crypto card wears a coin-spectrum accent. The collapsible
   "how to turn this on" guide keeps first-run setup obvious without clutter. */
.vp-os .card--pay { position: relative; overflow: hidden; }
.vp-os .card--pay::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--border-strong), transparent);
}
.vp-os .card--crypto::before {
  background: linear-gradient(90deg, #f7931a 0%, #ff6b00 22%, #627eea 58%, #26a17b 100%);
  opacity: 0.95;
}
.vp-os .pay-guide {
  margin: 0 0 var(--sp-4); border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-surface-2);
}
.vp-os .pay-guide > summary {
  cursor: pointer; padding: var(--sp-3) var(--sp-4); list-style: none;
  font-size: var(--text-sm); font-weight: 600; color: var(--text);
  display: flex; align-items: center; gap: 0.5rem;
}
.vp-os .pay-guide > summary::-webkit-details-marker { display: none; }
.vp-os .pay-guide > summary::before { content: "▸"; color: var(--brand); transition: transform var(--t-fast); }
.vp-os .pay-guide[open] > summary::before { transform: rotate(90deg); }
.vp-os .pay-guide__steps {
  margin: 0; padding: 0 var(--sp-5) var(--sp-4) calc(var(--sp-6) + 0.25rem);
  display: grid; gap: 0.55rem; font-size: var(--text-sm); color: var(--text-2); line-height: 1.55;
}
.vp-os .pay-guide__steps code { font-size: 0.82em; }

/* ── Monetization accordions (premium · animated · responsive) ───────────────
   Each option collapses to a summary row (icon · title · one-line subtitle ·
   status chip); expanding reveals the existing card, chromeless, with a smooth
   fade/slide and a rotating chevron. Native <details> — no JS, CSP-safe. */
.vp-os .mon-stack { display: grid; gap: var(--sp-3); margin-bottom: var(--sp-6); }
.vp-os .mon-acc {
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-surface);
  overflow: hidden; transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.vp-os .mon-acc[open] { border-color: var(--border-strong); box-shadow: var(--sh-sm); }
.vp-os .mon-acc__sum {
  display: flex; align-items: center; gap: var(--sp-3); cursor: pointer; list-style: none;
  padding: var(--sp-3) var(--sp-4); user-select: none;
  transition: background var(--t-fast);
}
.vp-os .mon-acc__sum::-webkit-details-marker { display: none; }
.vp-os .mon-acc__sum:hover { background: var(--bg-surface-2); }
.vp-os .mon-acc__ic {
  flex: none; width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center;
  font-size: 1.05rem; border-radius: var(--r-sm); background: var(--bg-surface-2); border: 1px solid var(--border);
}
.vp-os .mon-acc__head { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.vp-os .mon-acc__title { font-weight: 650; font-size: var(--text-sm); color: var(--text); }
.vp-os .mon-acc__sub { font-size: var(--text-xs); color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vp-os .mon-acc__chev { flex: none; color: var(--text-3); transition: transform var(--t-fast); }
.vp-os .mon-acc[open] .mon-acc__chev { transform: rotate(180deg); }
.vp-os .mon-acc[open] .mon-acc__sum { border-bottom: 1px solid var(--border); }
.vp-os .mon-acc__body { padding: var(--sp-4); animation: mon-reveal 0.28s cubic-bezier(0.16, 0.84, 0.44, 1); }
@keyframes mon-reveal { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
/* The wrapped card renders chromeless — the accordion is the frame — and its
   duplicate title + accent bar are hidden (the summary already names it). */
.vp-os .mon-acc__body > .card { border: 0; background: transparent; box-shadow: none; padding: 0; margin: 0; }
.vp-os .mon-acc__body > .card::before { display: none; }
.vp-os .mon-acc__body > .card > .settings-block-title:first-child { display: none; }
/* VayuTor cards use .card-title; hide it inside an accordion (the title is in the summary). */
.vp-os .mon-acc__body > .card > .card-title:first-child { display: none; }
.vp-os .mon-chip {
  flex: none; font-size: var(--text-xs); font-weight: 600; padding: 3px 9px; border-radius: var(--r-full);
  border: 1px solid var(--border); color: var(--text-3); background: var(--bg-surface-2); white-space: nowrap;
}
.vp-os .mon-chip--on { color: #34d399; border-color: rgba(52, 211, 153, 0.4); background: rgba(52, 211, 153, 0.12); }
.vp-os .mon-chip--off { color: var(--text-3); }
@media (prefers-reduced-motion: reduce) { .vp-os .mon-acc__body { animation: none; } }

/* ── Posts manager — premium per-post accordion cards ────────────────────────
   Each post is a collapsible card (reusing the .mon-acc frame). The bulk-select
   checkbox lives OUTSIDE the <summary> (column 1 of the row grid) so ticking it
   never toggles the card; tapping the card reveals only that post's actions. */
.vp-os .post-list-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-3);
}
.vp-os .post-selectall {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--text-sm); color: var(--text-2); cursor: pointer;
}
.vp-os .post-stack { margin-bottom: 0; }
.vp-os .post-row { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-3); align-items: start; }
.vp-os .post-acc { min-width: 0; }
.vp-os .post-acc__check { margin-top: 0.9rem; flex: none; cursor: pointer; }
.vp-os .post-acc__status { flex: none; }
.vp-os .post-acc__body { display: grid; gap: var(--sp-3); }
.vp-os .post-acc__tags { display: flex; flex-wrap: wrap; gap: 4px; }
.vp-os .post-acc__meta-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.vp-os .post-acc__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
@media (max-width: 560px) {
  .vp-os .mon-acc__sub { white-space: normal; }
  .vp-os .mon-chip { display: none; }
}

/* ── Update & Backup — premium hero ──────────────────────────────────────────
   The software-update panel: a glassy hero with a drifting accent aura, an
   Installed → Latest version flow with an arrow, and a live status chip. */
.vp-os .upd-hero {
  position: relative;
  border: 1px solid var(--card-border);
  border-radius: var(--r-md);
  background: var(--card-bg);
  box-shadow: var(--sh-sm);
  padding: var(--sp-6);
  margin-bottom: var(--sp-6);
}
.vp-os .upd-hero__aura { display: none; }
.vp-os .upd-hero__head { position: relative; }
.vp-os .upd-hero__badge {
  display: inline-block; font: 700 var(--text-xs)/1 var(--font-mono);
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--brand);
  background: var(--brand-dim); border: 1px solid var(--brand-dim);
  padding: 5px 10px; border-radius: var(--r-full);
}
.vp-os .upd-hero__lead { position: relative; margin-top: var(--sp-3); max-width: 62ch; color: var(--text-2); font-size: var(--text-sm); line-height: 1.6; }
.vp-os .upd-vers {
  position: relative;
  display: flex; align-items: stretch; flex-wrap: wrap; gap: var(--sp-3);
  margin: var(--sp-5) 0 var(--sp-2);
}
.vp-os .upd-ver {
  flex: 1 1 8rem; min-width: 8rem;
  display: flex; flex-direction: column; gap: 6px;
  padding: var(--sp-4);
  background: var(--bg-surface-2);
  border: 1px solid var(--card-border);
  border-radius: var(--r-md);
}
.vp-os .upd-ver__label { font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-3); font-weight: 600; }
.vp-os .upd-ver__num { font-family: var(--font-head); font-size: var(--text-2xl); font-weight: 700; color: var(--text); letter-spacing: -0.02em; }
.vp-os .upd-ver__num--latest { color: var(--brand); }
.vp-os .upd-ver__arrow { display: flex; align-items: center; color: var(--text-3); flex: 0 0 auto; }
.vp-os .upd-ver--status { flex: 1 1 10rem; }
.vp-os .upd-status {
  align-self: flex-start;
  font-weight: 650; font-size: var(--text-sm); color: var(--text-2);
  padding: 4px 10px; border-radius: var(--r-full);
  border: 1px solid var(--card-border); background: var(--bg-surface);
}
.vp-os .upd-status[data-state="uptodate"] { color: var(--ok); border-color: var(--ok-dim); background: var(--ok-dim); }
.vp-os .upd-status[data-state="available"] { color: var(--brand); border-color: var(--brand-dim); background: var(--brand-dim); }
.vp-os .upd-status[data-state="error"] { color: var(--danger); border-color: var(--danger-dim); background: var(--danger-dim); }
.vp-os .upd-opts { position: relative; display: grid; gap: 4px; margin: var(--sp-4) 0; }
.vp-os .upd-check { display: inline-flex; align-items: center; gap: 10px; font-size: var(--text-sm); color: var(--text); cursor: pointer; }
.vp-os .upd-check input { width: 16px; height: 16px; accent-color: var(--brand); flex: 0 0 auto; }
.vp-os .upd-opt-note { font-size: var(--text-xs); color: var(--text-3); line-height: 1.5; margin: 0 0 8px 26px; }
.vp-os .upd-actions { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin-top: var(--sp-4); }
.vp-os .upd-file { max-width: 22rem; }
@media (max-width: 560px) {
  .vp-os .upd-ver__arrow { transform: rotate(90deg); align-self: center; }
  .vp-os .upd-vers { flex-direction: column; }
}

/* ── Cards ───────────────────────────────────────────────────── */
.vp-os .card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--r);
  padding: var(--sp-5);
  box-shadow: var(--sh-sm);
}
.vp-os .card--hover { transition: border-color var(--t), transform var(--t), box-shadow var(--t); }
.vp-os .card--hover:hover { border-color: var(--border-strong); transform: translateY(-2px); box-shadow: var(--sh); }
.vp-os .card--glass {
  background: var(--bg-glass);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
}
.vp-os .card-title {
  font-family: var(--font-head);
  font-size: var(--text-base);
  font-weight: 600;
  margin-bottom: var(--sp-4);
  color: var(--text);
}
.vp-os .card-subtitle {
  font-size: var(--text-xs);
  color: var(--text-3);
  margin-top: calc(-1 * var(--sp-3));
  margin-bottom: var(--sp-4);
}

/* Stat cards */
.vp-os .stat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
}
.vp-os .stat-card {
  position: relative;
  background: var(--bg-surface); /* fallback for engines without color-mix */
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--bg-surface-2) 55%, var(--bg-surface)) 0%, var(--bg-surface) 60%);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  overflow: hidden;
  transition: border-color var(--t), box-shadow var(--t), transform var(--t);
}
/* Hairline top-light: a 1px gradient seam that catches the eye like a screen
   bezel — the "futuristic panel" cue, done with a pseudo-element so it costs
   nothing to paint and never shifts layout. */
.vp-os .stat-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-strong) 20%, var(--brand-glow) 50%, var(--border-strong) 80%, transparent);
  opacity: 0.5;
  transition: opacity var(--t);
}
.vp-os .stat-card:hover {
  border-color: var(--border-strong);
  box-shadow: 0 8px 28px -12px rgba(2, 8, 20, 0.55);
  transform: translateY(-2px);
}
.vp-os .stat-card:hover::before { opacity: 1; }
/* Attention variant: same panel, warm seam + value. Used where a number is not
   merely informational — full-control keys granted, a dedicated host that a
   proxy is answering for — so what needs a decision reads at a glance instead of
   being one more figure in a row. */
.vp-os .stat-card--warn { border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); }
.vp-os .stat-card--warn::before {
  background: linear-gradient(90deg, transparent, var(--warn) 50%, transparent);
  opacity: 0.75;
}
.vp-os .stat-card--warn .stat-card__value { color: var(--warn); }

/* ── Connector detail panel (VayuMCP) ──────────────────────────────────────
   A connector's facts as label/value rows rather than a table: the values are
   short and heterogeneous (a masked key, a relative time, a count), so a grid
   reads faster than columns and reflows cleanly on a phone. */
.vp-os .cx-details { display: flex; flex-direction: column; gap: .35rem; margin-bottom: .85rem; }
.vp-os .cx-detail {
  display: grid;
  grid-template-columns: minmax(6.5rem, 9rem) 1fr;
  gap: .75rem;
  align-items: baseline;
  padding: .3rem 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
}
.vp-os .cx-detail:last-child { border-bottom: 0; }
.vp-os .cx-detail__k { font-size: .82rem; color: var(--text-muted); }
.vp-os .cx-detail__v { font-size: .9rem; word-break: break-word; }
.vp-os .cx-cap {
  display: inline-block;
  padding: .1rem .4rem;
  margin: 0 .25rem .25rem 0;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-surface-2);
}
@media (max-width: 30rem) {
  .vp-os .cx-detail { grid-template-columns: 1fr; gap: .15rem; }
}
@media (prefers-reduced-motion: reduce) {
  .vp-os .stat-card { transition: border-color var(--t), box-shadow var(--t); }
  .vp-os .stat-card:hover { transform: none; }
}
.vp-os .stat-card__top { display: flex; justify-content: space-between; align-items: flex-start; }
.vp-os .stat-card__label { font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-3); }
.vp-os .stat-card__icon { width: 32px; height: 32px; border-radius: var(--r-sm); display: flex; align-items: center; justify-content: center; transition: transform var(--t); }
.vp-os .stat-card:hover .stat-card__icon { transform: scale(1.08); }
.vp-os .stat-card__icon--brand { background: var(--brand-dim); color: var(--brand); }
.vp-os .stat-card__icon--accent { background: var(--accent-dim); color: var(--accent); }
.vp-os .stat-card__icon--ok { background: var(--ok-dim); color: var(--ok); }
.vp-os .stat-card__icon--warn { background: var(--warn-dim); color: var(--warn); }
.vp-os .stat-card__value {
  font-family: var(--font-head);
  font-size: var(--text-3xl);
  font-weight: 700;
  color: var(--text);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
/* Word-valued stat (e.g. an active theme name) — smaller so a long name fits. */
.vp-os .stat-card__value--sm { font-size: var(--text-xl); line-height: 1.15; word-break: break-word; }
.vp-os .stat-card__bottom { display: flex; align-items: center; justify-content: space-between; }
.vp-os .stat-card__trend { font-size: var(--text-xs); font-weight: 600; }
.vp-os .stat-card__trend--up { color: var(--ok); }
.vp-os .stat-card__trend--down { color: var(--danger); }
.vp-os .stat-card__sparkline { display: block; }

/* ── Dashboard workspace (ADR-0141 dashboard redesign) ─────────────────
   The content areas — Posts, Pages, Comments, Messages, Media, New Post,
   Website — are surfaced on the dashboard itself as large clickable cards
   with live counts and notification badges, so the sidebar stays focused on
   the broader system areas. Each card is a first-class navigation target. */
.vp-os .section-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
  margin: 0 0 var(--sp-4);
}
.vp-os .section-head__title {
  font-family: var(--font-head); font-size: var(--text-lg); font-weight: 700;
  color: var(--text); letter-spacing: -0.01em;
}
.vp-os .section-head__hint { font-size: var(--text-xs); color: var(--text-3); }

.vp-os .work-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
}
.vp-os .work-card {
  position: relative;
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-surface);
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg-surface-2) 55%, var(--bg-surface)) 0%, var(--bg-surface) 60%);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  text-decoration: none;
  overflow: hidden;
  transition: border-color var(--t), box-shadow var(--t), transform var(--t);
}
.vp-os .work-card::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-strong) 20%, var(--brand-glow) 50%, var(--border-strong) 80%, transparent);
  opacity: 0.5; transition: opacity var(--t);
}
.vp-os .work-card:hover {
  border-color: var(--border-strong);
  box-shadow: 0 8px 28px -12px rgba(2, 8, 20, 0.55);
  transform: translateY(-2px); text-decoration: none;
}
.vp-os .work-card:hover::before { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .vp-os .work-card { transition: border-color var(--t), box-shadow var(--t); }
  .vp-os .work-card:hover { transform: none; }
}
.vp-os .work-card__icon {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-dim); color: var(--brand);
  transition: transform var(--t);
}
.vp-os .work-card:hover .work-card__icon { transform: scale(1.08); }
.vp-os .work-card__icon svg { width: 20px; height: 20px; }
.vp-os .work-card__icon--accent { background: var(--accent-dim); color: var(--accent); }
.vp-os .work-card__body { flex: 1; min-width: 0; }
.vp-os .work-card__title {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--text-sm); font-weight: 600; color: var(--text);
}
.vp-os .work-card__count {
  font-family: var(--font-head); font-variant-numeric: tabular-nums;
  font-size: var(--text-sm); font-weight: 700; color: var(--text-2);
}
.vp-os .work-card__desc { margin-top: 2px; font-size: var(--text-xs); color: var(--text-3); }
.vp-os .work-card__badge {
  min-width: 18px; height: 18px; padding: 0 6px; border-radius: var(--r-full);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.66rem; font-weight: 700; line-height: 1; color: #fff; background: var(--accent);
}
.vp-os .work-card__arrow {
  flex: 0 0 auto; color: var(--text-3); opacity: 0; transform: translateX(-4px);
  transition: opacity var(--t), transform var(--t);
}
.vp-os .work-card:hover .work-card__arrow { opacity: 1; transform: translateX(0); }

/* Anonymous-world status card — the .onion indicator moved off the sidebar
   toggle and onto the dashboard, where there is room to show it properly. */
.vp-os .world-card {
  display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5); margin-bottom: var(--sp-6);
  background: linear-gradient(120deg, var(--brand-dim), transparent 70%);
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
}
.vp-os .world-card__dot {
  flex: 0 0 auto; width: 9px; height: 9px; border-radius: var(--r-full);
  background: var(--ok); box-shadow: 0 0 8px var(--ok-dim);
}
.vp-os .world-card__dot--warn { background: var(--warn); box-shadow: 0 0 8px var(--warn-dim); }
.vp-os .world-card__text { flex: 1; min-width: 12rem; }
.vp-os .world-card__title { font-size: var(--text-sm); font-weight: 700; color: var(--text); }
.vp-os .world-card__addr {
  margin-top: 2px; font-family: var(--font-mono); font-size: var(--text-xs);
  color: var(--text-2); word-break: break-all;
}
.vp-os .world-card__actions { display: flex; align-items: center; gap: var(--sp-2); flex-shrink: 0; }

@media (max-width: 1100px) { .vp-os .work-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .vp-os .work-grid { grid-template-columns: 1fr; } }

/* ── VayuDomains — premium domain cards & per-site manager (ADR-0141) ────────
   The domain registry is presented as a responsive grid of premium cards with a
   staggered entrance, replacing the Stage-1 flat table. Each secondary card
   links to its own per-site manager (also surfaced from the Optimize hub) where
   its branding, content and lifecycle are controlled. Shared by both worlds — in
   the Tor world the hosts are .onion addresses and the same cards render. */
.vp-os .domain-grid {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-4); margin-bottom: var(--sp-5);
}
@media (max-width: 900px) { .vp-os .domain-grid { grid-template-columns: 1fr; } }

.vp-os .domain-card {
  position: relative;
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-5);
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg-surface-2) 55%, var(--bg-surface)) 0%, var(--bg-surface) 60%);
  border: 1px solid var(--border); border-radius: var(--r-md);
  overflow: hidden; opacity: 0;
  animation: vp-dom-in 0.5s cubic-bezier(0.16, 0.84, 0.44, 1) forwards;
  transition: border-color var(--t), box-shadow var(--t), transform var(--t);
}
.vp-os .domain-card::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--brand-glow) 50%, transparent);
  opacity: 0.6;
}
.vp-os .domain-card:hover {
  border-color: var(--border-strong);
  box-shadow: 0 10px 30px -14px rgba(2, 8, 20, 0.6);
  transform: translateY(-2px);
}
.vp-os .domain-card--primary {
  border-color: var(--border-strong);
  background: linear-gradient(135deg, var(--brand-dim), transparent 62%);
}
/* Staggered entrance — CSP-safe (no inline styles), driven by document order. */
.vp-os .domain-card:nth-child(1) { animation-delay: 0.02s; }
.vp-os .domain-card:nth-child(2) { animation-delay: 0.07s; }
.vp-os .domain-card:nth-child(3) { animation-delay: 0.12s; }
.vp-os .domain-card:nth-child(4) { animation-delay: 0.17s; }
.vp-os .domain-card:nth-child(5) { animation-delay: 0.22s; }
.vp-os .domain-card:nth-child(6) { animation-delay: 0.27s; }
.vp-os .domain-card:nth-child(n+7) { animation-delay: 0.3s; }
@keyframes vp-dom-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .vp-os .domain-card { animation: none; opacity: 1; }
  .vp-os .domain-card:hover { transform: none; }
}

.vp-os .domain-card__head { display: flex; align-items: flex-start; gap: var(--sp-3); }
.vp-os .domain-card__icon {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-dim); color: var(--brand);
}
.vp-os .domain-card__icon svg { width: 19px; height: 19px; }
.vp-os .domain-card__id { flex: 1; min-width: 0; }
.vp-os .domain-card__host {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600;
  color: var(--text); word-break: break-all;
}
.vp-os .domain-card__serves { margin-top: 3px; font-size: var(--text-xs); color: var(--text-3); }

.vp-os .domain-card__stats { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.vp-os .domain-stat {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 3px 9px; border-radius: var(--r-full);
  background: var(--bg-surface-2); border: 1px solid var(--border);
  font-size: var(--text-xs); color: var(--text-2);
}
.vp-os .domain-stat b {
  font-family: var(--font-head); font-variant-numeric: tabular-nums;
  color: var(--text); font-weight: 700;
}

.vp-os .domain-card__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.vp-os .domain-card__actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin-top: auto; padding-top: var(--sp-3); border-top: 1px solid var(--border);
}

/* Per-site manager hero (the /os/domains/{id} surface reached from Optimize). */
.vp-os .site-hero {
  display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap;
  padding: var(--sp-5); margin-bottom: var(--sp-5);
  background: linear-gradient(120deg, var(--brand-dim), transparent 70%);
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
}
.vp-os .site-hero__icon {
  flex: 0 0 auto; width: 46px; height: 46px; border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  background: var(--brand); color: #fff;
}
.vp-os .site-hero__icon svg { width: 22px; height: 22px; }
.vp-os .site-hero__body { flex: 1; min-width: 12rem; }
.vp-os .site-hero__host {
  font-family: var(--font-mono); font-size: var(--text-lg); font-weight: 700;
  color: var(--text); word-break: break-all;
}
.vp-os .site-hero__sub { margin-top: 4px; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); font-size: var(--text-xs); color: var(--text-2); }
.vp-os .site-hero__actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

/* ── Grid system ─────────────────────────────────────────────── */
.vp-os .grid { display: grid; gap: var(--sp-4); }
.vp-os .grid-2 { grid-template-columns: repeat(2, 1fr); }
.vp-os .grid-3 { grid-template-columns: repeat(3, 1fr); }
.vp-os .grid-4 { grid-template-columns: repeat(4, 1fr); }

/* ── Badges ──────────────────────────────────────────────────── */
.vp-os .badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 0.2em 0.6em;
  border-radius: var(--r-full);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  white-space: nowrap;
}
.vp-os .badge--ok      { background: var(--ok-dim);     color: var(--ok); }
.vp-os .badge--warn    { background: var(--warn-dim);   color: var(--warn); }
.vp-os .badge--danger  { background: var(--danger-dim); color: var(--danger); }
/* Pending device approvals (ADR-0129) must read as "action needed": the warn
   palette plus a solid ring so the chip stands out from a plain warn badge.
   Colors are re-tokened per theme below so the amber keeps contrast on light
   backgrounds too. */
.vp-os .badge--pending {
  background: var(--pending-dim, var(--warn-dim));
  color: var(--pending, var(--warn));
  box-shadow: inset 0 0 0 1px var(--pending, var(--warn));
  font-weight: 700;
}
.vp-os { --pending: #fbbf24; --pending-dim: rgba(251, 191, 36, 0.16); }
.vp-os[data-theme="light"] { --pending: #92400e; --pending-dim: #fef3c7; }
@media (prefers-color-scheme: light) {
  .vp-os[data-theme="auto"] { --pending: #92400e; --pending-dim: #fef3c7; }
}
.vp-os .badge--info    { background: var(--info-dim);   color: var(--info); }
.vp-os .badge--brand   { background: var(--brand-dim);  color: var(--brand); }
.vp-os .badge--accent  { background: var(--accent-dim); color: var(--accent); }
.vp-os .badge--muted   { background: var(--bg-surface-3); color: var(--text-3); }
.vp-os .badge--free    { background: var(--bg-surface-3); color: var(--text-2); }
.vp-os .badge--paid    { background: var(--accent-dim);   color: var(--accent); }

/* ── Space-mode badge (ADR-0141) ─────────────────────────────────
   Persistent topbar indicator of the world this whole install controls:
   a CLEARNET Space (public HTTPS domain, green) or a TOR Space (anonymous
   .onion, purple). Fixed per install by VAYUOS_MODE — a status label, not a
   toggle — so the two worlds are never confused when operating either. The
   leading dot is a ::before pseudo (no inline style; strict admin CSP). */
.vp-os .space-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.2em 0.65em;
  border-radius: var(--r-full);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.vp-os .space-badge::before {
  content: "";
  width: 0.5em;
  height: 0.5em;
  border-radius: var(--r-full);
  background: currentColor;
  flex: none;
}
.vp-os .space-badge--clearnet { background: var(--ok-dim);     color: var(--ok); }
.vp-os .space-badge--tor      { background: var(--accent-dim); color: var(--accent); }

/* ── Tor Space palette (ADR-0141) ────────────────────────────────
   While the Anonymous Tor Space is live, data-space="tor" on the shell
   repaints the accent/brand tokens purple, so the WHOLE VayuOS chrome
   (active nav, brand, buttons, the sidebar rail) signals the Tor world at a
   glance. Purely a colour shift — layout and the strict CSP are untouched. */
.vp-os[data-space="tor"] {
  --brand:      #a855f7;
  --brand-dim:  rgba(168, 85, 247, 0.18);
  --brand-glow: rgba(168, 85, 247, 0.28);
  --accent:     #a855f7;
  --accent-dim: rgba(168, 85, 247, 0.18);
}
.vp-os[data-space="tor"] .sidebar {
  border-right-color: var(--accent-dim);
  box-shadow: inset -1px 0 0 var(--accent-dim);
}

/* ── Form elements ───────────────────────────────────────────── */
.vp-os .field { display: flex; flex-direction: column; gap: var(--sp-2); }
.vp-os .field-label {
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--text-2);
}
.vp-os .field-hint {
  font-size: var(--text-xs);
  color: var(--text-3);
}

.vp-os .input, .vp-os .select, .vp-os .textarea {
  width: 100%;
  padding: 0.5625rem 0.875rem;
  background: var(--bg-surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-size: var(--text-sm);
  color: var(--text);
  outline: none;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
  -webkit-appearance: none;
}
.vp-os .input::placeholder, .vp-os .textarea::placeholder { color: var(--text-3); }
.vp-os .input:focus, .vp-os .select:focus, .vp-os .textarea:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-glow);
}
.vp-os .input--sm { padding: 0.375rem 0.75rem; font-size: var(--text-xs); }
.vp-os .input--error { border-color: var(--danger); }
.vp-os .textarea { resize: vertical; min-height: 100px; }
.vp-os .select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%238ba4c4' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 0.75rem center; padding-right: 2.25rem; cursor: pointer; }

/* Toggle switch (CSS-only) */
.vp-os .toggle {
  -webkit-appearance: none;
  appearance: none;
  width: 40px; height: 22px;
  background: var(--bg-surface-3);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  cursor: pointer;
  position: relative;
  transition: background var(--t), border-color var(--t);
  flex-shrink: 0;
}
.vp-os .toggle::before {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--text-3);
  transition: transform var(--t), background var(--t);
}
.vp-os .toggle:checked { background: var(--brand); border-color: var(--brand); }
.vp-os .toggle:checked::before { transform: translateX(18px); background: #fff; }

/* ── Chips / Tags ────────────────────────────────────────────── */
.vp-os .chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 0.25em 0.65em;
  border-radius: var(--r-full);
  font-size: var(--text-xs);
  font-weight: 500;
  background: var(--bg-surface-3);
  color: var(--text-2);
  border: 1px solid var(--border);
  white-space: nowrap;
}
.vp-os .chip--brand { background: var(--brand-dim); color: var(--brand); border-color: transparent; }
.vp-os .chip--removable button { width: 14px; height: 14px; opacity: 0.7; display: flex; align-items: center; justify-content: center; }
.vp-os .chip--removable button:hover { opacity: 1; }

/* ── Progress ────────────────────────────────────────────────── */
.vp-os .progress { height: 6px; background: var(--bg-surface-3); border-radius: var(--r-full); overflow: hidden; }
.vp-os .progress__bar { height: 100%; background: var(--brand); border-radius: var(--r-full); transition: width 0.5s ease; }
.vp-os .progress__bar--warn { background: var(--warn); }
.vp-os .progress__bar--danger { background: var(--danger); }
.vp-os .progress__bar--ok { background: var(--ok); }

/* Sparkline — server-rendered SVG line chart, colour via currentColor (no inline style) */
.vp-os .sparkline-wrap { margin-top: var(--sp-3); color: var(--brand); height: 64px; }
.vp-os .sparkline { width: 100%; height: 100%; display: block; }
.vp-os .sparkline__line { fill: none; stroke: currentColor; stroke-width: 2; vector-effect: non-scaling-stroke; stroke-linejoin: round; stroke-linecap: round; }
.vp-os .sparkline__area { fill: var(--brand-dim); stroke: none; opacity: 0.5; }

/* Trend area chart — the dashboard's 14-day publishing trend. Server-rendered
   SVG; every colour arrives via these classes (no inline styles, CSP-safe).
   The hover layer is pure CSS: each invisible per-day hit column reveals that
   day's dot + value tooltip. Scales with the card at a fixed aspect ratio. */
.vp-os .trendchart-wrap { margin-top: var(--sp-3); color: var(--brand); }
.vp-os .trendchart { width: 100%; height: auto; display: block; }
.vp-os .trendchart .tc-grid { stroke: var(--border); stroke-width: 1; stroke-dasharray: 2 4; }
.vp-os .trendchart .tc-base { stroke: var(--border-strong); stroke-width: 1; }
.vp-os .trendchart .tc-area { fill: url(#vpTrendGrad); stroke: none; }
.vp-os .trendchart .tc-grad-a { stop-color: currentColor; stop-opacity: 0.22; }
.vp-os .trendchart .tc-grad-b { stop-color: currentColor; stop-opacity: 0; }
.vp-os .trendchart .tc-line { fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.vp-os .trendchart .tc-end { fill: currentColor; stroke: var(--bg-surface); stroke-width: 2; }
.vp-os .trendchart .tc-ylabel, .vp-os .trendchart .tc-tick { fill: var(--text-3); font-size: 9px; font-family: var(--font-body); }
.vp-os .trendchart .tc-tick--start { text-anchor: start; }
.vp-os .trendchart .tc-tick--mid { text-anchor: middle; }
.vp-os .trendchart .tc-tick--end { text-anchor: end; }
.vp-os .trendchart .tc-peak { fill: var(--text-2); font-size: 10px; font-weight: 600; text-anchor: middle; font-family: var(--font-body); }
.vp-os .trendchart .tc-endlabel { fill: var(--text); font-size: 11px; font-weight: 700; text-anchor: end; font-family: var(--font-head); }
.vp-os .trendchart .tc-hit { fill: transparent; }
.vp-os .trendchart .tc-dot { fill: currentColor; stroke: var(--bg-surface); stroke-width: 1.5; opacity: 0; transition: opacity var(--t-fast); }
.vp-os .trendchart .tc-tip { opacity: 0; transition: opacity var(--t-fast); pointer-events: none; }
.vp-os .trendchart .tc-tip rect { fill: var(--bg-surface-3); stroke: var(--border-strong); stroke-width: 1; }
.vp-os .trendchart .tc-tip text { fill: var(--text); font-size: 10px; text-anchor: middle; font-family: var(--font-body); }
.vp-os .trendchart .tc-day:hover .tc-dot, .vp-os .trendchart .tc-day:hover .tc-tip { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .vp-os .trendchart .tc-dot, .vp-os .trendchart .tc-tip { transition: none; }
}

/* Width utilities */
.vp-os .w-0{width:0%}.vp-os .w-5{width:5%}.vp-os .w-10{width:10%}
.vp-os .w-15{width:15%}.vp-os .w-20{width:20%}.vp-os .w-25{width:25%}
.vp-os .w-30{width:30%}.vp-os .w-35{width:35%}.vp-os .w-40{width:40%}
.vp-os .w-45{width:45%}.vp-os .w-50{width:50%}.vp-os .w-55{width:55%}
.vp-os .w-60{width:60%}.vp-os .w-65{width:65%}.vp-os .w-70{width:70%}
.vp-os .w-75{width:75%}.vp-os .w-80{width:80%}.vp-os .w-85{width:85%}
.vp-os .w-90{width:90%}.vp-os .w-95{width:95%}.vp-os .w-100{width:100%}

/* ── Inline magnitude bars (analytics) ───────────────────────────
   A number stacked over a thin proportional bar, so a column of counts reads
   as a tiny bar chart at a glance. The fill width comes from a .w-N class
   (CSP-safe — no inline styles); this rule only sets the track/fill look, never
   width, so it never fights the width utilities. Folds cleanly into the
   stacked mobile card layout. */
.vp-os .vs-barcell { display: flex; flex-direction: column; gap: 5px; min-width: 72px; }
.vp-os .vs-barcell__n { font-variant-numeric: tabular-nums; font-weight: 600; line-height: 1; }
.vp-os .vs-bar { display: block; width: 100%; height: 4px; border-radius: var(--r-full); background: var(--bg-surface-3); overflow: hidden; }
.vp-os .vs-bar__fill { display: block; height: 100%; min-width: 2px; border-radius: var(--r-full); background: linear-gradient(90deg, var(--brand), var(--accent)); }
/* On the stacked mobile card, the value+bar sits right-aligned opposite its
   data-label — let the bar take the available width so it stays readable. */
@media (max-width: 640px) {
  .vp-os .table-wrap.vp-stackable .vs-barcell { align-items: flex-end; min-width: 0; flex: 1; }
  .vp-os .table-wrap.vp-stackable .vs-bar { max-width: 160px; }
}

/* ── Skeleton loaders ────────────────────────────────────────── */
@keyframes vp3-shimmer {
  0%   { background-position: -400px 0; }
  100% { background-position: 400px 0; }
}
.vp-os .skeleton {
  background: linear-gradient(90deg, var(--bg-surface-2) 25%, var(--bg-surface-3) 50%, var(--bg-surface-2) 75%);
  background-size: 800px 100%;
  animation: vp3-shimmer 1.8s infinite linear;
  border-radius: var(--r-sm);
}
.vp-os .skeleton--text { height: 14px; }
.vp-os .skeleton--title { height: 24px; }
.vp-os .skeleton--card { height: 96px; border-radius: var(--r); }
.vp-os .skeleton--avatar { width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0; }

/* ── Tables ──────────────────────────────────────────────────── */
.vp-os .table-wrap { overflow-x: auto; }
.vp-os .table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
.vp-os .table th {
  text-align: left;
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-3);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.vp-os .table td {
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--border);
  color: var(--text-2);
  vertical-align: middle;
}
.vp-os .table tr:last-child td { border-bottom: none; }
.vp-os .table tbody tr { transition: background var(--t-fast); }
.vp-os .table tbody tr:hover { background: var(--bg-surface-2); }
.vp-os .table .row-title { font-weight: 500; color: var(--text); }
.vp-os .table .row-title a { color: var(--text); text-decoration: none; }
.vp-os .table .row-title a:hover { color: var(--brand); }
.vp-os .table .row-meta { font-size: var(--text-xs); color: var(--text-3); margin-top: 2px; }
.vp-os .table .row-actions { white-space: nowrap; text-align: right; }
.vp-os .table-empty { text-align: center; padding: var(--sp-10); color: var(--text-3); font-size: var(--text-sm); }

/* Search row */
.vp-os .toolbar-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}
.vp-os .card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}
.vp-os .pf-head { display: flex; align-items: center; gap: var(--sp-4); }
/* Profile avatar preview: a fixed, cropped circular thumbnail regardless of the
   source image's intrinsic dimensions (large uploads are scaled down + cropped,
   never shown at full size). */
.vp-os .pf-avatar-frame {
  width: 72px; height: 72px;
  border-radius: var(--r-full);
  overflow: hidden;
  flex-shrink: 0;
  border: 1px solid var(--border);
  background: var(--bg-surface-3);
  display: flex; align-items: center; justify-content: center;
}
.vp-os .pf-avatar {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.vp-os .pf-avatar-empty { font-size: var(--text-xs); color: var(--text-3); padding: 0 6px; text-align: center; }
.vp-os .search-input { max-width: 320px; }

/* ── Avatar ──────────────────────────────────────────────────── */
.vp-os .avatar {
  width: 36px; height: 36px;
  border-radius: 50%;
  overflow: hidden;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-sm);
  font-weight: 700;
  font-family: var(--font-head);
}
.vp-os .avatar--sm { width: 28px; height: 28px; font-size: var(--text-xs); }
.vp-os .avatar--brand { background: var(--brand-dim); color: var(--brand); }
.vp-os .avatar--lg { width: 48px; height: 48px; font-size: var(--text-lg); }
/* Image avatars: fill the circular box and crop, never distort. */
.vp-os img.avatar { object-fit: cover; }
/* The sidebar footer user card links to the profile editor. */
.vp-os a.sidebar-user { text-decoration: none; color: inherit; }
.vp-os a.sidebar-user:hover { background: var(--bg-surface-3); border-radius: var(--r-md); }

/* ── Modal ───────────────────────────────────────────────────── */
@keyframes vp3-modal-in {
  from { opacity: 0; transform: scale(0.95) translateY(8px); }
  to   { opacity: 1; transform: scale(1)    translateY(0); }
}
@keyframes vp3-backdrop-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.vp-os .modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(8, 14, 26, 0.72);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-4);
  animation: vp3-backdrop-in var(--t-enter) both;
}
.vp-os .modal-backdrop[hidden] { display: none; }
.vp-os .modal-panel {
  background: var(--bg-surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  box-shadow: var(--sh-lg);
  width: 100%;
  max-width: 520px;
  animation: vp3-modal-in var(--t-spring) both;
  /* A tall dialog must never grow past the viewport. The backdrop is fixed and
     centres its child, so without a ceiling a long form (the tier editor has a
     dozen fields) overflows off BOTH edges and its footer — the Save button —
     becomes unreachable, with nothing to scroll because the backdrop itself does
     not scroll. Cap the panel and let the BODY scroll inside it, so the header
     and the actions stay pinned and visible at any height.
     dvh accounts for mobile browser chrome; vh is the fallback. */
  max-height: calc(100vh - var(--sp-4) * 2);
  max-height: calc(100dvh - var(--sp-4) * 2);
  display: flex;
  flex-direction: column;
}
/* The tier editor wraps body+footer in a <form>, so the flex column has to pass
   through it or the body has no bounded height to scroll within. min-height:0
   is what actually permits a flex child to shrink below its content. */
.vp-os .modal-panel > form {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1 1 auto;
}
.vp-os .modal-header, .vp-os .modal-footer { flex: 0 0 auto; }
.vp-os .modal-panel--lg { max-width: 720px; }
.vp-os .modal-header {
  padding: var(--sp-5) var(--sp-6);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.vp-os .modal-title { font-family: var(--font-head); font-weight: 600; font-size: var(--text-lg); }
.vp-os .modal-close { color: var(--text-3); transition: color var(--t-fast); }
.vp-os .modal-close:hover { color: var(--text); }
.vp-os .modal-body {
  padding: var(--sp-6);
  overflow-y: auto;
  overscroll-behavior: contain; /* don't scroll the page behind the dialog */
  min-height: 0;
  flex: 1 1 auto;
}
.vp-os .modal-footer {
  padding: var(--sp-4) var(--sp-6);
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-3);
}

/* ── Dropdown ────────────────────────────────────────────────── */
.vp-os .dropdown { position: relative; display: inline-block; }
.vp-os .dropdown-menu {
  position: absolute;
  top: calc(100% + var(--sp-2));
  right: 0;
  min-width: 180px;
  background: var(--bg-surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r);
  box-shadow: var(--sh-lg);
  z-index: 300;
  padding: var(--sp-2) 0;
  animation: vp3-modal-in var(--t-enter) both;
}
.vp-os .dropdown-menu[hidden] { display: none; }
.vp-os .dropdown-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--text-sm);
  color: var(--text-2);
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
.vp-os .dropdown-item:hover { background: var(--bg-surface-2); color: var(--text); }
.vp-os .dropdown-item--danger:hover { background: var(--danger-dim); color: var(--danger); }
.vp-os .dropdown-divider { height: 1px; background: var(--border); margin: var(--sp-2) 0; }

/* ── Toast ───────────────────────────────────────────────────── */
@keyframes vp3-toast-in  { from { transform: translateX(110%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes vp3-toast-out { from { transform: translateX(0); opacity: 1; } to { transform: translateX(110%); opacity: 0; } }
.vp-os .toast-container {
  position: fixed; bottom: var(--sp-6); right: var(--sp-6);
  display: flex; flex-direction: column; gap: var(--sp-3);
  z-index: 900; pointer-events: none;
}
.vp-os .toast {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg-surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r);
  box-shadow: var(--sh-lg);
  font-size: var(--text-sm);
  font-weight: 500;
  pointer-events: auto;
  min-width: 260px;
  max-width: 380px;
  animation: vp3-toast-in var(--t-enter) both;
}
.vp-os .toast--ok     { border-left: 3px solid var(--ok);     }
.vp-os .toast--error  { border-left: 3px solid var(--danger); }
.vp-os .toast--info   { border-left: 3px solid var(--info);   }
.vp-os .toast--warn   { border-left: 3px solid var(--warn);   }
.vp-os .toast.leaving { animation: vp3-toast-out var(--t-exit) both; }

/* ── Kbd ─────────────────────────────────────────────────────── */
.vp-os kbd {
  display: inline-flex;
  align-items: center;
  padding: 0.1em 0.4em;
  background: var(--bg-surface-3);
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: 0.75em;
  color: var(--text-3);
  white-space: nowrap;
}

/* ── Tabs ────────────────────────────────────────────────────── */
.vp-os .tab-list {
  display: flex;
  gap: var(--sp-1);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--sp-6);
}
.vp-os .tab {
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--text-3);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  transition: color var(--t-fast), border-color var(--t-fast);
  text-decoration: none;
}
.vp-os .tab:hover { color: var(--text-2); text-decoration: none; }
.vp-os .tab--active { color: var(--brand); border-bottom-color: var(--brand); }

/* ── Empty state ─────────────────────────────────────────────── */
.vp-os .empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--sp-12) var(--sp-8);
  gap: var(--sp-3);
}
.vp-os .empty-icon { font-size: 3rem; line-height: 1; }
.vp-os .empty-title { font-family: var(--font-head); font-size: var(--text-xl); font-weight: 700; }
.vp-os .empty-sub { font-size: var(--text-sm); color: var(--text-3); max-width: 380px; line-height: 1.6; }

/* ── Utility classes ─────────────────────────────────────────── */
.vp-os .muted { color: var(--text-3); }
.vp-os .text-sm { font-size: var(--text-sm); }
.vp-os .text-xs { font-size: var(--text-xs); }
.vp-os .font-head { font-family: var(--font-head); }
.vp-os .font-mono { font-family: var(--font-mono); }
.vp-os .font-bold { font-weight: 700; }
.vp-os .flex { display: flex; }
.vp-os .items-center { align-items: center; }
.vp-os .justify-between { justify-content: space-between; }
.vp-os .gap-2 { gap: var(--sp-2); }
.vp-os .gap-3 { gap: var(--sp-3); }
.vp-os .gap-4 { gap: var(--sp-4); }
.vp-os .mt-2 { margin-top: var(--sp-2); }
.vp-os .mt-3 { margin-top: var(--sp-3); }
.vp-os .mt-4 { margin-top: var(--sp-4); }
.vp-os .mt-6 { margin-top: var(--sp-6); }
.vp-os .mb-4 { margin-bottom: var(--sp-4); }
.vp-os .mb-6 { margin-bottom: var(--sp-6); }
.vp-os .truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vp-os [hidden] { display: none !important; }

/* Section divider */
.vp-os .section-divider {
  height: 1px;
  background: var(--border);
  margin: var(--sp-6) 0;
}

/* Count pill */
.vp-os .count-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 var(--sp-2);
  background: var(--bg-surface-3);
  color: var(--text-3);
  border-radius: var(--r-full);
  font-size: var(--text-xs);
  font-weight: 700;
  vertical-align: middle;
  margin-left: var(--sp-2);
}

/* ── Command palette ─────────────────────────────────────────── */
@keyframes vp3-palette-in {
  from { opacity: 0; transform: scale(0.97) translateY(-8px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}
.vp-os .cmd-backdrop {
  position: fixed; inset: 0;
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(14, 22, 40, 0.35), transparent 60%),
    rgba(6, 11, 22, 0.72);
  backdrop-filter: blur(10px) saturate(1.05);
  -webkit-backdrop-filter: blur(10px) saturate(1.05);
  z-index: 800;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 12vh;
  animation: vp3-backdrop-in var(--t-enter) both;
}
.vp-os .cmd-backdrop[hidden] { display: none; }
.vp-os .cmd-panel {
  position: relative;
  width: 100%;
  max-width: 600px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg-surface-2) 55%, var(--bg-surface)) 0%, var(--bg-surface) 42%);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg, 16px);
  box-shadow: 0 32px 80px -28px rgba(2, 8, 20, 0.85), 0 0 0 1px rgba(255, 255, 255, 0.02) inset;
  overflow: hidden;
  animation: vp3-palette-in var(--t-spring) both;
}
/* A brand hairline that sweeps the top edge — the palette's signature. */
.vp-os .cmd-panel::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px; z-index: 1;
  background: linear-gradient(90deg, transparent, var(--brand) 30%, var(--accent) 70%, transparent);
  opacity: 0.85;
}
.vp-os .cmd-input-wrap {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
  transition: border-color var(--t-fast);
}
.vp-os .cmd-input-wrap:focus-within { border-bottom-color: var(--brand); }
.vp-os .cmd-search-icon { color: var(--text-3); flex-shrink: 0; transition: color var(--t-fast); }
.vp-os .cmd-input-wrap:focus-within .cmd-search-icon { color: var(--brand); }
.vp-os .cmd-input {
  flex: 1;
  background: none;
  border: none;
  outline: none;
  font-size: var(--text-lg);
  color: var(--text);
}
.vp-os .cmd-input::placeholder { color: var(--text-3); }
.vp-os .cmd-results { max-height: 56vh; overflow-y: auto; padding: var(--sp-2) var(--sp-2) var(--sp-3); scroll-padding: var(--sp-3); }
.vp-os .cmd-group-label {
  padding: var(--sp-3) var(--sp-3) var(--sp-2);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--text-3);
}
.vp-os .cmd-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3);
  margin: 1px var(--sp-2);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast);
  text-decoration: none;
  color: var(--text);
}
.vp-os .cmd-item:hover,
.vp-os .cmd-item--active {
  background: var(--brand-dim);
  transform: translateX(3px);
  box-shadow: inset 3px 0 0 var(--brand);
}
/* The active row advertises the Enter shortcut. */
.vp-os .cmd-item--active::after {
  content: "\21B5"; /* ↵ */
  margin-left: auto; padding-left: var(--sp-3);
  font-size: var(--text-sm); color: var(--brand); opacity: 0.9;
}
.vp-os .cmd-item__icon {
  width: 32px; height: 32px;
  border-radius: var(--r-sm);
  background: linear-gradient(140deg, var(--bg-surface-3), var(--bg-surface-2));
  border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  font-size: 15px;
  flex-shrink: 0;
  transition: background var(--t-fast), border-color var(--t-fast), transform var(--t-fast);
}
.vp-os .cmd-item:hover .cmd-item__icon,
.vp-os .cmd-item--active .cmd-item__icon {
  background: var(--brand); border-color: var(--brand); transform: scale(1.06);
}
.vp-os .cmd-item__label { font-size: var(--text-sm); font-weight: 600; flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vp-os .cmd-item__hint { font-size: var(--text-xs); color: var(--text-3); }
.vp-os .cmd-footer {
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border);
  display: flex;
  gap: var(--sp-4);
  font-size: var(--text-xs);
  color: var(--text-3);
  background: color-mix(in srgb, var(--bg-surface-2) 40%, transparent);
}
.vp-os .cmd-footer-hint { display: flex; align-items: center; gap: var(--sp-2); }
.vp-os .cmd-footer kbd {
  min-width: 18px; height: 18px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-strong); border-radius: 5px;
  background: var(--bg-surface); font-size: 0.66rem; color: var(--text-2);
}
@media (prefers-reduced-motion: reduce) {
  .vp-os .cmd-item:hover, .vp-os .cmd-item--active { transform: none; }
}
@media (max-width: 640px) {
  .vp-os .cmd-backdrop { padding-top: 8vh; padding-left: var(--sp-3); padding-right: var(--sp-3); }
  .vp-os .cmd-input { font-size: var(--text-base); }
}

/* ── Activity feed ───────────────────────────────────────────── */
.vp-os .activity-list { display: flex; flex-direction: column; }
.vp-os .activity-item {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
}
.vp-os .activity-item:last-child { border-bottom: none; }
.vp-os .activity-icon {
  width: 32px; height: 32px;
  border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  font-size: 14px;
  flex-shrink: 0;
}
.vp-os .activity-icon--post    { background: var(--brand-dim); }
.vp-os .activity-icon--member  { background: var(--ok-dim); }
.vp-os .activity-icon--system  { background: var(--warn-dim); }
.vp-os .activity-body { flex: 1; min-width: 0; }
.vp-os .activity-text { font-size: var(--text-sm); color: var(--text); }
.vp-os .activity-time { font-size: var(--text-xs); color: var(--text-3); margin-top: 2px; }

/* ── Quick compose ───────────────────────────────────────────── */
.vp-os .quick-compose {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  margin-bottom: var(--sp-6);
  transition: border-color var(--t);
}
.vp-os .quick-compose:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-glow); }
.vp-os .quick-compose-icon { font-size: 1.25rem; flex-shrink: 0; }
.vp-os .quick-compose-input {
  flex: 1;
  background: none;
  border: none;
  outline: none;
  font-size: var(--text-base);
  color: var(--text);
}
.vp-os .quick-compose-input::placeholder { color: var(--text-3); }

/* ── Health / onboarding checklist ───────────────────────────── */
.vp-os .checklist { display: flex; flex-direction: column; gap: var(--sp-2); }
.vp-os .checklist-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-sm);
  font-size: var(--text-sm);
  background: var(--bg-surface-2);
}
.vp-os .checklist-item--done { opacity: 0.55; }
.vp-os .checklist-check {
  width: 20px; height: 20px;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px;
  color: transparent;
}
.vp-os .checklist-item--done .checklist-check {
  background: var(--ok);
  border-color: var(--ok);
  color: #fff;
}
.vp-os .checklist-label { flex: 1; color: var(--text-2); }
.vp-os .checklist-item--done .checklist-label { text-decoration: line-through; }

/* ── Settings forms ──────────────────────────────────────────── */
.vp-os .settings-grid { display: grid; grid-template-columns: 280px 1fr; gap: var(--sp-8); align-items: start; }
.vp-os .settings-section { display: flex; flex-direction: column; gap: var(--sp-6); }
.vp-os .settings-save-bar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-4);
  padding: var(--sp-4) 0 0;
  margin-top: var(--sp-6);
  border-top: 1px solid var(--border);
}
.vp-os .settings-block { display: flex; flex-direction: column; gap: var(--sp-4); }
.vp-os .settings-block-title { font-size: var(--text-sm); font-weight: 600; color: var(--text-2); padding-bottom: var(--sp-3); border-bottom: 1px solid var(--border); margin-bottom: var(--sp-1); }
.vp-os .settings-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-6); padding: var(--sp-3) 0; }
.vp-os .settings-row-info { flex: 1; }
.vp-os .settings-row-label { font-size: var(--text-sm); font-weight: 500; color: var(--text); }
.vp-os .settings-row-hint { font-size: var(--text-xs); color: var(--text-3); margin-top: 2px; }

/* ── Login page ──────────────────────────────────────────────── */
/* ── Auth pages (sign-in, change-password) ────────────────────────
   Calm, minimalist, Ghost-style: a single centered card on a clean
   background. Light by default (follows the OS via data-theme="auto");
   an unobtrusive switch offers light / dark / auto. No gradients. */
.vp-os.auth-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: var(--bg-base);
}
.vp-os .auth-col {
  width: 100%;
  max-width: 380px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
.vp-os .login-brandline {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--text);
  margin-bottom: 1.4rem;
  letter-spacing: -0.01em;
}
.vp-os .login-brandline img { width: 30px; height: 30px; border-radius: 8px; }
.vp-os .login-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 2.25rem 2rem;
  box-shadow: 0 1px 2px rgba(15,23,42,0.04), 0 10px 34px rgba(15,23,42,0.07);
}
.vp-os .login-title {
  font-family: var(--font-head);
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--text);
  text-align: center;
  letter-spacing: -0.02em;
  margin: 0 0 0.35rem;
}
.vp-os .login-sub { font-size: 0.9rem; color: var(--text-3); text-align: center; margin: 0 0 1.6rem; }
.vp-os .login-form { display: flex; flex-direction: column; gap: 1.05rem; }
.vp-os .login-form .field { display: flex; flex-direction: column; gap: 0.4rem; }
.vp-os .login-hint { color: var(--text-3); font-weight: 400; font-size: 0.75rem; }
.vp-os .login-remember { display: flex; align-items: center; gap: 0.55rem; font-size: 0.85rem; color: var(--text-2); cursor: pointer; user-select: none; }
.vp-os .login-remember input { width: 15px; height: 15px; accent-color: var(--brand); cursor: pointer; margin: 0; }
.vp-os .login-submit { margin-top: 0.4rem; justify-content: center; width: 100%; padding: 0.72rem 1rem; font-size: 0.95rem; border-radius: 10px; }
.vp-os .login-recover { margin: 1.15rem 0 0; font-size: 0.82rem; text-align: center; }
.vp-os .login-recover a { color: var(--text-2); text-decoration: none; border-bottom: 1px solid var(--border); padding-bottom: 1px; transition: color 0.15s ease, border-color 0.15s ease; }
.vp-os .login-recover a:hover { color: var(--brand); border-bottom-color: var(--brand); }
.vp-os .login-footer { margin-top: 1.4rem; font-size: 0.75rem; color: var(--text-3); text-align: center; }
.vp-os .login-error {
  padding: 0.7rem 0.9rem;
  background: var(--danger-dim);
  border: 1px solid var(--danger);
  border-radius: 10px;
  color: var(--danger);
  font-size: 0.85rem;
  margin-bottom: 1.1rem;
}

/* Theme switch (top-right) — small segmented control. */
.vp-os .theme-switch {
  position: fixed;
  top: 1rem; right: 1rem;
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: 0 1px 3px rgba(15,23,42,0.06);
}
.vp-os .theme-opt {
  width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; cursor: pointer;
  border-radius: 999px; font-size: 0.9rem; line-height: 1;
  color: var(--text-2);
  transition: background var(--t-fast, 120ms) ease, color var(--t-fast, 120ms) ease;
}
.vp-os .theme-opt:hover { color: var(--text); background: var(--bg-surface-2); }
.vp-os .theme-opt[aria-pressed="true"] { background: var(--brand-dim); color: var(--brand); }

/* ── Editor page ─────────────────────────────────────────────── */
/* Layout for the block editor lives in the "Block editor" section below; the
   earlier scaffolding rules were superseded and removed to avoid cascade
   conflicts that broke canvas scrolling. */

/* ── Notification bell badge ─────────────────────────────────── */
.vp-os .notif-btn { position: relative; }
.vp-os .notif-dot {
  position: absolute;
  top: 4px; right: 4px;
  width: 8px; height: 8px;
  background: var(--danger);
  border-radius: 50%;
  border: 2px solid var(--bg-surface);
}

/* ── Inline spinner ──────────────────────────────────────────── */
@keyframes vp3-spin { to { transform: rotate(360deg); } }
.vp-os [data-loading]::after {
  content: "";
  display: inline-block;
  width: 14px; height: 14px;
  border: 2px solid rgba(255,255,255,0.35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: vp3-spin 0.65s linear infinite;
  margin-left: var(--sp-2);
  vertical-align: middle;
}

/* ── Responsive ──────────────────────────────────────────────── */
@media (max-width: 1180px) {
  .vp-os .stat-grid { grid-template-columns: repeat(2, 1fr); }
  .vp-os .grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 900px) {
  .vp-os .settings-grid { grid-template-columns: 1fr; }
}
@media (max-width: 480px) {
  .vp-os .login-card { padding: 1.8rem 1.3rem; }
}
@media (max-width: 768px) {
  .vp-os .sidebar {
    transform: translateX(-100%);
  }
  .vp-os .sidebar.open {
    transform: translateX(0);
    box-shadow: var(--sh-lg);
  }
  .vp-os .main { margin-left: 0; }
  .vp-os .topbar { padding: 0 var(--sp-4); }
  .vp-os .content { padding: var(--sp-4); }
  .vp-os .menu-toggle { display: flex; }
  .vp-os .stat-grid { grid-template-columns: 1fr 1fr; }
  .vp-os .grid-3 { grid-template-columns: 1fr; }
  .vp-os .grid-2 { grid-template-columns: 1fr; }
  .vp-os .topbar-cmd { display: none; }
  .vp-os .page-header { flex-direction: column; align-items: flex-start; }

  /* Bottom nav on mobile */
  .vp-os .bottom-nav {
    position: fixed;
    bottom: 0; left: 0; right: 0;
    height: 56px;
    background: var(--bg-surface);
    border-top: 1px solid var(--border);
    display: flex;
    z-index: 200;
  }
  .vp-os .bottom-nav-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    font-size: 0.625rem;
    font-weight: 500;
    color: var(--text-3);
    text-decoration: none;
    padding: var(--sp-2) var(--sp-1);
    transition: color var(--t-fast);
  }
  .vp-os .bottom-nav-item.active { color: var(--brand); }
  .vp-os .bottom-nav-item svg { width: 22px; height: 22px; }
  .vp-os .content { padding-bottom: 72px; }
}
@media (min-width: 769px) {
  .vp-os .bottom-nav { display: none; }
}

/* ── Print ───────────────────────────────────────────────────── */
@media print {
  .vp-os .sidebar, .vp-os .topbar, .vp-os .bottom-nav { display: none; }
  .vp-os .main { margin-left: 0; }
}

/* ── Sidebar overlay (mobile) ────────────────────────────────── */
.vp-os .sidebar-overlay {
  display: none;
  position: fixed; inset: 0;
  background: rgba(8, 14, 26, 0.55);
  z-index: 190;
}
@media (max-width: 768px) {
  .vp-os .sidebar-overlay.open { display: block; }
}

/* ── Block editor (ADR-0068) ───────────────────────────────────────────────── */
/* The shell is a two-column grid (writing surface + tool sidebar) with a fixed
   topbar row. It is sized to the viewport beneath the sticky admin topbar so the
   writing column scrolls internally instead of letting the whole page grow —
   this is what lets a long post (or a single tall block) scroll smoothly. */
.vp-os .editor-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 280px;
  grid-template-rows: auto minmax(0, 1fr);
  gap: var(--sp-4) var(--sp-6);
  height: calc(100vh - var(--topbar-h) - 2 * var(--sp-6));
  min-height: 520px;
}
.vp-os .editor-topbar {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  background: var(--bg-surface);
  border-radius: var(--r-md);
  gap: var(--sp-3);
}
.vp-os .editor-topbar-actions { display: flex; align-items: center; gap: var(--sp-2); }
.vp-os .editor-topbar-status { font-size: var(--text-xs); color: var(--text-2); }
.vp-os .editor-topbar-status--ok   { color: var(--color-success, #22c55e); }
.vp-os .editor-topbar-status--warn { color: var(--color-warn, #f59e0b); }
.vp-os .editor-topbar-status--error { color: var(--color-danger, #ef4444); }
.vp-os .editor-wordcount { font-size: var(--text-xs); color: var(--text-3); margin-right: var(--sp-2); }
/* Active state for the toolbar toggle buttons (Focus / Split / HTML). */
.vp-os .editor-topbar-actions .btn.is-active {
  background: var(--brand-dim);
  color: var(--brand);
  border-color: var(--brand);
}

/* Writing column — owns the scroll. */
.vp-os .editor-main {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.vp-os .editor-title {
  flex: 0 0 auto;
  width: 100%;
  border: none;
  background: transparent;
  color: var(--text);
  font-family: var(--font-display, inherit);
  font-size: 2rem;
  font-weight: 700;
  padding: var(--sp-2) var(--sp-4) 0;
  margin: 0 0 var(--sp-2);
  outline: none;
}
.vp-os .editor-title::placeholder { color: var(--text-3); }

.vp-os .editor-workspace {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  gap: var(--sp-5);
  overflow: hidden;
}
.vp-os .editor-canvas {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  overflow-y: auto;
  overscroll-behavior: contain;
  scroll-behavior: smooth;
  /* Generous trailing space so the final block can scroll up into view and the
     caret never sits jammed against the bottom edge. */
  padding: var(--sp-2) var(--sp-4) 35vh;
}
/* Thin, unobtrusive scrollbar for the writing surface. */
.vp-os .editor-canvas { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
.vp-os .editor-canvas::-webkit-scrollbar { width: 10px; }
.vp-os .editor-canvas::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: var(--r-full); border: 3px solid transparent; background-clip: content-box; }
.vp-os .editor-canvas::-webkit-scrollbar-thumb:hover { background: var(--text-3); background-clip: content-box; }

/* Split live-preview pane — scrolls independently of the canvas. */
.vp-os .editor-live {
  flex: 1 1 50%;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--bg-surface);
  overflow: hidden;
}
.vp-os .editor-live[hidden] { display: none; }
.vp-os .editor-live-head {
  flex: 0 0 auto;
  padding: var(--sp-2) var(--sp-4);
  border-bottom: 1px solid var(--border);
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-3);
}
.vp-os .editor-live-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: var(--sp-5) var(--sp-6); }

/* HTML source mode — fills the writing column and scrolls on its own. */
.vp-os .editor-html {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--bg-surface);
  overflow: hidden;
}
.vp-os .editor-html[hidden] { display: none; }
.vp-os .editor-html-head {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  border-bottom: 1px solid var(--border);
}
.vp-os .editor-html-title {
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-3);
}
.vp-os .editor-html-area {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  resize: none;
  border: none;
  outline: none;
  background: var(--bg-base);
  color: var(--text);
  font-family: var(--font-mono, monospace);
  font-size: 0.85rem;
  line-height: 1.7;
  tab-size: 2;
  padding: var(--sp-4) var(--sp-5);
  overflow-y: auto;
  white-space: pre;
}
/* When HTML mode is on, hide the block canvas (the column shows the source). */
.vp-os .editor-shell.is-html .editor-canvas { display: none; }

.vp-os .editor-canvas { display: flex; flex-direction: column; gap: var(--sp-2); }

.vp-os .eblock {
  display: grid;
  grid-template-columns: 32px 1fr;
  gap: var(--sp-2);
  align-items: start;
  border-radius: var(--r-sm);
  padding: var(--sp-1);
  transition: background var(--t-fast);
}
.vp-os .eblock:hover { background: var(--bg-surface-2); }
.vp-os .eblock__ctrl { display: flex; flex-direction: column; gap: 2px; opacity: 0; transition: opacity var(--t-fast); }
.vp-os .eblock:hover .eblock__ctrl { opacity: 1; }
.vp-os .eblock__btn {
  width: 24px; height: 24px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-surface);
  color: var(--text-2);
  cursor: pointer;
  line-height: 1;
  font-size: var(--text-sm);
}
.vp-os .eblock__btn:hover { background: var(--bg-surface-3); color: var(--text); }
.vp-os .eblock__field { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }

.vp-os .eblock__text, .vp-os .eblock__input {
  width: 100%;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text);
  font: inherit;
  padding: var(--sp-2);
  border-radius: var(--r-sm);
  outline: none;
  resize: none;
}
.vp-os .eblock__text:focus, .vp-os .eblock__input:focus {
  border-color: var(--border);
  background: var(--bg-surface);
}
.vp-os .eblock__heading { font-size: 1.4rem; font-weight: 700; }
.vp-os .eblock--quote .eblock__text { border-left: 3px solid var(--brand); padding-left: var(--sp-3); font-style: italic; }
.vp-os .eblock__code { font-family: var(--font-mono, monospace); background: var(--bg-surface-3); }
.vp-os .eblock__lang, .vp-os .eblock__tone { max-width: 200px; font-size: var(--text-sm); }
.vp-os .eblock__level { max-width: 70px; }
.vp-os .eblock--callout .eblock__field { border-left: 3px solid var(--accent); padding-left: var(--sp-3); }
.vp-os .eblock__divider { border: none; border-top: 2px dashed var(--border); margin: var(--sp-2) 0; }

.vp-os .editor-sidebar {
  min-height: 0;
  overflow-y: auto;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.vp-os .editor-status { font-size: var(--text-sm); color: var(--text-2); }
.vp-os .editor-status--ok { color: var(--ok); }
.vp-os .editor-status--warn { color: var(--warn); }
.vp-os .editor-status--danger { color: var(--danger); }
.vp-os .editor-actions { display: flex; gap: var(--sp-2); }

/* Slash command palette */
.vp-os .block-palette {
  position: fixed;
  left: 50%; top: 30%;
  transform: translateX(-50%);
  width: min(420px, 92vw);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg, 0 20px 60px rgba(0,0,0,0.4));
  z-index: 300;
  overflow: hidden;
  animation: vp3-palette-in 0.16s ease;
}
.vp-os .block-palette__list { max-height: 60vh; overflow-y: auto; padding: var(--sp-2); }
.vp-os .block-palette__item {
  display: grid;
  grid-template-columns: 32px 1fr;
  grid-template-rows: auto auto;
  gap: 0 var(--sp-3);
  width: 100%;
  text-align: left;
  border: none;
  background: transparent;
  color: var(--text);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.vp-os .block-palette__item:hover { background: var(--brand-dim); }
.vp-os .block-palette__icon { grid-row: 1 / 3; display: flex; align-items: center; justify-content: center; font-size: var(--text-lg); color: var(--brand); }
.vp-os .block-palette__label { font-weight: 600; font-size: var(--text-sm); }
.vp-os .block-palette__hint { font-size: var(--text-xs); color: var(--text-3); }

/* Preview modal */
.vp-os .editor-preview-modal {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.6);
  display: flex; align-items: center; justify-content: center;
  z-index: 320; padding: var(--sp-4);
}
.vp-os .editor-preview-modal[hidden] { display: none; }
.vp-os .editor-preview-panel {
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  width: min(760px, 96vw);
  max-height: 88vh;
  display: flex; flex-direction: column;
  overflow: hidden;
}
.vp-os .editor-preview-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--border);
  font-weight: 600;
}
.vp-os .editor-preview-body { padding: var(--sp-6); overflow-y: auto; }

@media (max-width: 900px) {
  /* On small screens let the page scroll naturally rather than locking the
     editor to the viewport height. */
  .vp-os .editor-shell { grid-template-columns: 1fr; height: auto; min-height: 0; }
  .vp-os .editor-main { overflow: visible; }
  .vp-os .editor-canvas { overflow-y: visible; padding-bottom: var(--sp-10); }
  .vp-os .editor-workspace { flex-direction: column; overflow: visible; }
  .vp-os .editor-sidebar { position: static; overflow: visible; }
  /* Typewriter scrolling needs the canvas to be its own scroll container; on
     mobile the PAGE scrolls (overflow-y: visible above), so the 40vh focus
     padding would just add a phone-screen of dead space and the caret-centring
     can't run. Neutralise it — mobile browsers already keep the caret above the
     on-screen keyboard, which gives the same "line stays in view" comfort. */
  .vp-os .editor-shell.is-focus .editor-canvas { padding-top: var(--sp-6); padding-bottom: var(--sp-10); }
}

/* ── Media library (Phase 4, ADR-0068) ─────────────────────────────────────── */
.vp-os .media-dropzone {
  border: 2px dashed var(--border-strong);
  border-radius: var(--r-md);
  padding: var(--sp-8);
  text-align: center;
  cursor: pointer;
  transition: border-color var(--t-fast), background var(--t-fast);
  margin-bottom: var(--sp-6);
}
.vp-os .media-dropzone:hover, .vp-os .media-dropzone:focus-visible { border-color: var(--brand); background: var(--brand-dim); outline: none; }
.vp-os .media-dropzone--over { border-color: var(--brand); background: var(--brand-dim); }
.vp-os .media-dropzone__icon { font-size: 2rem; color: var(--brand); }
.vp-os .media-dropzone__text { margin-top: var(--sp-2); font-weight: 500; }
.vp-os .media-dropzone__link { color: var(--brand); text-decoration: underline; }
.vp-os .media-dropzone__hint { margin-top: var(--sp-1); }

.vp-os .media-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--sp-4);
}
.vp-os .media-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.vp-os .media-card__thumb {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--bg-surface-3);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.vp-os .media-card__select {
  position: absolute; top: 6px; left: 6px; z-index: 1;
  width: 18px; height: 18px; cursor: pointer;
}
.vp-os .media-card__alt {
  width: 100%; padding: 4px 6px; font-size: var(--text-xs);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg-surface); color: var(--text); font-family: inherit;
}
.vp-os .media-card__thumb img { width: 100%; height: 100%; object-fit: cover; }
.vp-os .media-card__pdf { font-weight: 700; color: var(--danger); letter-spacing: 0.05em; }
.vp-os .media-card__meta { padding: var(--sp-2) var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--text-xs); color: var(--text-2); }
.vp-os .media-card__copy {
  align-self: flex-start;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 2px var(--sp-2);
  font-size: var(--text-xs);
  color: var(--text-2);
}
.vp-os .media-card__copy:hover { background: var(--bg-surface-3); color: var(--text); }
.vp-os .skeleton--media { aspect-ratio: 4 / 3; height: auto; border-radius: var(--r-md); }

/* ── Security / TOTP enrolment (Phase 5, ADR-0068) ─────────────────────────── */
.vp-os .totp-key {
  margin-top: var(--sp-3);
  padding: var(--sp-3);
  background: var(--bg-surface-3);
  border-radius: var(--r-sm);
  letter-spacing: 0.12em;
  word-break: break-all;
}
.vp-os .totp-uri { margin-top: var(--sp-2); }
.vp-os .totp-enroll[hidden] { display: none; }
.eblock__embed-status{display:block;font-size:12px;color:var(--muted,#64748b);margin-top:4px;font-style:italic;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.eblock__diagram-preview{margin-top:8px;padding:12px;border:1px solid var(--border,#1e2d42);border-radius:6px;background:var(--surface,#0a1018);text-align:center;overflow-x:auto;min-height:40px}.eblock__diagram-preview svg{max-width:100%;height:auto}.eblock__diagram-preview.is-error{color:var(--red,#f87171);font:400 12px/1.5 var(--mono,monospace);text-align:left}.eblock__diagram-preview .vp-diagram__node,.eblock__diagram-preview .vp-diagram__actor{fill:#0e1520;stroke:#6366f1;stroke-width:1.5}.eblock__diagram-preview .vp-diagram__node--round,.eblock__diagram-preview .vp-diagram__node--diamond,.eblock__diagram-preview .vp-diagram__note{fill:#121c2a}.eblock__diagram-preview .vp-diagram__label,.eblock__diagram-preview .vp-diagram__actorlabel,.eblock__diagram-preview .vp-diagram__notetext{fill:#dde6f0}.eblock__diagram-preview .vp-diagram__edge,.eblock__diagram-preview .vp-diagram__msg{stroke:#8a9bb5;fill:none;stroke-width:1.5}.eblock__diagram-preview .vp-diagram__arrowhead{fill:#8a9bb5}.eblock__diagram-preview .vp-diagram__edgelabel,.eblock__diagram-preview .vp-diagram__msglabel{fill:#8a9bb5}.eblock__diagram-preview .vp-diagram__lifeline{stroke:#1e2d42;stroke-dasharray:3 3}

/* ── Tools & Plugins panel (VayuOS foundation) ─────────────────────────────── */
.vp-os .tools-cat {
  grid-column: 1 / -1;
  font-family: var(--font-head);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-3);
  margin: var(--sp-4) 0 var(--sp-1);
}
.vp-os .tools-cat:first-child { margin-top: 0; }
.vp-os .tools-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--sp-4);
}
.vp-os .tool-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.vp-os .tool-card:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.vp-os .tool-card__head { display: flex; align-items: center; gap: var(--sp-3); }
.vp-os .tool-card__icon { font-size: 1.25rem; line-height: 1; }
.vp-os .tool-card__title {
  font-family: var(--font-head);
  font-weight: 600;
  font-size: var(--text-base);
  flex: 1;
  min-width: 0;
}
.vp-os .tool-card__desc { color: var(--text-2); font-size: var(--text-sm); line-height: 1.5; flex: 1; }
.vp-os .tool-card__foot { display: flex; align-items: center; }
.vp-os .tool-status {
  font-size: var(--text-xs);
  font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--r-full);
  border: 1px solid transparent;
}
.vp-os .tool-status--on   { color: var(--ok);     background: var(--ok-dim); }
.vp-os .tool-status--off  { color: var(--text-3); background: var(--bg-surface-2); }
.vp-os .tool-status--idle { color: var(--warn);   background: var(--warn-dim); }

/* Toggle switch */
.vp-os .switch { position: relative; display: inline-flex; cursor: pointer; flex: 0 0 auto; }
.vp-os .switch-input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.vp-os .switch-track {
  width: 38px; height: 22px; border-radius: var(--r-full);
  background: var(--bg-surface-3); border: 1px solid var(--border);
  transition: background 0.18s ease, border-color 0.18s ease;
  position: relative; display: inline-block;
}
.vp-os .switch-track::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--text-2); transition: transform 0.18s ease, background 0.18s ease;
}
.vp-os .switch-input:checked + .switch-track { background: var(--brand-dim); border-color: var(--brand); }
.vp-os .switch-input:checked + .switch-track::after { transform: translateX(16px); background: var(--brand); }
.vp-os .switch-input:disabled + .switch-track { opacity: 0.5; }
.vp-os .switch-input:focus-visible + .switch-track { box-shadow: 0 0 0 2px var(--brand-glow); }

/* Monitoring: tool-card used as a navigational link */
.vp-os a.tool-card { text-decoration: none; color: inherit; cursor: pointer; }
.vp-os a.tool-card:hover .tool-card__title { color: var(--brand); }

/* ── AI suggestion overlay ─────────────────────────────────────────────────── */
.vp-os .ai-suggest {
  margin: 8px 0 4px;
  padding: 12px 14px;
  background: var(--bg-surface-2);
  border: 1px solid var(--brand-dim);
  border-left: 3px solid var(--brand);
  border-radius: var(--r-md);
}
.vp-os .ai-suggest__text {
  font-size: 0.92rem;
  color: var(--text-1);
  white-space: pre-wrap;
  margin-bottom: 10px;
}
.vp-os .ai-suggest__actions { display: flex; gap: 8px; }
.vp-os .btn--xs { padding: 2px 10px; font-size: 0.8rem; }
.vp-os .block-palette__sep {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-3);
  padding: 6px 12px 2px;
}

/* ── Version history modal ─────────────────────────────────────────────────── */
.vp-os .editor-history-modal {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(0,0,0,0.45);
  display: flex; align-items: stretch; justify-content: flex-end;
}
.vp-os .editor-history-modal[hidden] { display: none; }
.vp-os .editor-history-panel {
  width: min(680px, 96vw);
  background: var(--bg-surface);
  display: flex; flex-direction: column;
  border-left: 1px solid var(--border);
  overflow: hidden;
}
.vp-os .editor-history-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
}
.vp-os .editor-history-body {
  display: grid;
  grid-template-columns: 200px 1fr;
  overflow: hidden;
  flex: 1;
}
.vp-os .editor-history-list {
  border-right: 1px solid var(--border);
  overflow-y: auto;
  padding: 10px 0;
}
.vp-os .history-ver {
  display: flex; flex-direction: column; align-items: flex-start;
  width: 100%;
  padding: 10px 14px;
  background: none; border: none; cursor: pointer;
  text-align: left;
  transition: background 0.12s;
}
.vp-os .history-ver:hover { background: var(--bg-surface-2); }
.vp-os .history-ver__ts { font-size: 0.75rem; color: var(--text-3); }
.vp-os .history-ver__label { font-size: 0.85rem; color: var(--text-1); margin-top: 2px; }
.vp-os .editor-history-diff {
  overflow-y: auto;
  padding: 14px 18px;
}
.vp-os .history-diff__title { margin-bottom: 10px; }
.vp-os .history-diff__view {
  font-family: var(--font-mono, monospace);
  font-size: 0.85rem;
  line-height: 1.7;
  white-space: pre-wrap;
  word-break: break-word;
}
.vp-os .diff-ins { background: var(--ok-dim); color: var(--ok); border-radius: 2px; padding: 0 2px; }
.vp-os .diff-del { background: var(--danger-dim, rgba(220,53,69,.12)); color: var(--danger, #dc3545); border-radius: 2px; padding: 0 2px; text-decoration: line-through; }
.vp-os .diff-eq  { color: var(--text-2); }

/* ── Theme Studio ──────────────────────────────────────────────────────────── */
/* ── Theme Studio — Ghost-style customizer (controls panel + live preview) ─── */
.vp-os .customizer {
  display: grid;
  grid-template-columns: 380px 1fr;
  gap: 20px;
  align-items: start;
  /* Fill the viewport height so the preview can be large. */
  height: calc(100vh - 150px);
  min-height: 560px;
}
@media (max-width: 1100px) {
  .vp-os .customizer { grid-template-columns: 1fr; height: auto; }
}

/* Controls panel — scrolls independently of the sticky preview. */
.vp-os .customizer__panel {
  display: flex; flex-direction: column; gap: 12px;
  height: 100%; overflow-y: auto; padding-right: 6px;
}
@media (max-width: 1100px) { .vp-os .customizer__panel { height: auto; overflow: visible; } }

/* Collapsible control groups. flex:0 0 auto stops a tall open section from being
   squeezed (and clipped by overflow:hidden) to fit the panel — instead the panel
   itself scrolls, so the whole section and all its controls are reachable. */
.vp-os .cz-group {
  flex: 0 0 auto;
  background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); overflow: hidden;
}
.vp-os .cz-group__head {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 13px 16px; cursor: pointer; user-select: none; text-align: left;
  font-family: inherit; font-size: 0.9rem; font-weight: 600; color: var(--text);
  background: transparent; border: 0; appearance: none; list-style: none;
}
.vp-os .cz-group__head::-webkit-details-marker { display: none; }
.vp-os .cz-group__head::after {
  content: "⌄"; margin-left: auto; font-size: 1rem; color: var(--text-2);
  transition: transform .15s; transform: translateY(-2px) rotate(0deg);
}
.vp-os .cz-group--open > .cz-group__head::after { transform: translateY(0) rotate(180deg); }
.vp-os .cz-group__head:hover { background: var(--bg-surface-2); }
.vp-os .cz-group--open { border-color: var(--border-strong); box-shadow: var(--sh-sm); }
.vp-os .cz-group--open > .cz-group__head { background: var(--bg-surface-2); color: var(--text); }
.vp-os .cz-group--open > .cz-group__body { animation: mon-reveal 0.28s cubic-bezier(0.16, 0.84, 0.44, 1); }
@media (prefers-reduced-motion: reduce) { .vp-os .cz-group--open > .cz-group__body { animation: none; } }
.vp-os .cz-group__hint {
  font-size: 0.68rem; font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
  color: #fff; background: var(--brand); padding: 2px 7px; border-radius: var(--r-full);
}
.vp-os .cz-group__body { display: none; padding: 4px 16px 16px; border-top: 1px solid var(--border); }
.vp-os .cz-group--open > .cz-group__body { display: block; }

/* Theme Studio — Monetization-console group summaries. The head keeps its
   .cz-group__head class + aria-expanded (the accordion JS and the jump bar key
   off them) and gains the icon / title / subtitle / chip layout used by the
   Monetization accordions, so the whole console reads as one system. */
.vp-os .cz-group__head { gap: var(--sp-3); }
.vp-os .cz-group__ic {
  flex: none; width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.95rem; border-radius: var(--r-sm);
  background: var(--bg-surface-2); border: 1px solid var(--border);
}
.vp-os .cz-group__text { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; text-align: left; }
.vp-os .cz-group__title { font-weight: 650; font-size: var(--text-sm); color: var(--text); }
.vp-os .cz-group__sub {
  font-size: var(--text-xs); font-weight: 400; color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Status chips on a group summary (mirrors .mon-chip). */
.vp-os .cz-chip {
  flex: none; font-size: var(--text-xs); font-weight: 600; padding: 3px 9px; border-radius: var(--r-full);
  border: 1px solid var(--border); color: var(--text-3); background: var(--bg-surface-2); white-space: nowrap;
}
.vp-os .cz-chip--go { color: #38bdf8; border-color: rgba(56, 189, 248, 0.4); background: rgba(56, 189, 248, 0.12); }
.vp-os .cz-chip--live { color: #34d399; border-color: rgba(52, 211, 153, 0.4); background: rgba(52, 211, 153, 0.12); }
.vp-os .cz-chip--warn { color: var(--warn); border-color: rgba(245, 158, 11, 0.4); background: rgba(245, 158, 11, 0.12); }
.vp-os .cz-chip--bad { color: #f87171; border-color: rgba(248, 113, 113, 0.4); background: rgba(248, 113, 113, 0.12); }
@media (max-width: 700px) { .vp-os .cz-chip { display: none; } .vp-os .cz-group__sub { white-space: normal; } }

/* Section dividers between groups of controls (mirrors .section-head). */
.vp-os .cz-sec {
  display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap;
  margin: var(--sp-4) 0 var(--sp-1); padding: 0 2px;
}
.vp-os .cz-sec:first-child { margin-top: 0; }
.vp-os .cz-sec__title {
  font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--text-2);
}
.vp-os .cz-sec__hint { font-size: var(--text-xs); color: var(--text-3); }

/* Readability (WCAG contrast) readout inside the Brand colours group. */
.vp-os .cz-a11y {
  margin-top: var(--sp-4); padding: var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-surface-2);
}
.vp-os .cz-a11y__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-2);
}
.vp-os .cz-a11y__title { font-size: var(--text-sm); font-weight: 650; color: var(--text); }
.vp-os .cz-a11y__dot {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  margin-right: 6px; border: 1px solid var(--border-strong); vertical-align: baseline;
}
.vp-os .cz-a11y .table td { padding-top: 6px; padding-bottom: 6px; }

/* Customizer quick-jump chip bar — sticky section navigator. */
.vp-os .cz-jump {
  position: sticky; top: 0; z-index: 3;
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 8px; margin-bottom: 4px;
  background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r-md);
}
.vp-os .cz-jump__chip {
  font-size: 0.72rem; font-weight: 600; line-height: 1;
  padding: 5px 9px; cursor: pointer; color: var(--text-2);
  background: var(--bg-surface-2); border: 1px solid var(--border);
  border-radius: var(--r-full); transition: color .12s, border-color .12s, background .12s;
}
.vp-os .cz-jump__chip:hover { color: #fff; background: var(--brand); border-color: var(--brand); }

/* Apply button "unsaved changes" state — a subtle ring so the operator knows a
   live preview tweak still needs Applying to persist. */
.vp-os .btn.is-dirty {
  box-shadow: 0 0 0 2px var(--brand), 0 0 0 4px color-mix(in srgb, var(--brand) 35%, transparent);
}

/* Preview stage. */
.vp-os .customizer__stage {
  display: flex; flex-direction: column;
  height: 100%; min-height: 520px;
  background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); overflow: hidden;
}
@media (max-width: 1100px) { .vp-os .customizer__stage { height: 75vh; } }
.vp-os .customizer__toolbar {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-bottom: 1px solid var(--border);
  background: var(--bg-surface-2);
}
.vp-os .cz-toolbar-spacer { flex: 1; }
.vp-os .cz-devices { display: inline-flex; gap: 4px; background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r-full); padding: 3px; }
.vp-os .cz-device {
  font-size: 0.78rem; font-weight: 500; line-height: 1;
  padding: 6px 12px; cursor: pointer; color: var(--text-2);
  background: transparent; border: 0; border-radius: var(--r-full); transition: color .14s, background .14s;
}
.vp-os .cz-device:hover { color: var(--text); }
.vp-os .cz-device--active { color: #fff; background: var(--brand); }

.vp-os .customizer__viewport {
  flex: 1; position: relative; overflow: auto;
  display: flex; justify-content: center; align-items: flex-start;
  padding: 0; background:
    repeating-conic-gradient(var(--bg-surface-2) 0% 25%, transparent 0% 50%) 50% / 22px 22px;
}
.vp-os .customizer__frame-wrap {
  position: relative; width: 100%; height: 100%;
  transition: width .2s ease, max-width .2s ease;
}
.vp-os .customizer__viewport[data-device="desktop"] .customizer__frame-wrap { width: 100%; max-width: 100%; }
.vp-os .customizer__viewport[data-device="tablet"] .customizer__frame-wrap { width: 820px; max-width: 100%; }
.vp-os .customizer__viewport[data-device="mobile"] .customizer__frame-wrap { width: 390px; max-width: 100%; }
.vp-os .customizer__viewport[data-device="tablet"],
.vp-os .customizer__viewport[data-device="mobile"] { padding: 16px; align-items: flex-start; }

.vp-os .customizer__frame {
  width: 100%; height: 100%; min-height: 480px; border: 0; background: #fff;
  display: block; border-radius: 2px;
}
.vp-os .customizer__viewport[data-device="tablet"] .customizer__frame,
.vp-os .customizer__viewport[data-device="mobile"] .customizer__frame {
  border-radius: 12px; box-shadow: 0 12px 40px rgba(0,0,0,0.35); border: 1px solid var(--border);
}
.vp-os .customizer__frame-loading {
  position: absolute; top: 12px; left: 50%; transform: translateX(-50%);
  font-size: 0.78rem; color: var(--text-2);
  background: var(--bg-surface); border: 1px solid var(--border);
  padding: 5px 12px; border-radius: var(--r-full); box-shadow: var(--sh);
  pointer-events: none; z-index: 2;
}
.vp-os .customizer__frame-loading[hidden] { display: none; }

/* Brand logo + navigation editor rows in the customizer panel */
.vp-os .cz-logo { display: flex; align-items: center; gap: 12px; }
.vp-os .cz-logo__img { border-radius: 8px; background: var(--bg-surface-2); object-fit: cover; border: 1px solid var(--border); }
.vp-os .cz-logo__title { font-size: 0.85rem; font-weight: 600; color: var(--text); }
.vp-os .cz-nav-row { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.vp-os .cz-nav-row input[data-nav-label] { flex: 1; min-width: 0; }
.vp-os .cz-nav-row input[data-nav-href] { flex: 2; min-width: 0; }

/* ── Tumblr-style sliding toggle switches (customizer checkboxes) ──────────────
   The native checkbox is repainted as an iOS/Tumblr pill switch via the CSSOM
   appearance reset — no JS, no inline styles, CSP-safe. Label text sits on the
   left, the switch on the right, mirroring the reference theme editor. */
.vp-os .cz-check {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex: 1 1 auto; min-width: 0;
  font-size: 0.9rem; font-weight: 600; color: var(--text);
  cursor: pointer; user-select: none;
}
.vp-os .cz-check input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  order: 2; flex: 0 0 auto; position: relative;
  width: 42px; height: 24px; margin: 0; cursor: pointer;
  background: var(--bg-surface-2); border: 1px solid var(--border);
  border-radius: var(--r-full); transition: background .16s, border-color .16s;
}
.vp-os .cz-check input[type="checkbox"]::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 18px; height: 18px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.35);
  transition: transform .16s;
}
.vp-os .cz-check input[type="checkbox"]:checked { background: var(--brand); border-color: var(--brand); }
.vp-os .cz-check input[type="checkbox"]:checked::after { transform: translateX(18px); }
.vp-os .cz-check input[type="checkbox"]:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }


.vp-os .theme-presets { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 12px; }
.vp-os .theme-preset {
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px; cursor: pointer;
  background: var(--bg-surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); transition: border-color 0.14s, transform 0.14s;
}
.vp-os .theme-preset:hover { border-color: var(--brand); transform: translateY(-2px); }
.vp-os .theme-preset__swatches { display: flex; gap: 4px; }
.vp-os .theme-preset__swatch { width: 100%; height: 22px; border-radius: 4px; border: 1px solid rgba(255,255,255,0.06); }
.vp-os .theme-preset__name { font-size: 0.85rem; font-weight: 600; color: var(--text-1); }

/* ── Theme gallery cards (Tumblr-style visual previews) ────────────────────── */
.vp-os .theme-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 14px;
}
.vp-os .theme-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 0; cursor: pointer;
  background: var(--bg-surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); overflow: hidden;
  transition: border-color 0.14s, transform 0.14s, box-shadow 0.14s;
  text-align: left;
}
.vp-os .theme-card:hover {
  border-color: var(--brand);
  transform: translateY(-2px);
  box-shadow: 0 4px 16px rgba(0,0,0,0.2);
}
.vp-os .theme-card--active {
  border-color: var(--brand);
  box-shadow: 0 0 0 2px var(--brand);
  background: rgba(108, 92, 231, 0.08);
}
.vp-os .theme-card__preview {
  height: 100px; padding: 10px;
  display: flex; flex-direction: column; gap: 6px;
}
.vp-os .theme-card__bar {
  width: 100%; height: 8px; border-radius: 2px; opacity: 0.6;
}
.vp-os .theme-card__body {
  flex: 1; display: flex; flex-direction: column; gap: 6px;
  padding: 0 4px;
}
.vp-os .theme-card__line {
  height: 6px; border-radius: 3px; opacity: 0.4; width: 100%;
}
.vp-os .theme-card__line--short { width: 60%; }
.vp-os .theme-card__pills {
  display: flex; gap: 6px; margin-top: auto;
}
.vp-os .theme-card__pills span {
  width: 28px; height: 8px; border-radius: 4px;
}
.vp-os .theme-card__name {
  font-size: 0.8rem; font-weight: 600; color: var(--text-1);
  padding: 0 12px 10px;
}

/* ── Theme Store (deployable theme catalogue) ──────────────────────────────── */
.vp-os .store { display: flex; flex-direction: column; gap: 16px; }
.vp-os .store-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.vp-os .store-filters { display: flex; gap: 8px; flex-wrap: wrap; }
.vp-os .store-chip {
  font-size: 0.8rem; font-weight: 500; line-height: 1;
  padding: 7px 13px; cursor: pointer;
  color: var(--text-2);
  background: var(--bg-surface-2); border: 1px solid var(--border);
  border-radius: var(--r-full); transition: color .14s, border-color .14s, background .14s;
}
.vp-os .store-chip:hover { color: var(--text); border-color: var(--border-strong); }
.vp-os .store-chip--active {
  color: #fff; background: var(--brand); border-color: var(--brand);
}
.vp-os .store-search { min-width: 200px; flex: 0 1 280px; }
.vp-os .store-search .input { width: 100%; }
.vp-os .store-meta { margin-top: -4px; }

.vp-os .store-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 18px;
}
.vp-os .store-card {
  display: flex; flex-direction: column;
  background: var(--bg-surface-2); border: 1px solid var(--border);
  border-radius: var(--r-lg); overflow: hidden;
  transition: border-color .14s, transform .14s, box-shadow .14s;
}
.vp-os .store-card:hover {
  border-color: var(--brand); transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.22);
}
.vp-os .store-card--active {
  border-color: var(--brand);
  box-shadow: 0 0 0 2px var(--brand);
}
.vp-os .store-card__preview {
  position: relative;
  height: 132px; padding: 14px;
  display: flex; flex-direction: column; gap: 8px;
}
.vp-os .store-card__bar { width: 70%; height: 10px; border-radius: 3px; opacity: 0.7; }
.vp-os .store-card__lines { flex: 1; display: flex; flex-direction: column; gap: 7px; padding-top: 2px; }
.vp-os .store-card__line { height: 7px; border-radius: 3px; opacity: 0.45; width: 100%; }
.vp-os .store-card__line--short { width: 55%; }
.vp-os .store-card__pills { display: flex; gap: 7px; margin-top: auto; }
.vp-os .store-card__pills span { width: 30px; height: 10px; border-radius: 5px; }
.vp-os .store-card__badge {
  position: absolute; top: 10px; right: 10px;
  font-size: 0.68rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: #fff; background: var(--brand);
  padding: 3px 9px; border-radius: var(--r-full);
  box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.vp-os .store-card__info { display: flex; flex-direction: column; gap: 8px; padding: 14px 16px 16px; }
.vp-os .store-card__head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.vp-os .store-card__name { font-size: 1.02rem; font-weight: 700; color: var(--text); margin: 0; }
.vp-os .store-card__cat {
  font-size: 0.68rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-2); background: var(--bg-surface); border: 1px solid var(--border);
  padding: 2px 8px; border-radius: var(--r-full); white-space: nowrap;
}
.vp-os .store-card__tagline { font-size: 0.86rem; font-weight: 500; color: var(--text); margin: 0; }
.vp-os .store-card__desc { font-size: 0.82rem; line-height: 1.55; color: var(--text-2); margin: 0; }
.vp-os .store-card__tags { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 2px; }
.vp-os .store-tag {
  font-size: 0.72rem; color: var(--text-2);
  background: var(--bg-surface); border: 1px solid var(--border);
  padding: 2px 8px; border-radius: var(--r-sm);
}
.vp-os .store-card__actions { display: flex; gap: 8px; margin-top: 8px; align-items: center; }
.vp-os .store-card__deploy { min-width: 92px; }
.vp-os .store-card__deploy[data-store-active="true"] { opacity: 0.7; cursor: default; }
.vp-os .store-empty { padding: 40px 0; text-align: center; color: var(--text-2); }

/* ── Theme Store live preview overlay (isolated iframe) ────────────────────── */
.vp-os .store-preview { position: fixed; inset: 0; z-index: 300; display: flex; flex-direction: column; background: rgba(0,0,0,0.62); }
.vp-os .store-preview[hidden] { display: none; }
.vp-os .store-preview__bar { display: flex; align-items: center; gap: 0.6rem; padding: 0.7rem 1rem; background: var(--bg-surface); border-bottom: 1px solid var(--border); }
.vp-os .store-preview__title { font-weight: 700; color: var(--text); font-size: 0.95rem; }
.vp-os .store-preview__spacer { flex: 1; }
.vp-os .store-preview__close { display: grid; place-items: center; width: 38px; height: 38px; border: 0; border-radius: 8px; background: transparent; color: var(--text-2); font-size: 1.5rem; line-height: 1; cursor: pointer; }
.vp-os .store-preview__close:hover { background: var(--bg-surface-2); color: var(--text); }
.vp-os .store-preview__frame { flex: 1; width: 100%; border: 0; background: #fff; }

.vp-os .theme-fields { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; }
.vp-os .theme-fields--text { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.vp-os .theme-field { display: flex; flex-direction: column; gap: 6px; }
.vp-os .theme-field--text { gap: 6px; }
.vp-os .theme-field__label { font-size: 0.78rem; color: var(--text-2); }
.vp-os .theme-field__hint { font-size: 0.72rem; color: var(--text-3, var(--text-2)); opacity: 0.85; margin-top: 2px; }
.vp-os .theme-field__color {
  width: 100%; height: 38px; padding: 2px; cursor: pointer;
  background: var(--bg-surface-2); border: 1px solid var(--border); border-radius: var(--r-sm);
}

/* Live preview — consumes the --vp-* custom properties set via CSSOM. */
.vp-os .theme-prev {
  margin-top: 10px; padding: 20px; border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--vp-bg, #0b0f14);
  color: var(--vp-text, #e6edf3);
  font-family: var(--vp-font-sans, system-ui, sans-serif);
  font-size: var(--vp-font-size-base, 1rem);
  line-height: var(--vp-line-height, 1.6);
  max-height: 70vh; overflow-y: auto;
}
.vp-os .theme-prev__h1 { color: var(--vp-text, #fff); font-size: 1.5rem; margin: 0 0 10px; }
.vp-os .theme-prev__h2 { color: var(--vp-text, #fff); font-size: 1.15rem; margin: 16px 0 8px; }
.vp-os .theme-prev__p { margin: 0 0 10px; }
.vp-os .theme-prev__p strong { color: var(--vp-accent, #2dd4bf); }
.vp-os .theme-prev__link { color: var(--vp-accent, #2dd4bf); text-decoration: none; }
.vp-os .theme-prev__link:hover { text-decoration: underline; }
.vp-os .theme-prev__code {
  font-family: var(--vp-font-mono, ui-monospace, monospace);
  background: var(--bg-surface-2); padding: 1px 5px; border-radius: 4px;
}
.vp-os .theme-prev__quote {
  margin: 12px 0; padding: 8px 14px;
  border-left: 3px solid var(--vp-accent2, var(--vp-accent, #fbbf24));
  color: var(--vp-muted, #9aa4ad); font-style: italic;
  background: var(--bg-surface-2);
  border-radius: var(--vp-radius-lg, 0.5rem);
}
.vp-os .theme-prev__chips { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
.vp-os .theme-prev__chip {
  font-size: 0.72rem; padding: 2px 10px; border-radius: var(--r-full);
  background: var(--bg-surface-2);
}
.vp-os .theme-prev__chip--accent { color: var(--vp-accent, #2dd4bf); }
.vp-os .theme-prev__chip--hi { color: var(--vp-hi, #fbbf24); }
.vp-os .theme-prev__chip--green { color: var(--vp-green, #34d399); }

.vp-os .status--ok     { color: var(--ok); }
.vp-os .status--warn   { color: var(--warn); }
.vp-os .status--danger { color: var(--danger, #dc3545); }

/* ── Convert-to-blocks banner (legacy editor → block editor migration) ─────── */
.vp-os .convert-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 12px 16px; margin-bottom: 16px;
  background: var(--brand-dim); border: 1px solid var(--brand);
  border-radius: var(--r-md);
}
.vp-os .convert-banner__text { display: flex; flex-direction: column; gap: 2px; font-size: 0.9rem; }
.vp-os .convert-banner__text .muted { font-size: 0.82rem; }


/* ============================================================
   Operator consoles (System Modes, Policy, Topology, Replay,
   Faults, ADRs) — ported from the classic console into VayuOS.
   ============================================================ */
@keyframes live-beat{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(1.8);opacity:.4}}
@keyframes pulse-ring{0%{transform:scale(.3);opacity:.7}100%{transform:scale(1.9);opacity:0}}
@keyframes tl-enter{0%{opacity:0;transform:translateX(-8px)}60%{opacity:1}100%{opacity:1;transform:none}}
@keyframes tl-node-flash{0%{box-shadow:0 0 0 0 rgba(99,102,241,.5)}100%{box-shadow:0 0 0 7px rgba(99,102,241,0)}}
@keyframes tl-elbow{0%,100%{border-color:var(--border-strong)}50%{border-color:var(--brand)}}
@keyframes tl-spark{0%{opacity:0;transform:translate(0,-7px)}40%{opacity:.9}70%{opacity:.9;transform:translate(0,1px)}100%{opacity:0;transform:translate(6px,1px)}}
@keyframes esc-pulse{0%,100%{opacity:.35;transform:translateX(-1px)}50%{opacity:1;transform:translateX(2px)}}
@keyframes topo-flow{to{stroke-dashoffset:-10}}
.mode-badge.mode-normal{background:rgba(16,185,129,.1);color:var(--ok);border:1px solid rgba(16,185,129,.3)}
.mode-badge.mode-degraded{background:rgba(245,158,11,.1);color:var(--warn);border:1px solid rgba(245,158,11,.3)}
.mode-badge.mode-readonly,.mode-badge.mode-quarantined{background:rgba(239,68,68,.1);color:var(--danger);border:1px solid rgba(239,68,68,.3)}
.mode-badge.mode-recovery{background:rgba(6,182,212,.1);color:var(--info);border:1px solid rgba(6,182,212,.3)}
.mode-badge.mode-maintenance{background:rgba(139,92,246,.1);color:var(--brand);border:1px solid rgba(139,92,246,.3)}
.section-title{font:600 9px/1 var(--font-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--text-2);padding-bottom:5px;border-bottom:1px solid var(--border);margin:16px 0 9px}
.mode-banner{display:flex;align-items:center;gap:10px;padding:9px 13px;border-radius:var(--r-lg);border:1px solid var(--border);background:var(--bg-surface);margin-bottom:12px;position:relative;overflow:hidden}
.mode-banner::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px}
.mode-banner.mode-normal::before{background:var(--ok)}
.mode-banner.mode-degraded::before{background:var(--warn)}
.mode-banner.mode-readonly::before,.mode-banner.mode-quarantined::before{background:var(--danger)}
.mode-banner.mode-recovery::before{background:var(--info)}
.mode-banner.mode-maintenance::before{background:var(--brand)}
.mode-banner-pulse{position:relative;width:22px;height:22px;flex-shrink:0}
.mode-banner-pulse::before,.mode-banner-pulse::after{content:'';position:absolute;inset:0;border-radius:50%;background:var(--ok);opacity:0;animation:pulse-ring 3s ease-out infinite}
.mode-banner-pulse::after{animation-delay:1.5s}
.mode-banner-pulse-dot{position:absolute;inset:7px;border-radius:50%;background:var(--ok)}
.mode-banner-info{flex:1;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.mode-banner-state{font:800 13px/1 var(--font-mono);color:var(--ok);letter-spacing:.05em}
.mode-banner-desc{font:400 10px var(--font-mono);color:var(--text-2)}
.topo-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px}
.topo-node{display:flex;align-items:center;gap:7px;padding:7px 9px;background:var(--bg-surface-2);border:1px solid var(--border);border-radius:var(--r-sm);transition:border-color .15s,box-shadow .15s}
.topo-node.topo-ok{border-color:rgba(16,185,129,.2)}
.topo-node.topo-ok:hover{box-shadow:0 0 0 1px rgba(16,185,129,.2),0 4px 16px var(--ok-dim);border-color:rgba(16,185,129,.35)}
.topo-node.topo-warn{border-color:rgba(245,158,11,.2)}
.topo-node.topo-warn:hover{box-shadow:0 0 0 1px rgba(245,158,11,.2),0 4px 16px var(--warn-dim);border-color:rgba(245,158,11,.35)}
.topo-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}
.topo-dot.d-ok{background:var(--ok);animation:live-beat 4s ease-in-out infinite}
.topo-dot.d-warn{background:var(--warn);animation:live-beat 2s ease-in-out infinite}
.topo-info{display:flex;flex-direction:column;gap:2px}
.topo-name{font:600 10px var(--font-body);color:var(--text)}
.topo-status{font:400 9px var(--font-mono);color:var(--text-2)}
.action-row{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:12px}
.stream-live-dot{width:4px;height:4px;border-radius:50%;background:var(--ok);animation:live-beat 2s ease-in-out infinite}
.timeline-panel{background:var(--bg-surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:11px 15px 13px;margin-bottom:12px;position:relative;overflow:hidden}
.timeline-panel::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--brand),transparent)}
.timeline-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:11px;padding-bottom:6px;border-bottom:1px solid var(--border);gap:10px;flex-wrap:wrap}
.tl-badge{display:inline-flex;align-items:center;gap:4px;padding:2px 7px;border-radius:100px;font:700 8px var(--font-mono);letter-spacing:.08em;background:rgba(99,102,241,.1);color:var(--brand);border:1px solid rgba(99,102,241,.25)}
.tl-badge-dot{width:4px;height:4px;border-radius:50%;background:var(--brand);animation:live-beat 2.2s ease-in-out infinite}
.timeline{position:relative;display:flex;flex-direction:column}
.timeline::before{content:'';position:absolute;left:96px;top:7px;bottom:9px;width:1px;background:linear-gradient(180deg,transparent,var(--border-strong) 6%,var(--border-strong) 94%,transparent)}
.tl-entry{position:relative;display:grid;grid-template-columns:86px 1fr;gap:20px;padding:4px 0;align-items:start}
.tl-time{display:flex;flex-direction:column;align-items:flex-end;gap:1px;padding-top:1px}
.tl-clock{font:600 10px var(--font-mono);color:var(--text-2)}
.tl-rel{font:400 8px var(--font-mono);color:var(--text-2)}
.tl-node{position:absolute;left:91px;top:5px;width:11px;height:11px;border-radius:50%;border:2px solid var(--bg-base);z-index:2;background:var(--text-2)}
.tl-node.tl-ok{background:var(--ok);box-shadow:0 0 0 3px rgba(16,185,129,.12)}
.tl-node.tl-info{background:var(--info);box-shadow:0 0 0 3px rgba(6,182,212,.1)}
.tl-node.tl-accent{background:var(--brand);box-shadow:0 0 0 3px rgba(99,102,241,.12)}
.tl-node.tl-warn{background:var(--warn);box-shadow:0 0 0 3px rgba(245,158,11,.14);animation:live-beat 2.4s ease-in-out infinite}
.tl-node.tl-err{background:var(--danger);box-shadow:0 0 0 3px rgba(239,68,68,.16);animation:live-beat 1.6s ease-in-out infinite}
.tl-body{display:flex;flex-direction:column;gap:2px}
.tl-msg{font:500 11px/1.4 var(--font-body);color:var(--text)}
.tl-cat{font:700 8px var(--font-mono);letter-spacing:.06em;text-transform:uppercase;padding:1px 5px;border-radius:2px;margin-right:6px;vertical-align:middle}
.tl-cat-sys{background:rgba(99,102,241,.12);color:var(--brand)}
.tl-cat-db{background:rgba(6,182,212,.1);color:var(--info)}
.tl-cat-gov{background:rgba(245,158,11,.1);color:var(--warn)}
.tl-cat-queue{background:rgba(16,185,129,.1);color:var(--ok)}
.tl-cat-mode{background:rgba(139,92,246,.12);color:var(--brand)}
.tl-cat-fault{background:rgba(239,68,68,.12);color:var(--danger)}
.tl-cat-ok{background:rgba(16,185,129,.1);color:var(--ok)}
.tl-causal{font:400 9px/1.4 var(--font-mono);color:var(--text-2);display:flex;align-items:flex-start;gap:5px;margin-top:1px}
.tl-causal::before{content:'';width:8px;height:8px;border-left:1px solid var(--border-strong);border-bottom:1px solid var(--border-strong);border-radius:0 0 0 2px;flex-shrink:0;margin-top:-1px}
.tl-entry.tl-last .tl-msg{color:var(--info)}
.tl-entry.tl-enter{animation:tl-enter .5s cubic-bezier(.2,.7,.2,1) both}
.tl-entry.tl-enter .tl-node{animation:tl-node-flash .7s ease both}
.tl-causal::before{animation:tl-elbow 2.4s ease-in-out infinite}
.tl-causal::after{content:'';position:absolute;left:3px;top:50%;width:4px;height:4px;border-radius:50%;background:var(--brand);opacity:0;animation:tl-spark 2.4s ease-in-out infinite}
.tl-causal{position:relative;padding-left:0}
.tl-stream-flag{display:inline-flex;align-items:center;gap:4px;font:700 8px var(--font-mono);letter-spacing:.06em;color:var(--ok);margin-left:8px}
.tl-stream-flag.paused{color:var(--text-2)}
.esc-arrow{animation:esc-pulse 1.7s ease-in-out infinite}
.esc-chain .esc-arrow:nth-of-type(1){animation-delay:0s}
.esc-chain .esc-arrow:nth-of-type(2){animation-delay:.2s}
.esc-chain .esc-arrow:nth-of-type(3){animation-delay:.4s}
.esc-chain .esc-arrow:nth-of-type(4){animation-delay:.6s}
.console-note{font:400 11px/1.55 var(--font-mono);color:var(--text-2);background:rgba(99,102,241,.04);border:1px solid var(--border);border-left:2px solid var(--accent);border-radius:var(--r-sm);padding:9px 13px;margin-bottom:14px}
.mode-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:6px}
.mode-tile{background:var(--bg-surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:12px 14px;position:relative;overflow:hidden;display:flex;flex-direction:column;gap:7px;min-height:124px}
.mode-tile::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--border-strong)}
.mode-tile.m-normal::before{background:var(--ok)}
.mode-tile.m-degraded::before{background:var(--warn)}
.mode-tile.m-readonly::before,.mode-tile.m-quarantined::before{background:var(--danger)}
.mode-tile.m-recovery::before{background:var(--info)}
.mode-tile.m-maintenance::before{background:var(--brand)}
.mode-tile.current{border-color:rgba(99,102,241,.4);box-shadow:0 0 0 1px rgba(99,102,241,.15),0 6px 24px rgba(0,0,0,.5)}
.mode-tile-top{display:flex;align-items:center;justify-content:space-between;gap:8px}
.mode-tile-name{font:800 13px var(--font-mono);letter-spacing:.04em;color:var(--text)}
.mode-tile-badge{font:700 8px var(--font-mono);letter-spacing:.06em;padding:2px 7px;border-radius:100px;text-transform:uppercase;white-space:nowrap}
.mode-tile-badge.cur{background:rgba(99,102,241,.15);color:var(--brand)}
.mode-tile-badge.reach{background:rgba(16,185,129,.1);color:var(--ok)}
.mode-tile-badge.block{background:rgba(55,74,98,.25);color:var(--text-2)}
.mode-tile-desc{font:400 10px/1.5 var(--font-mono);color:var(--text-2);flex:1}
.mode-tile-btn{align-self:flex-start;font:600 10px var(--font-mono);padding:5px 11px;border-radius:var(--r-sm);border:1px solid var(--border-strong);background:rgba(255,255,255,.03);color:var(--text-2);cursor:pointer;transition:border-color .12s,color .12s,background .12s}
.mode-tile-btn:hover{border-color:var(--accent);color:var(--info);background:rgba(99,102,241,.1)}
.mode-tile-btn:disabled{opacity:.4;cursor:not-allowed}
.fe-table{width:100%;border-collapse:collapse;margin-bottom:6px}
.fe-table th{text-align:left;font:600 9px var(--font-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--text-2);padding:6px 10px;border-bottom:1px solid var(--border)}
.fe-table td{padding:9px 10px;border-bottom:1px solid rgba(22,32,48,.6);font:400 11px var(--font-mono);color:var(--text-2);vertical-align:middle}
.fe-table tr:hover td{background:rgba(255,255,255,.02)}
.fe-name{color:var(--text);font-weight:600}
.fe-target{font:600 10px var(--font-mono);padding:2px 8px;border-radius:100px}
.fe-target.t-readonly,.fe-target.t-quarantined{background:rgba(239,68,68,.1);color:var(--danger)}
.fe-target.t-degraded{background:rgba(245,158,11,.1);color:var(--warn)}
.fe-target.t-recovery{background:rgba(6,182,212,.1);color:var(--info)}
.fe-sim-btn{font:600 10px var(--font-mono);padding:5px 12px;border-radius:var(--r-sm);border:1px solid var(--border-strong);background:rgba(255,255,255,.03);color:var(--text-2);cursor:pointer;transition:border-color .12s,color .12s,background .12s}
.fe-sim-btn:hover{border-color:var(--danger);color:var(--danger);background:rgba(239,68,68,.08)}
.esc-chain{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.esc-step{font:600 10px var(--font-mono);padding:6px 11px;border-radius:var(--r-sm);background:var(--bg-surface-2);border:1px solid var(--border);color:var(--text-2)}
.esc-arrow{color:var(--text-2);font-size:13px}
.q-strip{display:grid;grid-template-columns:repeat(6,1fr);gap:7px;margin-bottom:12px}
.q-stat{background:var(--bg-surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:10px 13px;position:relative;overflow:hidden}
.q-stat::before{content:'';position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,rgba(99,102,241,.2),transparent)}
.q-stat-val{font:800 1.6rem/1 var(--font-body);letter-spacing:-.03em;color:var(--text)}
.q-stat-label{font:600 9px var(--font-mono);letter-spacing:.06em;text-transform:uppercase;color:var(--text-2);margin-top:5px}
.topo-wrap{background:var(--bg-surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:10px;margin-bottom:10px;box-shadow:inset 0 1px 0 rgba(255,255,255,.02)}
.topo-svg{width:100%;height:auto;display:block;background:radial-gradient(ellipse at 50% -10%,rgba(99,102,241,.05),transparent 55%)}
.topo-band{font:700 9px var(--font-mono);letter-spacing:.1em;fill:var(--text-2);opacity:.55;text-transform:uppercase}
.topo-edge{stroke:#22324a;stroke-width:1.4;fill:none}
.topo-edge.flow{stroke:var(--border-strong);stroke-dasharray:5 5;animation:topo-flow 1.1s linear infinite}
.topo-edge.ctrl{stroke:#8b5cf6;stroke-opacity:.45;stroke-width:1.3;stroke-dasharray:2 4}
.topo-rect{fill:#0b1119;stroke-width:1.5}
.topo-node:hover .topo-rect{fill:#0e1626}
.topo-label{font:600 13px var(--font-mono);fill:var(--text)}
.topo-sub{font:400 10px var(--font-mono);fill:var(--text-2)}
.topo-legend{display:flex;gap:18px;flex-wrap:wrap;padding:2px 4px 4px}
.tl-leg{display:inline-flex;align-items:center;gap:6px;font:400 10px var(--font-mono);color:var(--text-2)}
.tl-leg-dot{width:7px;height:7px;border-radius:50%}
.tl-leg-line{width:18px;height:0;border-top:1.5px solid var(--border-strong)}
.tl-leg-line.ctrl{border-top:1.5px dashed #8b5cf6}
.policy-strip{display:flex;gap:10px;margin-bottom:18px}
.policy-stat{background:var(--bg-surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:10px 16px 8px;min-width:90px}
.policy-stat-val{font:700 26px/1 var(--font-mono);color:var(--text)}
.policy-stat-val.ps-pass{color:var(--ok)}
.policy-stat-val.ps-warn{color:var(--warn)}
.policy-stat-val.ps-fail{color:var(--danger)}
.policy-stat-label{font:600 9px var(--font-mono);letter-spacing:.06em;text-transform:uppercase;color:var(--text-2);margin-top:5px}
.policy-history{width:100%;border-collapse:collapse;font-size:12px}
.policy-history th{font:600 9px var(--font-mono);letter-spacing:.06em;text-transform:uppercase;color:var(--text-2);text-align:left;padding:4px 8px 8px;border-bottom:1px solid var(--border)}
.policy-history td{padding:7px 8px;border-bottom:1px solid #0e1827;vertical-align:middle}
.policy-history tr:last-child td{border-bottom:none}
.pol-cat{font:500 10px var(--font-mono);color:var(--text-2);text-transform:uppercase;letter-spacing:.05em}
.pol-name{font:500 12px var(--font-mono);color:var(--text)}
.pol-detail{font:400 11px var(--font-mono);color:var(--text-2);max-width:340px}
.pol-runid{font:400 10px var(--font-mono);color:var(--border-strong)}
.pol-ts{font:400 11px var(--font-mono);color:var(--text-2)}
.policy-trend{display:flex;gap:3px;align-items:flex-end;height:36px;margin-top:4px}

/* VayuOS operator page header */
.os-page-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp-4);margin:0 0 var(--sp-8)}
.os-page-title{font:600 var(--text-2xl)/1.15 var(--font-head);color:var(--text);margin:0}
.os-page-sub{font:400 var(--text-sm)/1.5 var(--font-body);color:var(--text-2);margin:.35rem 0 0}
/* Operator action status toast */
.action-msg{position:fixed;bottom:16px;right:16px;z-index:500;max-width:360px;padding:10px 14px;border:1px solid var(--ok);border-radius:var(--r-sm);background:var(--bg-surface-2);color:var(--text);font:500 var(--text-sm) var(--font-body);box-shadow:var(--sh-lg);opacity:0;transform:translateY(8px);transition:opacity .2s,transform .2s}
.action-msg.visible{opacity:1;transform:translateY(0)}
.action-msg.is-error{border-color:var(--danger)}

/* ============================================================
   Post manager — status pills + status filter segmented control
   ============================================================ */
.status-pill{display:inline-flex;align-items:center;gap:.35em;font:600 var(--text-xs) var(--font-body);padding:.2em .6em;border-radius:999px;border:1px solid var(--border);white-space:nowrap}
.status-pill--live{color:var(--ok);background:var(--ok-dim);border-color:transparent}
.status-pill--draft{color:var(--warn);background:var(--warn-dim);border-color:transparent}
.seg-filter{display:inline-flex;gap:2px;margin-left:auto;background:var(--bg-surface-2);border:1px solid var(--border);border-radius:var(--r-sm);padding:2px}
.seg-btn{appearance:none;border:0;background:transparent;color:var(--text-2);font:600 var(--text-sm) var(--font-body);padding:.35em .8em;border-radius:calc(var(--r-sm) - 2px);cursor:pointer;transition:background var(--t-fast),color var(--t-fast)}
.seg-btn .muted{font-weight:500;opacity:.7;margin-left:.3em}
.seg-btn:hover{color:var(--text)}
.seg-btn.is-active{background:var(--bg-surface);color:var(--text);box-shadow:var(--sh-sm)}
/* Status tabs are now <a> links (server-side filtering) — strip the underline. */
.vp-os a.seg-btn{text-decoration:none}

/* ── Posts manager: filter bar + pagination (CSP-safe, no inline styles) ───── */
.vp-os .posts-filter{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2)}
.vp-os .posts-filter .search-input{min-width:200px}
.vp-os .posts-filter-date{display:inline-flex;align-items:center;gap:.4em;font-size:var(--text-xs);color:var(--text-3);white-space:nowrap}
.vp-os .posts-filter-date .input{width:auto}
.vp-os .select--inline,.vp-os .select--sm{width:auto;padding-top:.375rem;padding-bottom:.375rem;font-size:var(--text-xs)}

.vp-os .pager{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-3);margin-top:var(--sp-4);padding-top:var(--sp-4);border-top:1px solid var(--border)}
.vp-os .pager-info{color:var(--text-3);font-size:var(--text-sm)}
.vp-os .pager-info strong{color:var(--text-2);font-weight:600}
.vp-os .pager-controls{display:inline-flex;flex-wrap:wrap;align-items:center;gap:2px;margin-left:auto}
.vp-os .pager-btn{display:inline-flex;align-items:center;justify-content:center;min-width:34px;height:34px;padding:0 .6em;border:1px solid var(--border);border-radius:var(--r-sm);background:var(--bg-surface-2);color:var(--text-2);font:600 var(--text-sm) var(--font-body);text-decoration:none;cursor:pointer;transition:background var(--t-fast),color var(--t-fast),border-color var(--t-fast)}
.vp-os a.pager-btn:hover{background:var(--bg-surface-3);color:var(--text);border-color:var(--border-strong)}
.vp-os .pager-btn.is-current{background:var(--brand);border-color:var(--brand);color:#fff;cursor:default}
.vp-os .pager-btn.is-disabled{opacity:.4;cursor:not-allowed;pointer-events:none}
.vp-os .pager-gap{padding:0 .3em;color:var(--text-3)}
.vp-os .pager-jump{display:inline-flex;align-items:center;gap:.4em;font-size:var(--text-xs);color:var(--text-3)}
.vp-os .pager-jump-label{display:inline-flex;align-items:center;gap:.4em;white-space:nowrap}
.vp-os .pager-jump-input{width:5em;text-align:center}
.vp-os .pager-jump-total{white-space:nowrap}
@media (max-width:720px){
  .vp-os .pager{flex-direction:column;align-items:stretch}
  .vp-os .pager-controls{margin-left:0;justify-content:center}
  .vp-os .pager-jump{justify-content:center}
}


/* ── VayuMail panel (CSP-safe: no inline styles) ───────────────────────────── */
.vmtabs { display: flex; flex-wrap: wrap; gap: .25rem; margin: .25rem 0 1rem; border-bottom: 1px solid var(--border); }
.vmtabs .tab { padding: .5rem .85rem; }
.vm-row { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin-top: .75rem; }
.vm-row--end { align-items: flex-end; }
/* The certificate diagnostic's re-check wrapper: the swap target for
   "Re-check now" (ADR-0160). Its own block so the button and the "checked at"
   stamp sit above the checks rather than beside them. */
.vm-recheck { display: block; }
.vm-recheck > .vm-row { margin-top: 0; margin-bottom: .75rem; justify-content: space-between; }
.vm-grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; }
.vm-actions { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: .75rem; align-items: center; }
.vm-bulk { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin: .5rem 0 .75rem; padding: .5rem .75rem; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-surface-2); }
.vm-bulk[hidden] { display: none; }
.vm-move { display: inline-flex; align-items: center; }
.vm-quota-input { width: 6rem; }
.vm-quota { margin: .25rem 0 .75rem; }
.vm-quota-meta { margin-bottom: .3rem; }
.vm-quota-track { height: 8px; border-radius: 999px; background: var(--border-strong); overflow: hidden; max-width: 28rem; }
.vm-quota-fill { height: 100%; width: 0; border-radius: 999px; transition: width .3s ease; background: #4f7d5a; }
.vm-quota-fill--warn { background: #d9844f; }
.vm-quota-fill--full { background: #d9534f; }
.vm-quota-full { color: #d9534f; margin-top: .35rem; }
.input--sm { padding: .25rem .5rem; font-size: .85rem; height: auto; width: auto; }
.vm-check { width: 1px; white-space: nowrap; text-align: center; }
.vm-check-row, .vm-check input[type=checkbox] { cursor: pointer; }
.btn--ghost { background: transparent; border-color: transparent; padding-left: .4rem; padding-right: .4rem; }
.btn--ghost:hover { background: var(--bg-surface-2); }
.vm-grow { flex: 1 1 12rem; }
.vm-suffix { color: var(--text-3); font-size: .85rem; margin-left: .35rem; }
/* The message body must NOT be its own scroll container. It used to carry
   max-height: 65vh + overflow: auto, which put a scrollbar inside the reading
   pane's scrollbar and squeezed the text into 65% of the window even in full
   view, where a whole screen was available. The pane scrolls; the body flows.
   Only the raw source keeps a cap (.vm-raw below) — that one really is a dump. */
.vm-pre { white-space: pre-wrap; word-break: break-word; margin: 0; }
.vm-stat { font-size: 1.6rem; font-weight: 600; }
.vm-section-title { margin-top: 1.5rem; }
.vm-break { word-break: break-all; }

/* ── VayuMail inbox — sticky toolbar, avatars, list polish (v-inbox) ───────── */
.vp-os .vm-poller { display: none; }
.vp-os .vm-toolbar {
  position: sticky; top: 0; z-index: 6;
  display: flex; align-items: center; justify-content: space-between;
  gap: .75rem; flex-wrap: wrap;
  padding: .55rem .7rem; margin: 0 0 .6rem;
  background: var(--bg-glass); backdrop-filter: blur(10px);
  border: 1px solid var(--border); border-radius: 12px;
}
.vp-os .vm-toolbar-id { display: flex; align-items: center; gap: .55rem; min-width: 0; }
.vp-os .vm-toolbar-meta { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.vp-os .vm-toolbar-meta strong { overflow-wrap: anywhere; }
.vp-os .vm-toolbar-actions { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.vp-os .vm-toolbar-actions .vm-search { margin: 0; }

.vp-os .vm-av {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%; flex: 0 0 auto;
  font-size: .72rem; font-weight: 700; letter-spacing: .02em;
  color: #fff; text-transform: uppercase; user-select: none;
}
.vp-os .vm-av--0 { background: #6366f1; }
.vp-os .vm-av--1 { background: #0ea5e9; }
.vp-os .vm-av--2 { background: #10b981; }
.vp-os .vm-av--3 { background: #f59e0b; }
.vp-os .vm-av--4 { background: #ec4899; }
.vp-os .vm-av--5 { background: #8b5cf6; }
/* Photo avatar: the uploaded profile picture, clipped to the same circle as the
   initials chip. No background so a transparent PNG reads cleanly. */
.vp-os .vm-av--img { background: none; padding: 0; overflow: hidden; }
.vp-os .vm-av--img img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block; }

/* Per-domain mailbox tabs — pure CSS (hidden radio + label + :checked sibling
   rules), so no JS and no inline styles are needed (CSP-safe). Rules are emitted
   for up to 10 domains; installs with more still work, only tabs 11+ won't be
   selectable (no real install has that many mail domains). */
.vp-os .vm-domtabs { position: relative; }
.vp-os .vm-domtab-radio { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.vp-os .vm-domtabs-strip { display: flex; gap: .35rem; flex-wrap: wrap; margin-bottom: var(--sp-3); border-bottom: 1px solid var(--border, rgba(255,255,255,.08)); }
.vp-os .vm-domtab-tab { cursor: pointer; padding: .5rem .95rem; border-radius: 10px 10px 0 0; font-weight: 600; color: var(--text-2, #9aa4b2); user-select: none; display: inline-flex; align-items: center; gap: .4rem; border: 1px solid transparent; border-bottom: none; margin-bottom: -1px; transition: color .12s, background .12s; }
.vp-os .vm-domtab-tab:hover { color: var(--text, #e6edf3); }
.vp-os .vm-domtab-panel { display: none; }
.vp-os .vm-domtab-radio:focus-visible + .vm-domtab-radio + .vm-domtabs-strip label,
.vp-os .vm-domtabs-strip label:focus-within { outline: 2px solid var(--brand, #3b82f6); outline-offset: 2px; }
.vp-os #vm-dt-0:checked ~ .vm-domtab-panel[data-i="0"], .vp-os #vm-dt-1:checked ~ .vm-domtab-panel[data-i="1"],
.vp-os #vm-dt-2:checked ~ .vm-domtab-panel[data-i="2"], .vp-os #vm-dt-3:checked ~ .vm-domtab-panel[data-i="3"],
.vp-os #vm-dt-4:checked ~ .vm-domtab-panel[data-i="4"], .vp-os #vm-dt-5:checked ~ .vm-domtab-panel[data-i="5"],
.vp-os #vm-dt-6:checked ~ .vm-domtab-panel[data-i="6"], .vp-os #vm-dt-7:checked ~ .vm-domtab-panel[data-i="7"],
.vp-os #vm-dt-8:checked ~ .vm-domtab-panel[data-i="8"], .vp-os #vm-dt-9:checked ~ .vm-domtab-panel[data-i="9"] { display: block; }
.vp-os #vm-dt-0:checked ~ .vm-domtabs-strip label[for="vm-dt-0"], .vp-os #vm-dt-1:checked ~ .vm-domtabs-strip label[for="vm-dt-1"],
.vp-os #vm-dt-2:checked ~ .vm-domtabs-strip label[for="vm-dt-2"], .vp-os #vm-dt-3:checked ~ .vm-domtabs-strip label[for="vm-dt-3"],
.vp-os #vm-dt-4:checked ~ .vm-domtabs-strip label[for="vm-dt-4"], .vp-os #vm-dt-5:checked ~ .vm-domtabs-strip label[for="vm-dt-5"],
.vp-os #vm-dt-6:checked ~ .vm-domtabs-strip label[for="vm-dt-6"], .vp-os #vm-dt-7:checked ~ .vm-domtabs-strip label[for="vm-dt-7"],
.vp-os #vm-dt-8:checked ~ .vm-domtabs-strip label[for="vm-dt-8"], .vp-os #vm-dt-9:checked ~ .vm-domtabs-strip label[for="vm-dt-9"] {
  color: var(--text, #e6edf3); background: var(--surface-2, rgba(255,255,255,.05)); border-color: var(--border, rgba(255,255,255,.08)); }

/* Per-mailbox address book (Contacts panel + save-contact control). */
.vp-os .vm-contacts { display: flex; flex-direction: column; gap: var(--sp-3); }
.vp-os .vm-contacts-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); flex-wrap: wrap; }
.vp-os .vm-contacts-title { margin: 0; font-size: 1.05rem; }
.vp-os .vm-contacts-sub { margin: 0; }
.vp-os .vm-contacts-add { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; }
.vp-os .vm-contacts-add .input { flex: 1 1 160px; min-width: 0; }
.vp-os .vm-contacts-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.vp-os .vm-contact { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) 0; border-top: 1px solid var(--border, rgba(255,255,255,.08)); }
.vp-os .vm-contact:first-child { border-top: 0; }
.vp-os .vm-contact-id { display: flex; align-items: center; gap: var(--sp-2); text-decoration: none; color: inherit; flex: 1 1 auto; min-width: 0; }
.vp-os .vm-contact-meta { display: flex; flex-direction: column; min-width: 0; }
.vp-os .vm-contact-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vp-os .vm-contact-mail { color: var(--text-2, #9aa4b2); font-size: .82rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vp-os .vm-contact-del { flex: 0 0 auto; }
.vp-os .vm-contact-saved { color: #10b981; }

.vp-os .vm-list td { vertical-align: middle; }
.vp-os .vm-from { display: flex; align-items: center; gap: .55rem; min-width: 0; text-decoration: none; color: var(--text); }
.vp-os .vm-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 15rem; }
.vp-os .vm-subj a { color: var(--text); text-decoration: none; }
.vp-os .vm-subj a:hover { text-decoration: underline; }
.vp-os .vm-date { white-space: nowrap; }
.vp-os tr.vm-unread .vm-name,
.vp-os tr.vm-unread .vm-subj a { font-weight: 700; }
.vp-os tr.vm-unread .vm-subj a::before {
  content: ""; display: inline-block; width: 7px; height: 7px;
  border-radius: 50%; background: var(--accent);
  margin-right: .5rem; vertical-align: middle;
}
.vp-os .vm-tab-badge {
  display: inline-block; min-width: 1.15rem; padding: 0 .32rem; margin-left: .3rem;
  font-size: .68rem; font-weight: 700; line-height: 1.15rem; text-align: center;
  color: #fff; background: var(--accent); border-radius: 999px;
}

/* ── VayuMail message reader (v-reader) ────────────────────────────────────── */
.vp-os .vm-reader-top { display: flex; align-items: center; justify-content: space-between; gap: .5rem; margin-bottom: .6rem; }
.vp-os .vm-reader-nav { display: inline-flex; gap: .25rem; }
.vp-os .vm-reader-nav [aria-disabled="true"] { opacity: .4; pointer-events: none; }

.vp-os .vm-msg-head { padding: .75rem 0 .85rem; border-bottom: 1px solid var(--border); margin-bottom: 1rem; }
.vp-os .vm-msg-subject { font-size: var(--text-xl); font-weight: 700; line-height: 1.3; margin-bottom: .6rem; }
.vp-os .vm-msg-from-row { display: flex; align-items: flex-start; gap: .65rem; }
.vp-os .vm-msg-from-row .vm-av { width: 38px; height: 38px; font-size: .82rem; }
.vp-os .vm-msg-from-meta { min-width: 0; }
.vp-os .vm-msg-fromname { overflow-wrap: anywhere; }

.vp-os .vm-pgp { display: inline-block; vertical-align: middle; margin-left: .5rem; padding: .1rem .45rem; font-size: .7rem; font-weight: 600; border-radius: 999px; }
.vp-os .vm-pgp--enc { color: var(--accent); background: var(--accent-dim); }
.vp-os .vm-pgp--sig { color: var(--ok); background: var(--ok-dim); }

.vp-os .vm-attach { margin: 0 0 1rem; }
.vp-os .vm-attach-list { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .4rem; }
.vp-os .vm-attach-chip {
  display: inline-flex; align-items: center; gap: .5rem; max-width: 22rem;
  padding: .4rem .65rem; border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg-surface-2); color: var(--text); text-decoration: none;
  transition: border-color .15s ease, background .15s ease;
}
.vp-os .vm-attach-chip:hover { border-color: var(--accent); background: var(--bg-surface-3); }
.vp-os .vm-attach-ico { font-size: 1.1rem; flex: 0 0 auto; }
.vp-os .vm-attach-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vp-os .vm-attach-size { color: var(--text-3); font-size: .72rem; flex: 0 0 auto; }

.vp-os .vm-html { line-height: 1.6; overflow-wrap: anywhere; }
.vp-os .vm-html img { max-width: 100%; height: auto; }
.vp-os .vm-html a { color: var(--accent); }

.vp-os .vm-quote { margin-top: .5rem; }
.vp-os .vm-quote > summary {
  cursor: pointer; display: inline-block; list-style: none;
  padding: .1rem .55rem; border-radius: 999px; font-size: .72rem;
  color: var(--text-2); background: var(--bg-surface-2); border: 1px solid var(--border);
  user-select: none;
}
.vp-os .vm-quote > summary::-webkit-details-marker { display: none; }
.vp-os .vm-quote[open] > summary { margin-bottom: .5rem; }
.vp-os .vm-pre--quoted { color: var(--text-2); border-left: 2px solid var(--border-strong); padding-left: .75rem; }

@media print {
  /* Print exactly the open message: hide everything, then re-show the
     reader (visibility cascades back on for its subtree) pinned to the
     page origin. Chrome, list, toolbars and action buttons never print. */
  body * { visibility: hidden !important; }
  .vm-reader, .vm-reader * { visibility: visible !important; }
  .vm-reader {
    position: absolute !important; left: 0 !important; top: 0 !important;
    width: 100% !important; margin: 0 !important;
    border: 0 !important; box-shadow: none !important;
    background: #fff !important; color: #000 !important;
  }
  .vm-reader-top, .vm-actions, .vm-rawwrap { display: none !important; }
  .vm-msg-body { max-width: none !important; }
}

/* ── VayuMail split reading pane (v-split) ─────────────────────────────────── */
/* List + in-place reader side by side. The reader loads via HTMX into
   #vm-readpane; pane actions fire HX-Trigger:vm-mail-changed to refresh the
   list. Collapses to one column on narrow screens (the pane overlays the list
   only while a message is open). */
.vp-os .vm-split { display: grid; grid-template-columns: minmax(20rem, 26rem) minmax(0, 1fr); gap: .9rem; align-items: start; }
.vp-os .vm-inbox-list { min-width: 0; }
.vp-os .vm-readpane { min-width: 0; position: sticky; top: .5rem; }
.vp-os .vm-readpane .vm-reader { margin: 0; }
.vp-os .vm-readpane-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; gap: .4rem; min-height: 16rem;
  border: 1px dashed var(--border-strong); border-radius: 12px;
  background: var(--bg-glass); padding: 2rem 1rem;
}
.vp-os .vm-readpane-empty-ico { font-size: 2rem; opacity: .5; }
/* Active row highlight (set by delegated JS on open). */
.vp-os tr.vm-active > td { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.vp-os tr.vm-active .vm-subj a { text-decoration: underline; }

/* Collapse the split while nothing is open: the list gets the full width
   and the dashed placeholder disappears; opening a message brings the
   two-column split (or the narrow-screen overlay) back. Browsers without
   :has() keep the previous always-split behavior. */
.vp-os .vm-split:has(.vm-readpane-empty) { grid-template-columns: 1fr; }
.vp-os .vm-split:has(.vm-readpane-empty) .vm-readpane { display: none; }

/* Full view (⛶): the open message overlays the work area — but only the area
   RIGHT of the fixed sidebar, and above it, so it never slides under the rail.
   left offsets by the sidebar width; z-index clears the sidebar's 200. */
.vp-os #vm-readpane.vm-readpane--full {
  position: fixed; top: 1.25rem; right: 1.25rem; bottom: 1.25rem;
  left: calc(var(--sidebar-w) + 1.25rem); z-index: 240; overflow: auto;
  background: var(--bg-surface); border: 1px solid var(--border-strong);
  border-radius: 14px; padding: 1rem;
  box-shadow: 0 24px 64px rgb(0 0 0 / .45);
}
.vp-os #vm-readpane.vm-readpane--full .vm-reader { box-shadow: none; }
/* At <=768px the sidebar is off-canvas (see the rail's transform), so the
   overlay spans full width. */
@media (max-width: 768px) {
  .vp-os #vm-readpane.vm-readpane--full { left: 1.25rem; }
}

/* Premium touches: rows glide, unread carries an accent bar, the reader
   arrives with a soft rise, tabs behave like segmented pills. */
.vp-os .vm-list tbody tr { transition: background .14s ease; }
.vp-os .vm-list tbody tr:hover > td { background: color-mix(in srgb, var(--accent) 6%, transparent); }
.vp-os .vm-list tbody td { padding-top: .6rem; padding-bottom: .6rem; }
.vp-os tr.vm-unread > td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.vp-os .vm-readpane .vm-reader {
  box-shadow: 0 10px 34px rgb(0 0 0 / .22);
  animation: vm-reader-in .18s ease-out;
}
@keyframes vm-reader-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .vp-os .vm-readpane .vm-reader { animation: none; }
}
.vmtabs .tab { border-radius: 9px 9px 0 0; transition: color .14s ease, background .14s ease; }
.vmtabs .tab:hover { background: var(--bg-surface-2); }

/* Narrow screens: single column. The pane hides until a message is opened,
   then it shows above the list as a full-width reader with a Close button. */
@media (max-width: 60rem) {
  .vp-os .vm-split { grid-template-columns: 1fr; }
  .vp-os .vm-readpane { position: static; }
  /* Empty pane takes no space on mobile; the reader (with .vm-reader) shows. */
  .vp-os .vm-readpane:has(.vm-readpane-empty) { display: none; }
  .vp-os .vm-readpane:has(.vm-reader) { order: -1; margin-bottom: .6rem; }
}

/* ── VayuMail conversation threading (v-thread) ────────────────────────────── */
.vp-os .vm-thread-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.5rem; height: 1.25rem; padding: 0 .4rem; margin-left: .4rem;
  border: 1px solid var(--border-strong); border-radius: 999px;
  background: transparent; color: var(--text-2);
  font-size: .72rem; font-weight: 700; cursor: pointer;
}
.vp-os .vm-thread-count:hover { border-color: var(--accent); color: var(--accent); }
.vp-os .vm-thread-count--open { background: var(--accent); border-color: var(--accent); color: #fff; }
.vp-os tr.vm-thread-child > td { background: color-mix(in srgb, var(--border) 40%, transparent); }
.vp-os tr.vm-thread-child .vm-subj { padding-left: 1.4rem; }

/* ── VayuMail vacation autoresponder (v-ooo) ───────────────────────────────── */
.vp-os .vm-ooo { border: 1px solid var(--border); border-radius: 10px; padding: .35rem .65rem; margin: 0 0 .5rem; }
.vp-os .vm-ooo > summary { cursor: pointer; display: flex; align-items: center; gap: .6rem; padding: .3rem 0; list-style: none; }
.vp-os .vm-ooo > summary::before { content: "▸"; opacity: .6; }
.vp-os .vm-ooo[open] > summary::before { content: "▾"; }
.vp-os .vm-ooo-form { display: flex; flex-direction: column; gap: .6rem; padding: .5rem 0 .65rem; }
.vp-os .vm-ooo-form textarea { resize: vertical; }

/* ── VayuMail composer (v-compose) ─────────────────────────────────────────── */
.vp-os .vm-row--tight { margin: 0 0 .65rem; }
.vp-os .vm-compose-actions { align-items: center; }

.vp-os .vm-chips {
  display: flex; flex-wrap: wrap; gap: .35rem; align-items: center;
  padding: .3rem .4rem; border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg-surface); min-height: 2.4rem;
}
.vp-os .vm-chips:focus-within { border-color: var(--accent); }
.vp-os .vm-chip {
  display: inline-flex; align-items: center; gap: .3rem; max-width: 100%;
  padding: .12rem .2rem .12rem .55rem; font-size: .8rem; line-height: 1.4;
  background: var(--bg-surface-3); border-radius: 999px;
}
.vp-os .vm-chip > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vp-os .vm-chip--bad { background: var(--danger-dim); color: var(--danger); }
.vp-os .vm-chip-x {
  border: 0; background: transparent; color: inherit; cursor: pointer;
  font-size: 1.05rem; line-height: 1; padding: 0 .25rem; border-radius: 999px;
}
.vp-os .vm-chip-x:hover { background: rgba(127, 127, 127, .25); }
.vp-os .vm-chip-input {
  flex: 1 1 9rem; min-width: 9rem; border: 0; outline: none; background: transparent;
  color: var(--text); font-size: var(--text-sm); padding: .25rem;
}

.vp-os .vm-dropzone {
  border: 1.5px dashed var(--border-strong); border-radius: 10px;
  padding: .85rem 1rem; text-align: center; margin-bottom: .5rem;
  transition: border-color .15s ease, background .15s ease;
}
.vp-os .vm-dropzone--over { border-color: var(--accent); background: var(--accent-dim); }
.vp-os .vm-dropzone-hint { display: block; margin-top: .3rem; }
.vp-os .vm-attach-tray { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: .85rem; }

.vp-os .vm-sig { margin: 0 0 .85rem; padding: .6rem .75rem; border: 1px solid var(--border); border-radius: 10px; background: var(--bg-surface-2); }
.vp-os .vm-sig-edit { margin-top: .5rem; }
.vp-os .vm-sig-edit > summary { cursor: pointer; font-size: var(--text-sm); color: var(--text-2); user-select: none; }
.vp-os .vm-sig-edit > summary::-webkit-details-marker { color: var(--text-3); }
.vp-os .vm-sig-edit textarea { margin-top: .5rem; }
.vp-os .vm-sig-preview { margin: .5rem 0 0; padding: .5rem .65rem; border-left: 2px solid var(--border-strong); color: var(--text-2); font-size: var(--text-sm); white-space: pre-wrap; word-break: break-word; max-height: 8rem; overflow: auto; }

.vp-os .vm-undobar {
  display: flex; align-items: center; gap: .75rem; margin-top: .6rem;
  padding: .55rem .8rem; border: 1px solid var(--accent); border-radius: 10px;
  background: var(--accent-dim); color: var(--text); font-size: var(--text-sm);
}
.vp-os .vm-undobar[hidden] { display: none; }
.vp-os .vm-undobar span { flex: 1 1 auto; }

.vp-os .vm-pgp-hint { font-size: .72rem; color: var(--text-3); margin-left: auto; }
.vp-os .vm-pgp-hint--enc { color: var(--ok); }
@media (max-width: 640px) { .vp-os .vm-pgp-hint { margin-left: 0; flex-basis: 100%; } }

/* ── VayuMail search (v-search) ────────────────────────────────────────────── */
.vp-os .vm-search-form { margin: .5rem 0 1rem; }
.vp-os .vm-search-row { display: flex; gap: .5rem; align-items: center; }
.vp-os .vm-search-row .input { flex: 1 1 auto; }
.vp-os .vm-search-filters { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin-top: .55rem; }
.vp-os .vm-search-filters .input--sm { width: auto; }
.vp-os .vm-filter-date, .vp-os .vm-filter-check {
  display: inline-flex; align-items: center; gap: .35rem;
  font-size: var(--text-sm); color: var(--text-2);
}
.vp-os .vm-search-count { margin: .25rem 0 .6rem; }
.vp-os mark { background: var(--warn-dim); color: var(--text); border-radius: 3px; padding: 0 .12em; }

/* ── VayuMail keyboard shortcuts: list cursor + help overlay (v-keys) ───────── */
.vp-os .vm-list tbody tr:hover { background: var(--bg-surface-2); }
.vp-os tr.vm-focus { background: var(--accent-dim); box-shadow: inset 3px 0 0 var(--accent); }

.vp-os .vm-help {
  max-width: 30rem; width: calc(100% - 2rem); box-sizing: border-box;
  border: 1px solid var(--border-strong); border-radius: 14px;
  background: var(--bg-surface); color: var(--text);
  padding: 1.1rem 1.25rem; box-shadow: 0 24px 64px rgba(0, 0, 0, .45);
}
.vp-os .vm-help[popover] { margin: auto; }         /* native popover: viewport-centered */
.vp-os .vm-help:not([popover]) { display: none; position: fixed; inset: 0; margin: auto; height: max-content; z-index: 2000; }
.vp-os .vm-help.vm-help--open { display: block; }
.vp-os .vm-help[popover]::backdrop { background: rgba(0, 0, 0, .45); }
.vp-os .vm-help-title { font-weight: 700; font-size: 1.05rem; margin-bottom: .85rem; }
.vp-os .vm-help-grid { display: grid; grid-template-columns: 1fr auto; gap: .45rem .9rem; align-items: center; }
.vp-os .vm-help-grid > span:nth-child(odd) { color: var(--text-2); font-size: .85rem; }
.vp-os .vm-kbd {
  justify-self: end; font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
  font-size: .72rem; color: var(--text); background: var(--bg-surface-3);
  border: 1px solid var(--border); border-radius: 6px; padding: .12rem .45rem; white-space: nowrap;
}
.vp-os .vm-help-foot { margin-top: .95rem; }


/* Live analytics indicator — pulsing dot next to the "Live" card title. */
.vp-os .live-dot {
  display: inline-block;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: var(--ok, #1db954);
  margin-right: 0.4rem;
  vertical-align: middle;
  animation: vp-live-pulse 1.6s ease-in-out infinite;
}
@keyframes vp-live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.35; transform: scale(0.7); }
}
@media (prefers-reduced-motion: reduce) {
  .vp-os .live-dot { animation: none; }
}


/* ── Editor: focus (distraction-free) mode & drop states ─────────────────── */
/* Focus mode hides the tool sidebar and widens the writing column so nothing
   competes with the prose; the topbar stays for quick exit (⌘. toggles it). */
.vp-os .editor-shell.is-focus { grid-template-columns: minmax(0, 1fr); }
.vp-os .editor-shell.is-focus .editor-sidebar { display: none; }
.vp-os .editor-shell.is-focus .editor-canvas { padding-left: max(var(--sp-4), calc((100% - 820px) / 2)); padding-right: max(var(--sp-4), calc((100% - 820px) / 2)); }
/* Typewriter room is defined once, authoritatively, further down (after the
   base focus padding rule) so it always wins the cascade on desktop while never
   applying on mobile — see the min-width:901px block near .editor-canvas base
   padding. Keeping a single source of truth avoids the ordering bug where a
   later unconditional padding-top silently defeated it. */
.vp-os .editor-shell.is-focus .editor-title { max-width: 820px; margin-left: auto; margin-right: auto; padding-left: var(--sp-1); }

/* Dimming the non-active blocks in focus mode keeps the eye on the current line
   without hiding context. */
/* Active-line spotlight: in focus mode, once the caret is in a block
   (.is-spotlight, set by the editor JS), that block glows and the rest recede.
   The eye rests on the current line without losing the surrounding context.
   Only active alongside .is-spotlight, so placing the caret in the title (or
   before any click) never greys the whole canvas. */
.vp-os .editor-shell.is-focus .eblock { transition: opacity var(--t-fast); }
.vp-os .editor-shell.is-focus.is-spotlight .eblock { opacity: 0.32; }
.vp-os .editor-shell.is-focus.is-spotlight .eblock.is-caret { opacity: 1; }

/* Image paste / drag-and-drop target highlight on the canvas. */
.vp-os .editor-canvas.is-dragover {
  outline: 2px dashed var(--brand);
  outline-offset: -8px;
  background: var(--brand-dim);
  border-radius: var(--r-md);
}

/* ── Editor: inline formatting toolbar (floating on text selection) ───────── */
.vp-os .fmt-bar {
  position: absolute;
  display: none;
  gap: 2px;
  padding: 4px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg, 0 12px 32px rgba(0,0,0,0.4));
  z-index: 320;
}
.vp-os .fmt-bar__btn {
  min-width: 30px;
  height: 30px;
  padding: 0 8px;
  border: 0;
  border-radius: var(--r-sm, 6px);
  background: transparent;
  color: var(--text);
  font-size: var(--text-sm);
  cursor: pointer;
  line-height: 1;
}
.vp-os .fmt-bar__btn:hover { background: var(--brand-dim); color: var(--brand); }
.vp-os .fmt-bar__btn--b { font-weight: 800; }
.vp-os .fmt-bar__btn--i { font-style: italic; font-family: Georgia, serif; }
.vp-os .fmt-bar__btn--s { text-decoration: line-through; }

/* ── Editor: slash-palette filter input ───────────────────────────────────── */
.vp-os .block-palette__search {
  width: 100%;
  box-sizing: border-box;
  padding: 10px 14px;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  font-size: var(--text-sm);
  outline: none;
}
.vp-os .block-palette__search::placeholder { color: var(--text-3); }

/* ── Editor: image drag-and-drop affordance ───────────────────────────────── */
.vp-os [data-editor-canvas].is-dragover {
  outline: 2px dashed var(--brand);
  outline-offset: 6px;
  border-radius: var(--r-md);
}


/* ── Theme Studio: custom CSS / code editor ───────────────────────────────── */
.vp-os textarea.theme-code {
  width: 100%;
  box-sizing: border-box;
  min-height: 220px;
  resize: vertical;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: var(--text-sm);
  line-height: 1.5;
  tab-size: 2;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}


/* ══════════════════════════════════════════════════════════════════════════
   Post editor v1.14.0 — new blocks, reordering, focus mode, split preview,
   live stats, palette polish. (Strict CSP: classes only, no inline styles.)
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Topbar word-count chip ─────────────────────────────────────────────── */
.vp-os .editor-wordcount {
  font-size: var(--text-xs);
  color: var(--text-3);
  padding: 2px var(--sp-2);
  border-radius: var(--r-full);
  background: var(--bg-surface-2);
  white-space: nowrap;
}
.vp-os .btn.is-active { background: var(--brand-dim); color: var(--brand); border-color: var(--brand); }

/* ── Workspace: canvas + optional split live-preview ────────────────────── */
.vp-os .editor-workspace { display: flex; gap: var(--sp-5); align-items: stretch; min-width: 0; }
.vp-os .editor-workspace > .editor-canvas { flex: 1 1 auto; min-width: 0; }
.vp-os .editor-live {
  flex: 1 1 50%;
  min-width: 0;
  border-left: 1px solid var(--border);
  padding-left: var(--sp-5);
  max-height: calc(100vh - var(--topbar-h) - 120px);
  overflow-y: auto;
  animation: vp3-enter var(--t-enter);
}
.vp-os .editor-live[hidden] { display: none; }
.vp-os .editor-live-head {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-3);
  margin-bottom: var(--sp-3);
}
.vp-os .editor-live-body { font-size: var(--text-base); line-height: 1.7; }
@keyframes vp3-enter { from { opacity: 0; transform: translateX(8px); } to { opacity: 1; transform: none; } }

/* ── Sidebar live stats ─────────────────────────────────────────────────── */
.vp-os .editor-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
  padding: var(--sp-3) 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.vp-os .editor-stat { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 2px; }
.vp-os .editor-stat__num { font-size: var(--text-lg); font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.vp-os .editor-stat__label { font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-3); }

/* ── Live document outline ────────────────────────────────────────────────
   Mirrors the post's heading structure; entries indent by level and the
   section the caret is in stays highlighted. Scrolls internally past ~14
   entries so a long document never pushes the sidebar tools off-screen. */
.vp-os .editor-outline { padding: var(--sp-3) 0; border-bottom: 1px solid var(--border); }
.vp-os .editor-outline__title {
  font-size: var(--text-xs); font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--text-3); margin-bottom: var(--sp-2);
}
.vp-os .editor-outline__list { display: flex; flex-direction: column; gap: 1px; max-height: 320px; overflow-y: auto; }
.vp-os .editor-outline__item {
  display: block; width: 100%; text-align: left;
  background: none; border: 0; cursor: pointer;
  font: inherit; font-size: var(--text-sm); color: var(--text-2);
  padding: var(--sp-1) var(--sp-2); border-radius: var(--r-sm);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: background var(--t-fast), color var(--t-fast);
}
.vp-os .editor-outline__item:hover { background: var(--bg-surface-2); color: var(--text); }
.vp-os .editor-outline__item:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.vp-os .editor-outline__item.is-active { background: var(--brand-dim); color: var(--text); }
.vp-os .editor-outline__item--l3 { padding-left: calc(var(--sp-2) + var(--sp-4)); }
.vp-os .editor-outline__item--l4 { padding-left: calc(var(--sp-2) + var(--sp-8)); }

/* ── Block control rail (drag, move, insert, delete) ────────────────────── */
.vp-os .eblock__ctrl { flex-direction: column; gap: 2px; }
.vp-os .eblock__drag { cursor: grab; }
.vp-os .eblock__drag:active { cursor: grabbing; }
.vp-os .eblock.is-dragging { opacity: 0.45; }
/* Keyboard grab-mode: focus ring on the handle + a clear "lifted" state on the
   block so a keyboard user always sees which block they are moving. */
.vp-os .eblock__drag:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
.vp-os .eblock.is-grabbed {
  box-shadow: 0 0 0 2px var(--brand-glow), 0 8px 24px -10px rgba(2, 8, 20, 0.6);
  border-radius: var(--r-sm);
}
.vp-os .eblock.is-grabbed .eblock__ctrl { opacity: 1; }
/* Screen-reader-only live region for reorder announcements. */
.vp-os .eblock__sr-live, .eblock__sr-live {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.vp-os .eblock.is-drop-before { box-shadow: 0 -2px 0 0 var(--brand); }
.vp-os .eblock.is-drop-after  { box-shadow: 0 2px 0 0 var(--brand); }

/* ── Task-list block editor ─────────────────────────────────────────────── */
.vp-os .eblock__tasks { display: flex; flex-direction: column; gap: var(--sp-1); }
.vp-os .eblock__task { display: flex; align-items: center; gap: var(--sp-2); }
.vp-os .eblock__task-check { width: 16px; height: 16px; accent-color: var(--brand); flex: 0 0 auto; cursor: pointer; }
.vp-os .eblock__task-text { flex: 1 1 auto; }
.vp-os .eblock__task.is-done .eblock__task-text { text-decoration: line-through; color: var(--text-3); }
.vp-os .eblock__addrow {
  align-self: flex-start;
  margin-top: var(--sp-1);
  border: 1px dashed var(--border-strong);
  background: transparent;
  color: var(--text-2);
  border-radius: var(--r-sm);
  padding: 2px var(--sp-3);
  font-size: var(--text-xs);
  cursor: pointer;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.vp-os .eblock__addrow:hover { color: var(--brand); border-color: var(--brand); }

/* ── Table block editor ─────────────────────────────────────────────────── */
.vp-os .eblock__table { display: flex; flex-direction: column; gap: var(--sp-2); overflow-x: auto; }
.vp-os .eblock__table-grid { border-collapse: collapse; width: 100%; }
.vp-os .eblock__table-grid th, .vp-os .eblock__table-grid td { border: 1px solid var(--border); padding: 2px; vertical-align: middle; }
.vp-os .eblock__table-grid th .eblock__input { font-weight: 700; }
.vp-os .eblock__table-grid .eblock__input { border: none; background: transparent; padding: var(--sp-2); }
.vp-os .eblock__table-grid .eblock__input:focus { background: var(--bg-surface); border-radius: var(--r-sm); }
.vp-os .eblock__table-rowctl { width: 30px; text-align: center; border: none !important; }
.vp-os .eblock__table-ctl { display: flex; gap: var(--sp-2); }

/* ── Toggle / math / hint helpers ───────────────────────────────────────── */
.vp-os .eblock__checkline { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--text-sm); color: var(--text-2); cursor: pointer; }
.vp-os .eblock__checkline input { accent-color: var(--brand); }
.vp-os .eblock__hint { margin-top: 2px; }
.vp-os .eblock--toggle .eblock__field { border-left: 3px solid var(--accent); padding-left: var(--sp-3); }
.vp-os .eblock--math .eblock__code { font-family: var(--font-mono); }

/* ── Slash palette: keyboard highlight ──────────────────────────────────── */
.vp-os .block-palette__item.is-active { background: var(--brand-dim); outline: 1px solid var(--brand); }

/* ── Focus (distraction-free) mode ──────────────────────────────────────── */
.vp-os .editor-shell.is-focus { grid-template-columns: 1fr; }
.vp-os .editor-shell.is-focus .editor-sidebar { display: none; }
.vp-os .editor-shell.is-focus .editor-topbar { background: transparent; border-bottom-color: transparent; }
.vp-os .editor-shell.is-focus .editor-topbar-status,
.vp-os .editor-shell.is-focus .editor-wordcount { opacity: 0.6; }
.vp-os .editor-shell.is-focus .editor-main { max-width: 760px; margin: 0 auto; width: 100%; }
.vp-os .editor-shell.is-focus .editor-canvas { padding-top: var(--sp-8); }
/* Typewriter room (DESKTOP ONLY) — authoritative, placed last so it wins the
   cascade on wide screens where the canvas itself scrolls: enough top/bottom
   space that the first and last lines can still reach the vertical centre when
   the editor JS centres the caret line. On mobile (<=900px) the PAGE scrolls,
   so this never applies and the small base padding above is used — no phone
   ever shows ~40vh of empty space. */
@media (min-width: 901px) {
  .vp-os .editor-shell.is-focus .editor-canvas { padding-top: 40vh; padding-bottom: 40vh; }
}
.vp-os .editor-shell.is-focus .eblock__ctrl { opacity: 0; }
.vp-os .editor-shell.is-focus .eblock:hover .eblock__ctrl { opacity: 1; }

@media (max-width: 900px) {
  .vp-os .editor-workspace { flex-direction: column; }
  .vp-os .editor-live { border-left: none; border-top: 1px solid var(--border); padding-left: 0; padding-top: var(--sp-4); }
}

/* ══════════════════════════════════════════════════════════════════════════
   Rendered block styles (admin preview + live pane). These mirror the classes
   emitted by internal/blockrender so Preview/Split match the published page.
   ══════════════════════════════════════════════════════════════════════════ */

/* Table */
.vp-os .article .vp-table { overflow-x: auto; margin: var(--sp-5) 0; }
.vp-os .article .vp-table table { border-collapse: collapse; width: 100%; font-size: var(--text-sm); }
.vp-os .article .vp-table th, .vp-os .article .vp-table td { border: 1px solid var(--border); padding: var(--sp-2) var(--sp-3); text-align: left; }
.vp-os .article .vp-table thead th { background: var(--bg-surface-2); font-weight: 700; }
.vp-os .article .vp-table tbody tr:nth-child(even) { background: var(--bg-surface-2); }

/* Toggle */
.vp-os .article .vp-toggle { border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4); margin: var(--sp-4) 0; background: var(--bg-surface); }
.vp-os .article .vp-toggle > summary { cursor: pointer; font-weight: 600; color: var(--text); list-style: none; }
.vp-os .article .vp-toggle > summary::-webkit-details-marker { display: none; }
.vp-os .article .vp-toggle > summary::before { content: "▸"; display: inline-block; margin-right: var(--sp-2); color: var(--brand); transition: transform var(--t-fast); }
.vp-os .article .vp-toggle[open] > summary::before { transform: rotate(90deg); }
.vp-os .article .vp-toggle__body { margin-top: var(--sp-3); color: var(--text-2); }

/* Task list */
.vp-os .article .vp-tasks { list-style: none; padding-left: 0; margin: var(--sp-4) 0; }
.vp-os .article .vp-task { display: flex; align-items: flex-start; gap: var(--sp-2); padding: 2px 0; }
.vp-os .article .vp-task__box { flex: 0 0 auto; width: 16px; height: 16px; margin-top: 3px; border: 2px solid var(--border-strong); border-radius: 4px; }
.vp-os .article .vp-task--done .vp-task__box { background: var(--brand); border-color: var(--brand); position: relative; }
.vp-os .article .vp-task--done .vp-task__box::after { content: "✓"; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #fff; line-height: 1; }
.vp-os .article .vp-task--done .vp-task__text { text-decoration: line-through; color: var(--text-3); }

/* Math */
.vp-os .article .vp-math {
  font-family: var(--font-mono);
  background: var(--bg-surface-2);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-sm);
  padding: var(--sp-3) var(--sp-4);
  margin: var(--sp-4) 0;
  overflow-x: auto;
  white-space: pre-wrap;
  color: var(--text);
}

/* Audio */
.vp-os .article .vp-audio { margin: var(--sp-4) 0; }
.vp-os .article .vp-audio audio { width: 100%; }
.vp-os .article .vp-audio figcaption { font-size: var(--text-xs); color: var(--text-3); margin-top: var(--sp-1); }

/* VayuMail: mailbox search bar */
.vp-os .vm-search { display: flex; gap: 0.5rem; align-items: center; margin: 0.75rem 0; }
.vp-os .vm-search .input { flex: 1 1 auto; }


/* ── VayuAnalytics dashboard polish (metric deltas, privacy note, mobile) ──── */
.vp-os .vm-stat-row { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.vp-os .vm-delta {
  display: inline-flex;
  align-items: center;
  gap: 0.15em;
  padding: 0.1em 0.5em;
  border-radius: var(--r-full);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.vp-os .vm-delta--good { background: var(--ok-dim);     color: var(--ok); }
.vp-os .vm-delta--bad  { background: var(--danger-dim); color: var(--danger); }
.vp-os .vm-delta--flat { background: var(--bg-surface-2); color: var(--text-3); }
.vp-os .vm-delta--new  { background: var(--info-dim);   color: var(--info); }

/* Trust footer */
.vp-os .vm-privacy-note {
  margin-top: var(--sp-6);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--bg-surface-2);
  text-align: center;
}

/* Period selector: subtle "loading" cue while the next window is fetched. */
.vp-os [data-period].is-loading { opacity: 0.5; pointer-events: none; }
.vp-os [data-period].is-loading::after {
  content: "Loading…";
  margin-left: var(--sp-2);
  font-size: var(--text-xs);
  color: var(--text-3);
  align-self: center;
}

/* Mobile: stack the multi-column analytics grids and keep tables swipeable. */
@media (max-width: 860px) {
  .vp-os .grid-2,
  .vp-os .grid-3,
  .vp-os .vm-metrics.grid-4 { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .vp-os .table-wrap { -webkit-overflow-scrolling: touch; }
  .vp-os .vm-stat { font-size: 1.35rem; }
}


/* ── VayuAnalytics: tabbed layout + premium live view ──────────────────────── */
/* Tab bar (buttons) — clean wrapping pills. Wraps onto multiple lines instead
   of showing a horizontal scrollbar, so every section is reachable at a glance. */
.vp-os .vm-analytics-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  border-bottom: none;
  margin-bottom: var(--sp-5);
  overflow: visible;
}
.vp-os button.tab {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  cursor: pointer;
  white-space: nowrap;
  color: var(--text-3);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 500;
  padding: 0.4rem 0.9rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  transition: color var(--t-fast), background var(--t-fast), border-color var(--t-fast);
}
.vp-os button.tab:hover { color: var(--text); border-color: var(--border-strong); }
.vp-os button.tab.tab--active {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}
.vp-os .vm-tab-ico { font-size: 1em; line-height: 1; }
.vp-os .vm-tab-panel { animation: vm-fade-in var(--t, 160ms) ease; }
@keyframes vm-fade-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .vp-os .vm-tab-panel { animation: none; } }

/* Live hero card — big active-visitor count with a radar-pulse motif. The card
   is a two-column flex: headline metric on the left, concentric pulse rings on
   the right. All motion is transform/opacity only (GPU-cheap) and disabled under
   prefers-reduced-motion. */
.vp-os .vm-live-hero {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  overflow: hidden;
  position: relative;
}
.vp-os .vm-live-hero__main { min-width: 0; }
.vp-os .vm-live-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.09em;
  color: var(--ok);
  text-transform: uppercase;
  margin-bottom: var(--sp-2);
}
.vp-os .vm-live-count {
  font-size: 3.2rem;
  font-weight: 700;
  line-height: 1;
  color: var(--brand);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.vp-os .vm-live-sub { margin-top: var(--sp-2); }
.vp-os .vm-live-updated { color: var(--text-3); margin-left: 0.35em; }

/* Concentric radar rings — three expanding circles staggered in time. */
.vp-os .vm-live-rings {
  position: relative;
  width: 92px;
  height: 92px;
  flex: 0 0 auto;
}
.vp-os .vm-live-rings span {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid var(--ok);
  opacity: 0;
  animation: vm-radar 2.8s ease-out infinite;
}
.vp-os .vm-live-rings span:nth-child(2) { animation-delay: 0.9s; }
.vp-os .vm-live-rings span:nth-child(3) { animation-delay: 1.8s; }
@keyframes vm-radar {
  0%   { transform: scale(0.35); opacity: 0.55; }
  70%  { opacity: 0.12; }
  100% { transform: scale(4.1); opacity: 0; }
}

/* Live bar lists animate their rows in on refresh (staggered fade+rise). */
.vp-os .vm-live-list .vp-bar--enter { animation: vm-bar-in 0.32s ease both; }
.vp-os .vm-live-list .vp-bar--enter:nth-child(2) { animation-delay: 0.03s; }
.vp-os .vm-live-list .vp-bar--enter:nth-child(3) { animation-delay: 0.06s; }
.vp-os .vm-live-list .vp-bar--enter:nth-child(4) { animation-delay: 0.09s; }
.vp-os .vm-live-list .vp-bar--enter:nth-child(5) { animation-delay: 0.12s; }
@keyframes vm-bar-in { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }

/* Derived-engagement strip — GDPR-safe ratios under the headline metrics. */
.vp-os .vm-engage {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-3);
  margin-bottom: var(--sp-6);
}
.vp-os .vm-engage__item {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
}
.vp-os .vm-engage__val {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.vp-os .vm-engage__label { font-size: var(--text-sm); color: var(--text-2); margin-top: 2px; }
.vp-os .vm-engage__hint { font-size: var(--text-xs); color: var(--text-3); margin-top: 2px; }

@media (prefers-reduced-motion: reduce) {
  .vp-os .vm-live-rings span { animation: none; opacity: 0.18; }
  .vp-os .vm-live-list .vp-bar--enter { animation: none; }
}

/* Country flags: real self-hosted SVG images (flag-icons, MIT), so they render
   identically on every platform — including Windows, which omits flag emoji
   from its system font. The country name is always shown alongside. */
.vp-os .vp-flag-img {
  display: inline-block;
  width: 1.33em;
  height: 1em;
  object-fit: cover;
  border-radius: 2px;
  vertical-align: -0.12em;
  margin-right: 0.45em;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12);
  background: var(--bg-surface-2);
}
/* Neutral globe placeholder for visitors with no known country (no GeoIP). */
.vp-os .vp-flag-unknown {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2399a' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18'/%3E%3C/svg%3E");
  background-size: cover;
  background-position: center;
  box-shadow: none;
}

/* Geography — long country/region/city lists scroll inside their card so the
   page never becomes one endless column. */
.vp-os .vp-geo-scroll { max-height: 340px; overflow-y: auto; padding-right: 4px; }
.vp-os .vp-geo-scroll::-webkit-scrollbar { width: 8px; }
.vp-os .vp-geo-scroll::-webkit-scrollbar-track { background: transparent; }
.vp-os .vp-geo-scroll::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 8px; }

/* Premium setup card shown when region/city data needs a CDN location header. */
.vp-os .vp-geo-setup {
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-md);
  padding: var(--sp-4);
  background: var(--brand-dim);
}
.vp-os .vp-geo-setup__lead { color: var(--text-2); font-size: var(--text-sm); margin-bottom: var(--sp-3); line-height: 1.5; }
.vp-os .vp-geo-setup__steps { list-style: none; display: grid; gap: var(--sp-2); margin: 0 0 var(--sp-3); padding: 0; }
.vp-os .vp-geo-setup__steps li { display: flex; align-items: center; gap: 0.6em; font-size: var(--text-sm); color: var(--text); }
.vp-os .vp-geo-setup__n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; flex: 0 0 auto;
  border-radius: 50%; background: var(--brand); color: #fff;
  font-weight: 700; font-size: 12px;
}
.vp-os .vp-geo-setup__alt { font-size: var(--text-xs); color: var(--text-3); margin: 0; }
.vp-os .vp-geo-setup code { background: var(--bg-surface-2); padding: 1px 5px; border-radius: 4px; font-size: 0.85em; }

@media (max-width: 860px) {
  .vp-os .vm-live-grid { grid-template-columns: 1fr; }
  .vp-os .vm-live-count { font-size: 2.4rem; }
  .vp-os .vm-engage { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
  .vp-os .vm-live-rings { display: none; }
  .vp-os .vm-engage { grid-template-columns: 1fr 1fr; }
}


/* ── Update & Backup panel (admin_os_update.go) ──────────────────────────── */
.vp-os .settings-callout {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  padding: .9rem 1.1rem;
  margin-bottom: 1.5rem;
  border: 1px solid var(--border, #2a2a2a);
  border-left: 3px solid var(--brand, #7c83ff);
  border-radius: 10px;
  background: var(--surface-2, rgba(124, 131, 255, .06));
}
.vp-os .theme-actions {
  display: flex;
  gap: .5rem;
  align-items: center;
  flex-wrap: wrap;
}
.vp-os .update-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
  margin-bottom: .5rem;
}
.vp-os .update-version__value {
  font-size: 1.25rem;
  font-weight: 600;
  margin-top: .15rem;
}
.vp-os .update-version__value.is-available { color: var(--brand, #7c83ff); }
.vp-os .update-notes {
  margin-top: 1rem;
  padding: 1rem 1.15rem;
  max-height: 22rem;
  overflow: auto;
  word-break: break-word;
  font-size: .85rem;
  line-height: 1.55;
  border: 1px solid var(--border, #2a2a2a);
  border-radius: 12px;
  background: var(--surface-2, rgba(127, 127, 127, .06));
  color: var(--text-muted, #9ca3af);
}
/* An older release, or a hand-written body, that is not in changelog shape: shown
   verbatim rather than not at all. */
.vp-os .upd-notes__raw { white-space: pre-wrap; }
.vp-os .upd-notes__title {
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text, #e6edf3);
  margin-bottom: .7rem;
}
.vp-os .upd-notes__head {
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--accent, #6366f1);
  margin: .85rem 0 .4rem;
}
.vp-os .upd-notes__head:first-of-type { margin-top: 0; }
.vp-os .upd-notes__list { list-style: none; margin: 0; padding: 0; display: grid; gap: .55rem; }
.vp-os .upd-notes__item {
  position: relative;
  padding-left: 1.1rem;
}
/* A drawn marker rather than a list bullet, so the lead line wraps flush. */
.vp-os .upd-notes__item::before {
  content: '';
  position: absolute;
  left: .1rem;
  top: .58em;
  width: .38rem;
  height: .38rem;
  border-radius: 50%;
  background: var(--accent, #6366f1);
  opacity: .8;
}
.vp-os .upd-notes__lead {
  display: block;
  font-weight: 600;
  color: var(--text, #e6edf3);
}
.vp-os .upd-notes__rest { display: block; opacity: .85; }
.vp-os .upd-notes__more {
  margin-top: .8rem;
  padding-top: .7rem;
  border-top: 1px solid var(--border, #2a2a2a);
  font-size: .78rem;
  opacity: .8;
}
.vp-os [data-update-msg].is-error,
.vp-os [data-backup-msg].is-error { color: var(--danger, #ef4444); }
@media (max-width: 720px) {
  .vp-os .update-row { grid-template-columns: 1fr; }
}


/* ── Editor: Post settings drawer (publishing options) ───────────────────── */
.vp-os .editor-settings-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 340;
}
.vp-os .editor-settings-backdrop[hidden] { display: none; }
.vp-os .editor-settings {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 420px;
  max-width: 92vw;
  z-index: 350;
  background: var(--bg-surface);
  border-left: 1px solid var(--border);
  box-shadow: -16px 0 48px rgba(0, 0, 0, 0.32);
  display: flex;
  flex-direction: column;
  animation: vp-settings-in 0.18s ease;
}
.vp-os .editor-settings[hidden] { display: none; }
@keyframes vp-settings-in { from { transform: translateX(24px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
.vp-os .editor-settings-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
}
.vp-os .editor-settings-title { font-weight: 700; font-size: var(--text-md); }
.vp-os .editor-settings-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: var(--sp-4) var(--sp-5) var(--sp-10);
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}

.vp-os .pm-field { display: flex; flex-direction: column; gap: var(--sp-2); }
.vp-os .pm-label { font-size: var(--text-sm); font-weight: 600; color: var(--text-2); }
.vp-os .pm-input {
  width: 100%;
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text);
  font-size: var(--text-sm);
  padding: var(--sp-2) var(--sp-3);
  outline: none;
}
.vp-os .pm-input:focus { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-dim); }
.vp-os .pm-textarea { resize: vertical; min-height: 64px; line-height: 1.5; font-family: inherit; }
.vp-os .pm-hint { line-height: 1.4; }
.vp-os .pm-row { display: flex; align-items: center; gap: var(--sp-2); }
.vp-os .pm-row .pm-input { flex: 1 1 auto; }
.vp-os .pm-prefix { color: var(--text-3); font-size: var(--text-sm); }

.vp-os .pm-feature {
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-md);
  background: var(--bg-base);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.vp-os .pm-feature-preview { width: 100%; height: 100%; object-fit: cover; }
.vp-os .pm-feature-empty { color: var(--text-3); font-size: var(--text-sm); }

.vp-os .pm-tags { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.vp-os .pm-tag {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  background: var(--brand-dim);
  color: var(--brand);
  border-radius: var(--r-full);
  padding: 2px var(--sp-2);
  font-size: var(--text-xs);
}
.vp-os .pm-tag-x {
  border: none;
  background: none;
  color: inherit;
  cursor: pointer;
  font-size: var(--text-md);
  line-height: 1;
  padding: 0;
}
.vp-os .pm-tag-x:hover { color: var(--text); }

.vp-os .pm-toggles { gap: var(--sp-3); }
.vp-os .pm-check { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--text-sm); cursor: pointer; }

.vp-os .pm-group { border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4); }
.vp-os .pm-group[open] { padding-bottom: var(--sp-4); }
.vp-os .pm-group > summary { cursor: pointer; font-weight: 600; font-size: var(--text-sm); color: var(--text-2); list-style: none; }
.vp-os .pm-group > summary::-webkit-details-marker { display: none; }
.vp-os .pm-group > summary::after { content: "▸"; float: right; color: var(--text-3); transition: transform var(--t-fast); }
.vp-os .pm-group[open] > summary::after { transform: rotate(90deg); }
.vp-os .pm-group .pm-field { margin-top: var(--sp-3); }
.vp-os .pm-subhead { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-3); margin-top: var(--sp-3); }

@media (max-width: 600px) {
  .vp-os .editor-settings { width: 100vw; }
}


/* ── Editor: image card row, gallery editor ──────────────────────────────── */
.vp-os .eblock__row { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.vp-os .eblock__row .eblock__input { flex: 1 1 200px; }

.vp-os .eblock__gallery { display: flex; flex-direction: column; gap: var(--sp-2); }
.vp-os .eblock__gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: var(--sp-2);
}
.vp-os .eblock__gallery-cell {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--bg-base);
  border: 1px solid var(--border);
}
.vp-os .eblock__gallery-cell img { width: 100%; height: 100%; object-fit: cover; display: block; }
.vp-os .eblock__gallery-del {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 22px;
  height: 22px;
  border: none;
  border-radius: var(--r-full);
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  cursor: pointer;
  line-height: 1;
}
.vp-os .eblock__gallery-del:hover { background: var(--color-danger, #ef4444); }


/* ── ADR Registry ────────────────────────────────────────────── */
.vp-os .adr-list { display: flex; flex-direction: column; gap: 6px; }
.vp-os a.adr-row {
  display: flex; align-items: center; gap: 14px;
  padding: 11px 14px;
  background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: var(--r-md); text-decoration: none; color: var(--text);
  transition: border-color .12s ease, transform .12s ease, background .12s ease;
}
.vp-os a.adr-row:hover {
  border-color: var(--accent); background: var(--bg-surface-3, var(--bg-surface));
  transform: translateY(-1px); text-decoration: none;
}
.vp-os .adr-row .adr-number {
  font: 700 11px var(--font-mono); letter-spacing: .04em; color: var(--accent);
  white-space: nowrap; min-width: 84px;
}
.vp-os .adr-row .adr-title { flex: 1; font-size: 13px; color: var(--text); text-transform: capitalize; }
.vp-os .adr-row .adr-badge {
  font: 700 8px var(--font-mono); letter-spacing: .06em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 100px; white-space: nowrap;
  background: rgba(16,185,129,.1); color: var(--ok);
}

/* ADR read view */
.vp-os .adr-doc-actions { margin-bottom: 14px; }
.vp-os article.adr-doc {
  padding: 24px 28px; line-height: 1.65; color: var(--text-1, var(--text));
  font-size: 14px; max-width: 920px;
}
.vp-os article.adr-doc h1,
.vp-os article.adr-doc h2,
.vp-os article.adr-doc h3,
.vp-os article.adr-doc h4 { color: var(--text); line-height: 1.3; margin: 1.4em 0 .6em; }
.vp-os article.adr-doc h1 { font-size: 22px; }
.vp-os article.adr-doc h2 { font-size: 18px; border-bottom: 1px solid var(--border); padding-bottom: .3em; }
.vp-os article.adr-doc h3 { font-size: 15px; }
.vp-os article.adr-doc p,
.vp-os article.adr-doc ul,
.vp-os article.adr-doc ol { margin: .7em 0; color: var(--text-2); }
.vp-os article.adr-doc li { margin: .3em 0; }
.vp-os article.adr-doc a { color: var(--accent); }
.vp-os article.adr-doc strong { color: var(--text); }
.vp-os article.adr-doc code {
  font: 400 12px var(--font-mono); background: rgba(99,102,241,.08);
  border: 1px solid var(--border); border-radius: var(--r-sm); padding: 1px 5px;
}
.vp-os article.adr-doc pre {
  background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: 14px 16px; overflow-x: auto; margin: 1em 0;
}
.vp-os article.adr-doc pre code { background: none; border: none; padding: 0; }
.vp-os article.adr-doc blockquote {
  border-left: 3px solid var(--accent); margin: 1em 0; padding: .2em 0 .2em 14px;
  color: var(--text-2);
}
.vp-os article.adr-doc table { border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 13px; }
.vp-os article.adr-doc th,
.vp-os article.adr-doc td { border: 1px solid var(--border); padding: 7px 10px; text-align: left; }
.vp-os article.adr-doc th { background: var(--bg-surface); color: var(--text); }



/* ============================================================================
   VayuOS — Mobile app experience (responsive enhancement layer)
   Loaded last so it refines the base rules above. Goals: native-app feel on
   phones — comfortable touch targets, safe-area awareness, no iOS focus-zoom,
   a wide tap-to-close drawer, an app-style bottom bar, and wide data tables
   that fold into readable cards instead of forcing a horizontal scroll.
   ========================================================================== */

/* Kill the grey tap flash and stop accidental horizontal scrolling. */
.vp-os { -webkit-tap-highlight-color: transparent; }
.vp-os .main { max-width: 100%; overflow-x: hidden; }
.vp-os .content { max-width: 1280px; min-width: 0; }

/* Dynamic viewport units where supported, so the mobile browser's collapsing
   address bar never clips the drawer or shell. */
@supports (height: 100dvh) {
  .vp-os .sidebar { height: 100dvh; }
  .vp-os .shell { min-height: 100dvh; }
}

/* ── Touch targets ─────────────────────────────────────────────
   Only on real touch / coarse-pointer devices, so the desktop density is
   untouched. 44px is the Apple/Android minimum comfortable hit area. */
@media (hover: none) and (pointer: coarse) {
  .vp-os .nav-link { min-height: 44px; }
  .vp-os .btn { min-height: 40px; display: inline-flex; align-items: center; justify-content: center; }
  .vp-os .btn--sm { min-height: 38px; }
  .vp-os .table .row-actions a,
  .vp-os .table .row-actions button {
    min-height: 36px; display: inline-flex; align-items: center;
  }
  /* Slightly larger form controls are easier to hit. */
  .vp-os input:not([type="checkbox"]):not([type="radio"]),
  .vp-os select,
  .vp-os textarea { min-height: 42px; }
}

/* ── Phone layout (≤768px) ─────────────────────────────────────
   Refines the existing mobile block: a wider drawer, no iOS focus-zoom,
   a compact topbar, and safe-area-aware spacing. */
@media (max-width: 768px) {
  /* A roomier, app-style slide-in drawer. */
  .vp-os .sidebar {
    width: min(86vw, 320px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  /* 16px is the threshold below which iOS Safari auto-zooms on focus; pin all
     text inputs to it so tapping a field never jumps the layout. */
  .vp-os input,
  .vp-os select,
  .vp-os textarea { font-size: 16px; }

  /* Compact, single-line topbar that never overflows. */
  .vp-os .topbar { gap: var(--sp-2); padding: 0 var(--sp-3); }
  .vp-os .topbar-title {
    font-size: var(--text-base);
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .vp-os .topbar .btn--sm { padding: var(--sp-2) var(--sp-3); }

  /* Let dense control rows wrap instead of overflowing. */
  .vp-os .toolbar-row,
  .vp-os .card-head,
  .vp-os .bulk-bar { flex-wrap: wrap; }
  .vp-os .toolbar-row > .input,
  .vp-os .toolbar-row > input[type="search"],
  .vp-os .toolbar-row > select { flex: 1 1 100%; width: 100%; }

  /* Comfortable card padding on small screens. */
  .vp-os .content { padding: var(--sp-4) var(--sp-3); }
  .vp-os .card { padding: var(--sp-4); }
}

/* ── App-style bottom bar ──────────────────────────────────────
   The shared bottom nav is shown ≤768px. Make it safe-area aware, give it
   clear active state, and respect items hidden by the role filter (JS). */
@media (max-width: 768px) {
  .vp-os .bottom-nav {
    height: auto;
    min-height: 56px;
    padding-bottom: env(safe-area-inset-bottom, 0px);
    box-shadow: 0 -1px 0 var(--border), var(--sh);
  }
  .vp-os .bottom-nav-item {
    min-height: 56px;
    border: none; background: none;
    -webkit-tap-highlight-color: transparent;
  }
  .vp-os .bottom-nav-item.active,
  .vp-os .bottom-nav-item[aria-current="page"] { color: var(--brand); }
  .vp-os .bottom-nav-item--accent { color: var(--brand); }
  .vp-os .bottom-nav-item--accent svg { opacity: 1; }
  /* Items the role filter removes must collapse (the base rule sets flex). */
  .vp-os .bottom-nav-item[hidden] { display: none; }
  /* Clear the fixed bar + the home-indicator inset. */
  .vp-os .content { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }
}

/* ── Responsive data tables → cards (≤640px) ───────────────────
   JS (initResponsiveTables) stamps each cell with data-label from its column
   header and flags qualifying wrappers with .vp-stackable. Here we fold those
   tables into labelled cards so wide tables stay readable without a horizontal
   scrollbar. Tables that opt out ([data-no-stack]) or have a selection column
   keep the normal swipe-scroll behaviour. */
@media (max-width: 640px) {
  .vp-os .table-wrap.vp-stackable { overflow-x: visible; }
  .vp-os .table-wrap.vp-stackable > table,
  .vp-os .table-wrap.vp-stackable > table > tbody,
  .vp-os .table-wrap.vp-stackable > table > tbody > tr,
  .vp-os .table-wrap.vp-stackable > table > tbody > tr > td { display: block; width: 100%; }

  /* Visually hide column headers but keep them for assistive tech. */
  .vp-os .table-wrap.vp-stackable > table > thead {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }

  .vp-os .table-wrap.vp-stackable > table > tbody > tr {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    padding: var(--sp-1) var(--sp-3);
    margin-bottom: var(--sp-3);
  }
  .vp-os .table-wrap.vp-stackable > table > tbody > tr:hover { background: var(--bg-surface); }

  .vp-os .table-wrap.vp-stackable > table > tbody > tr > td {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-2) 0;
    border: none;
    border-bottom: 1px solid var(--border);
    text-align: right;
    white-space: normal;
  }
  .vp-os .table-wrap.vp-stackable > table > tbody > tr > td:last-child { border-bottom: none; }

  /* The column label, pulled from the header by JS. */
  .vp-os .table-wrap.vp-stackable > table > tbody > tr > td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 40%;
    text-align: left;
    font-size: var(--text-xs); font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--text-3);
  }
  /* Action cells (blank header) span full width and right-align their buttons. */
  .vp-os .table-wrap.vp-stackable > table > tbody > tr > td[data-label=""]::before { content: none; }
  .vp-os .table-wrap.vp-stackable .row-actions { text-align: right; }
  .vp-os .table-wrap.vp-stackable .row-meta { text-align: right; }
}

/* Honour reduced-motion: drop the drawer slide for users who ask for it. */
@media (prefers-reduced-motion: reduce) {
  .vp-os .sidebar { transition: none; }
}


/* Transient "couldn't load" notice on list pages (e.g. Posts under DB load). */
.vp-os .load-notice {
  border-left: 3px solid var(--warn);
  background: var(--warn-dim);
}

/* ── Analytics charts (server-rendered SVG, CSP-safe) ─────────────── */
.vp-os {
  --chart-1: #0ea5e9; --chart-2: #a78bfa; --chart-3: #22c55e; --chart-4: #f59e0b;
  --chart-5: #ec4899; --chart-6: #ef4444; --chart-7: #06b6d4; --chart-8: #8b5cf6;
}
/* Horizontal bar list */
.vp-os .vp-bars { display: flex; flex-direction: column; gap: .7rem; }
.vp-os .vp-bar { display: grid; grid-template-columns: 1fr auto; gap: .2rem .75rem; align-items: baseline; }
.vp-os .vp-bar__label { font-size: .85rem; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.vp-os .vp-bar__label a { color: inherit; text-decoration: none; }
.vp-os .vp-bar__label a:hover { color: var(--brand); text-decoration: underline; }
.vp-os .vp-bar__val { font-variant-numeric: tabular-nums; font-weight: 600; font-size: .85rem; color: var(--text); white-space: nowrap; }
.vp-os .vp-bar__pct { color: var(--text-3); font-weight: 400; margin-left: .4rem; }
.vp-os .vp-bar__track { grid-column: 1 / -1; height: 8px; border-radius: 999px; background: var(--bg-surface-2); overflow: hidden; }
.vp-os .vp-bar__fill { display: block; height: 100%; border-radius: 999px; background: var(--chart-1); transition: width .4s ease; }
.vp-os .vp-bar--c1 .vp-bar__fill { background: var(--chart-1); }
.vp-os .vp-bar--c2 .vp-bar__fill { background: var(--chart-2); }
.vp-os .vp-bar--c3 .vp-bar__fill { background: var(--chart-3); }
.vp-os .vp-bar--c4 .vp-bar__fill { background: var(--chart-4); }
.vp-os .vp-bar--c5 .vp-bar__fill { background: var(--chart-5); }
.vp-os .vp-bar--c6 .vp-bar__fill { background: var(--chart-6); }
.vp-os .vp-bar--c7 .vp-bar__fill { background: var(--chart-7); }
.vp-os .vp-bar--c8 .vp-bar__fill { background: var(--chart-8); }

/* Donut chart + legend */
.vp-os .vp-donut-wrap { display: flex; gap: 1.4rem; align-items: center; flex-wrap: wrap; }
.vp-os .vp-donut { width: 128px; height: 128px; flex: 0 0 auto; transform: rotate(0deg); }
.vp-os .vp-donut__track { fill: none; stroke: var(--bg-surface-2); stroke-width: 5; }
.vp-os .vp-donut__seg { fill: none; stroke-width: 5; }
.vp-os .vp-legend { display: flex; flex-direction: column; gap: .45rem; min-width: 140px; flex: 1 1 auto; }
.vp-os .vp-legend__item { display: flex; align-items: center; gap: .5rem; font-size: .85rem; color: var(--text-2); }
.vp-os .vp-legend__dot { width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto; }
.vp-os .vp-legend__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1 1 auto; }
.vp-os .vp-legend__val { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--text); }
.vp-os .donut-c1, .vp-os .legend-c1 { stroke: var(--chart-1); background: var(--chart-1); }
.vp-os .donut-c2, .vp-os .legend-c2 { stroke: var(--chart-2); background: var(--chart-2); }
.vp-os .donut-c3, .vp-os .legend-c3 { stroke: var(--chart-3); background: var(--chart-3); }
.vp-os .donut-c4, .vp-os .legend-c4 { stroke: var(--chart-4); background: var(--chart-4); }
.vp-os .donut-c5, .vp-os .legend-c5 { stroke: var(--chart-5); background: var(--chart-5); }
.vp-os .donut-c6, .vp-os .legend-c6 { stroke: var(--chart-6); background: var(--chart-6); }
.vp-os .donut-c7, .vp-os .legend-c7 { stroke: var(--chart-7); background: var(--chart-7); }
.vp-os .donut-c8, .vp-os .legend-c8 { stroke: var(--chart-8); background: var(--chart-8); }

/* Two-series trend chart */
.vp-os .vp-trend { margin-top: .25rem; }
.vp-os .vp-trend-legend { display: flex; align-items: center; gap: 1.2rem; margin-bottom: .6rem; font-size: .8rem; color: var(--text-2); }
.vp-os .vp-trend-peak { margin-left: auto; font-size: .72rem; color: var(--text-3); padding: .12rem .55rem; border-radius: 999px; background: color-mix(in srgb, var(--chart-1) 12%, transparent); }
.vp-os .vp-trend-svg { width: 100%; height: auto; max-height: 320px; display: block; overflow: visible; }
.vp-os .chart-grid { stroke: var(--border); stroke-width: 1; opacity: .5; }
.vp-os .chart-yaxis { fill: var(--text-3); font-size: 9px; }
.vp-os .chart-xaxis { fill: var(--text-3); font-size: 9px; text-anchor: middle; }
.vp-os .chart-xaxis--start { text-anchor: start; }
.vp-os .chart-xaxis--end { text-anchor: end; }

/* Gradient area fill (stop colours set here so no inline SVG styles are needed). */
.vp-os .vp-trend-grad-0 { stop-color: var(--chart-1); stop-opacity: .34; }
.vp-os .vp-trend-grad-1 { stop-color: var(--chart-1); stop-opacity: 0; }
.vp-os .vp-trend-area { fill: url(#vpTrendFill); }
.vp-os .vp-trend-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.vp-os .vp-trend-line--pv { stroke: var(--chart-1); }
.vp-os .vp-trend-line--vis { stroke: var(--chart-2); stroke-dasharray: 4 3; }

/* ── Interactive hover layer: guide line, dots and a styled tooltip, revealed by
   pure CSS on band :hover (no JS, no inline styles). ─────────────────────────── */
.vp-os .vp-pt__hit { fill: transparent; cursor: crosshair; }
.vp-os .vp-pt__guide { stroke: var(--text-3); stroke-width: 1; stroke-dasharray: 3 3; opacity: 0; vector-effect: non-scaling-stroke; }
.vp-os .vp-pt__dot { opacity: 0; stroke: var(--surface-1); stroke-width: 1.5; }
.vp-os .vp-pt__dot--pv { fill: var(--chart-1); }
.vp-os .vp-pt__dot--vis { fill: var(--chart-2); }
.vp-os .vp-pt__tip { opacity: 0; pointer-events: none; }
.vp-os .vp-pt__tip-bg { fill: var(--bg-surface-3, #1e2d47); stroke: var(--border-strong, var(--border)); stroke-width: 1; filter: drop-shadow(0 6px 16px rgba(0,0,0,.45)); }
.vp-os .vp-pt__tip-date { fill: var(--text, #eef2f8); font-size: 11px; font-weight: 700; }
.vp-os .vp-pt__tip-lbl { fill: var(--text-2, #8ba4c4); font-size: 10px; }
.vp-os .vp-pt__tip-val { fill: var(--text, #eef2f8); font-size: 10px; font-weight: 700; text-anchor: end; }
.vp-os .vp-pt__tip-dot--pv { fill: var(--chart-1); }
.vp-os .vp-pt__tip-dot--vis { fill: var(--chart-2); }
/* Only the hovered band lights up. Transitions are short + GPU-cheap (opacity). */
.vp-os .vp-pt__guide, .vp-os .vp-pt__dot, .vp-os .vp-pt__tip { transition: opacity .12s var(--ease, ease); }
.vp-os .vp-pt:hover .vp-pt__guide,
.vp-os .vp-pt:hover .vp-pt__dot,
.vp-os .vp-pt:hover .vp-pt__tip { opacity: 1; }

/* Light one-shot draw-in when the chart first mounts. */
@keyframes vpTrendDraw { from { stroke-dashoffset: 3000; } to { stroke-dashoffset: 0; } }
@keyframes vpTrendRise { from { opacity: 0; } to { opacity: 1; } }
.vp-os .vp-trend[data-chart] .vp-trend-line { stroke-dasharray: 3000; animation: vpTrendDraw .9s var(--ease-out, ease) forwards; }
.vp-os .vp-trend[data-chart] .vp-trend-line--vis { stroke-dasharray: 4 3; animation: vpTrendRise .9s ease forwards; }
.vp-os .vp-trend[data-chart] .vp-trend-area { animation: vpTrendRise 1s ease forwards; }
@media (prefers-reduced-motion: reduce) {
  .vp-os .vp-trend[data-chart] .vp-trend-line,
  .vp-os .vp-trend[data-chart] .vp-trend-line--vis,
  .vp-os .vp-trend[data-chart] .vp-trend-area { animation: none; stroke-dasharray: none; }
  .vp-os .vp-trend-line--vis { stroke-dasharray: 4 3; }
  .vp-os .vp-pt__guide, .vp-os .vp-pt__dot, .vp-os .vp-pt__tip { transition: none; }
}

/* ── Editor: Ghost-style writing surface ─────────────────────────────────────
   A calm, centered, chrome-free writing measure. Block controls stay invisible
   until the writer reaches for them; text sits at a book-like size on a quiet
   surface. Overrides the utilitarian editor defaults above (same specificity,
   later in the cascade). */
.vp-os .editor-title {
  max-width: 46rem;
  margin-left: auto;
  margin-right: auto;
  font-size: 2.6rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  padding-top: var(--sp-4);
}
.vp-os .editor-canvas { align-items: stretch; }
.vp-os .eblock {
  width: 100%;
  max-width: calc(46rem + 32px + var(--sp-2));
  margin-left: auto;
  margin-right: auto;
}
.vp-os .eblock:hover { background: transparent; }
.vp-os .eblock:focus-within { background: transparent; }
.vp-os .eblock__btn {
  border-color: transparent;
  background: transparent;
  color: var(--text-3);
  border-radius: var(--r-sm);
}
.vp-os .eblock__btn:hover { background: var(--bg-surface-2); color: var(--text); }
.vp-os .eblock__text, .vp-os .eblock__input {
  font-size: 1.05rem;
  line-height: 1.7;
}
.vp-os .eblock__text:focus, .vp-os .eblock__input:focus {
  border-color: transparent;
  background: var(--bg-surface-2);
}
.vp-os .eblock__heading { font-size: 1.55rem; letter-spacing: -0.015em; line-height: 1.25; }
.vp-os .eblock__code, .vp-os .eblock__lang { font-size: 0.9rem; }
.vp-os .eblock--quote .eblock__text { border-left: 3px solid var(--border-strong); }
/* Elegant file-drop affordance over the whole canvas. */
.vp-os .editor-canvas.is-dragover {
  outline: 2px dashed var(--brand);
  outline-offset: -6px;
  border-radius: var(--r-md);
  background: var(--brand-dim);
}

/* ── VayuMail: rotating setup QR + refined mail surface ──────────────────────
   Clean, modern-minimalist presentation: generous whitespace, flat surfaces,
   no gradients. The QR page is a single calm card built to be scanned. */
.vp-os .vm-qr-card { max-width: 46rem; }
.vp-os .vm-qr-hero { display: flex; gap: var(--sp-6); align-items: flex-start; flex-wrap: wrap; }
.vp-os .vm-qr-img {
  background: #fff;
  padding: 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  flex: 0 0 auto;
}
.vp-os .vm-qr-info { flex: 1 1 240px; min-width: 0; }
.vp-os .vm-qr-email { font-size: var(--text-sm); color: var(--text-2); margin-bottom: var(--sp-2); overflow-wrap: anywhere; }
.vp-os .vm-qr-pass {
  font-size: 1.15rem;
  letter-spacing: 0.04em;
  padding: var(--sp-2) var(--sp-3);
  background: var(--bg-surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  display: inline-block;
  margin-bottom: var(--sp-3);
  user-select: all;
  overflow-wrap: anywhere;
}
.vp-os .vm-qr-launch { flex-wrap: wrap; gap: var(--sp-2); }
.vp-os .vm-qr-launch form { margin: 0; }
/* Mail list rows: calmer separators, roomier touch targets. */
.vp-os .vm-list .vm-row-item { padding-block: 0.65rem; }

/* ── Website studio (business site) ─────────────────────────────────────────*/
.vp-os .biz-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--sp-3); }
.vp-os .biz-card {
  text-align: left;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--bg-surface);
  padding: var(--sp-4);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  transition: border-color var(--t-fast);
}
.vp-os .biz-card:hover { border-color: var(--brand); }
.vp-os .biz-card--active { border-color: var(--brand); background: var(--brand-dim); }
.vp-os .biz-card-cat { font-size: var(--text-xs); letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-3); }
.vp-os .biz-card-name { font-weight: 700; font-size: var(--text-lg); color: var(--text); }
.vp-os .biz-card-tag { line-height: 1.45; }
.vp-os .vb-mode { display: block; padding: var(--sp-2) 0; cursor: pointer; }
.vp-os .biz-form { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); }
.vp-os .biz-form-col { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.vp-os .biz-form .pm-label { margin-top: var(--sp-2); }
@media (max-width: 800px) { .vp-os .biz-form { grid-template-columns: 1fr; } }
/* The .zip deploy row: file picker, Deploy, optional Roll back, status. It was
   the div's only class and had no rule, so the controls ran together with no
   spacing and the status text sat flush against the last button. */
.vp-os .biz-deploy { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }


/* ============================================================
   VayuShield console (VayuShield / VayuAnalytics)
   Strict-CSP safe: all rules are classes served from this same
   -origin stylesheet (style-src 'self'); no inline <style>/style=.
   Toggle switches, :has() progressive disclosure, stat cards.
   ============================================================ */

/* Vertical rhythm between the console's cards/forms/details. */
.vp-os .vs-page { display: flex; flex-direction: column; gap: var(--sp-5); }

/* ── Status hero ─────────────────────────────────────────────── */
.vp-os .vs-hero {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  background: linear-gradient(135deg, var(--bg-surface), var(--bg-surface-2));
}
.vp-os .vs-title {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-family: var(--font-head);
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--text);
}
.vp-os .vs-dot { width: 12px; height: 12px; border-radius: var(--r-full); background: var(--text-3); flex: none; }
.vp-os .vs-dot.on { background: var(--ok); box-shadow: 0 0 0 4px var(--ok-dim); }
.vp-os .vs-dot.attack { background: var(--danger); box-shadow: 0 0 0 4px var(--danger-dim); animation: vs-pulse 1.4s ease-in-out infinite; }
@keyframes vs-pulse { 0%, 100% { box-shadow: 0 0 0 4px var(--danger-dim); } 50% { box-shadow: 0 0 0 8px transparent; } }
.vp-os .vs-metrics { display: flex; gap: var(--sp-8); flex-wrap: wrap; }
.vp-os .vs-metric .n { font-family: var(--font-head); font-size: var(--text-2xl); font-weight: 700; line-height: 1; color: var(--text); }
.vp-os .vs-metric .l { font-size: var(--text-xs); letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-2); margin-top: var(--sp-1); }

/* Lead paragraph under a card-title; section divider within a card. */
.vp-os .vs-lead { margin: calc(-1 * var(--sp-2)) 0 var(--sp-3); }
.vp-os .vs-section { margin-top: var(--sp-6); padding-top: var(--sp-5); border-top: 1px solid var(--border); }

/* ── Aegis defense-layer map ─────────────────────────────────── */
.vp-os .vs-aegis { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--sp-3); }
.vp-os .vs-layer { display: flex; gap: var(--sp-3); align-items: flex-start; padding: var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-surface-2); }
.vp-os .vs-layer-tag { font-family: var(--font-head); font-weight: 700; font-size: var(--text-sm); color: var(--text-2); border: 1px solid var(--border-strong); border-radius: var(--r-sm); padding: 2px 6px; flex: none; }
/* The flexible column beside the fixed-width layer tag. Every sibling in this
   family had a rule and this one did not, so the column kept its content's
   intrinsic width and a long stats row pushed the card sideways. */
.vp-os .vs-layer-body { flex: 1; min-width: 0; }
.vp-os .vs-layer-name { font-weight: 600; color: var(--text); font-size: var(--text-sm); }
.vp-os .vs-layer-desc { color: var(--text-2); font-size: var(--text-xs); margin-top: 2px; }
.vp-os .vs-layer-stats { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
.vp-os .vs-layer-stats span { font-family: var(--font-mono, monospace); font-size: var(--text-xs); color: var(--text); background: var(--bg-surface-3); border-radius: var(--r-sm); padding: 1px 6px; }
.vp-os .vs-layer.is-live { border-color: var(--ok); }
.vp-os .vs-layer.is-live .vs-layer-tag { color: var(--ok); border-color: var(--ok); }
.vp-os .vs-layer.is-tuned { border-color: var(--brand); }
.vp-os .vs-layer.is-tuned .vs-layer-tag { color: var(--brand); border-color: var(--brand); }
.vp-os .vs-layer.is-hot { border-color: var(--warn, #d97706); }
.vp-os .vs-layer.is-hot .vs-layer-tag { color: var(--warn, #d97706); border-color: var(--warn, #d97706); }
.vp-os .vs-layer.is-off { opacity: 0.65; }

/* ── Ephemeral save-feedback toast ───────────────────────────── */
.vp-os .vs-toast { position: fixed; bottom: var(--sp-6); left: 50%; transform: translate(-50%, 12px); opacity: 0; background: var(--bg-surface); color: var(--text); border: 1px solid var(--ok); border-radius: var(--r-md); padding: var(--sp-3) var(--sp-5); font-size: var(--text-sm); box-shadow: var(--shadow-lg, 0 8px 30px rgba(0,0,0,.25)); z-index: 200; transition: opacity .3s ease, transform .3s ease; pointer-events: none; }
.vp-os .vs-toast.is-in { opacity: 1; transform: translate(-50%, 0); }

/* ── Feature rows ────────────────────────────────────────────── */
.vp-os .vs-feat { border-top: 1px solid var(--border); }
.vp-os .vs-feat:first-of-type { border-top: 0; }
.vp-os .vs-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); padding: var(--sp-4) 0; }
.vp-os .vs-row-title { font-weight: 600; color: var(--text); }
.vp-os .vs-row-desc { color: var(--text-2); font-size: var(--text-sm); margin-top: var(--sp-1); max-width: 64ch; }

/* ── Toggle switch ───────────────────────────────────────────── */
.vp-os .vs-switch { position: relative; display: inline-block; width: 44px; height: 24px; flex: none; }
.vp-os .vs-switch input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; z-index: 1; }
.vp-os .vs-slider { position: absolute; inset: 0; background: var(--bg-surface-3); border: 1px solid var(--border-strong); border-radius: var(--r-full); transition: background var(--t), border-color var(--t); }
.vp-os .vs-slider::before { content: ""; position: absolute; height: 18px; width: 18px; left: 2px; top: 2px; background: var(--text-2); border-radius: 50%; transition: transform var(--t), background var(--t); }
.vp-os .vs-switch input:checked + .vs-slider { background: var(--brand); border-color: var(--brand); }
.vp-os .vs-switch input:checked + .vs-slider::before { transform: translateX(20px); background: #fff; }
.vp-os .vs-switch input:focus-visible + .vs-slider { box-shadow: 0 0 0 3px var(--brand-glow); }

/* ── Advanced disclosure (revealed only when its master toggle is on) ── */
.vp-os .vs-adv {
  display: none;
  flex-wrap: wrap;
  gap: var(--sp-4);
  padding: var(--sp-4);
  margin: 0 0 var(--sp-4);
  background: var(--bg-surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.vp-os .vs-feat:has(input[data-master]:checked) .vs-adv { display: flex; }
.vp-os .vs-field { display: flex; flex-direction: column; gap: var(--sp-2); }
.vp-os .vs-field label { font-size: var(--text-xs); letter-spacing: 0.03em; text-transform: uppercase; color: var(--text-2); }
.vp-os .vs-field input[type="number"] {
  width: 8rem;
  background: var(--bg-base);
  border: 1px solid var(--border-strong);
  color: var(--text);
  border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-3);
  font-family: var(--font-mono);
}
.vp-os .vs-field input[type="number"]:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-glow); }
.vp-os .vs-field--tog { flex-direction: row; align-items: center; gap: var(--sp-3); }
.vp-os .vs-field--tog label { text-transform: none; font-size: var(--text-sm); color: var(--text); }

/* ── Operator policy fields ──────────────────────────────────────
   vs-adv--open is an advanced block with no master toggle above it: the
   operator's own allow/deny lists are the section, not a detail of one, so
   they must be visible without a switch to reveal them. */
.vp-os .vs-adv--open { display: flex; }
.vp-os .vs-field--area { flex: 1 1 22rem; min-width: 0; }
.vp-os .vs-field--area textarea {
  width: 100%;
  min-height: 5.5rem;
  resize: vertical;
  background: var(--bg-base);
  border: 1px solid var(--border-strong);
  color: var(--text);
  border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: 1.6;
}
.vp-os .vs-field--area textarea:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-glow); }
.vp-os .vs-field--area textarea::placeholder { color: var(--text-3); opacity: 0.7; }
.vp-os .vs-field--area p { margin: 0; max-width: 62ch; }

/* ── Save bar ────────────────────────────────────────────────── */
.vp-os .vs-save { display: flex; align-items: center; gap: var(--sp-4); padding-top: var(--sp-5); margin-top: var(--sp-4); border-top: 1px solid var(--border); flex-wrap: wrap; }

/* ── Network hardening <details> ─────────────────────────────── */
.vp-os .vs-summary { cursor: pointer; margin-bottom: 0; -webkit-user-select: none; user-select: none; }
.vp-os details[open] .vs-summary { margin-bottom: var(--sp-4); }
/* Per-section HTMX "Refresh" control — a right-aligned pill at the top of a
   refreshable section body; its icon spins while the fetch is in flight. */
.vp-os .vs-sec-tools { display: flex; justify-content: flex-end; margin-bottom: var(--sp-3); }
.vp-os .vs-refresh-btn { display: inline-flex; align-items: center; gap: 0.4em; font-size: var(--text-xs); font-weight: 600; color: var(--text-2); background: var(--bg-surface-2); border: 1px solid var(--border); border-radius: var(--r-full); padding: 0.3rem 0.75rem; cursor: pointer; line-height: 1; transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast); }
.vp-os .vs-refresh-btn:hover { color: var(--brand); border-color: var(--brand); background: var(--bg-surface-3); }
.vp-os .vs-refresh-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.vp-os .vs-refresh-ico { display: inline-block; font-size: 1.05em; line-height: 1; }
.vp-os .vs-refresh-btn.htmx-request { opacity: 0.7; pointer-events: none; }
.vp-os .vs-refresh-btn.htmx-request .vs-refresh-ico { animation: vs-spin 0.7s linear infinite; }
@keyframes vs-spin { to { transform: rotate(360deg); } }

/* Flattened engagement sub-sections inside the single "Engagement analytics"
   card — a light top rule instead of a nested card per report. */
.vp-os .vs-subsection { margin-top: var(--sp-5); padding-top: var(--sp-4); border-top: 1px solid var(--border); }
.vp-os .vs-subsection:first-of-type { margin-top: var(--sp-2); padding-top: 0; border-top: 0; }

/* Tier 2/3 network-hardening blocks + copy-command control. */
.vp-os .vs-tier { margin: var(--sp-4) 0; padding: var(--sp-4); border: 1px solid var(--border); border-radius: var(--r); background: var(--bg-surface-2); }
.vp-os .vs-tier-head { font-weight: 700; color: var(--text); margin-bottom: var(--sp-2); }
.vp-os .vs-cmd { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin: var(--sp-2) 0; }
.vp-os .vs-cmd code { flex: 1 1 auto; min-width: 0; overflow-x: auto; white-space: pre; background: var(--bg-surface-3); border: 1px solid var(--border); border-radius: var(--r); padding: 0.45rem 0.6rem; font-size: var(--text-xs); }
.vp-os .vs-copy-btn { flex: none; font-size: var(--text-xs); font-weight: 600; color: var(--text-2); background: var(--bg-surface-2); border: 1px solid var(--border); border-radius: var(--r); padding: 0.45rem 0.8rem; cursor: pointer; transition: color var(--t-fast), border-color var(--t-fast); }
.vp-os .vs-copy-btn:hover { color: var(--brand); border-color: var(--brand); }
.vp-os .vs-copy-btn.is-copied { color: var(--brand); border-color: var(--brand); }

/* Tier 2/3 in-panel toggle rows: title/description on the left, live state pill
   + on/off button on the right. */
.vp-os .vs-hard-row { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.vp-os .vs-hard-ctl { display: flex; align-items: center; gap: var(--sp-3); flex: none; }
/* VayuShield audit trail — compact aggregate tables and the hourly sparkline.
   No inline styles anywhere: assertCSPSafe fails the page on a style="…" attr. */
.vp-os .vs-trail { width: 100%; border-collapse: collapse; font-size: var(--text-sm); margin-top: 0.5rem; }
.vp-os .vs-trail td { padding: 0.28rem 0.5rem 0.28rem 0; border-bottom: 1px solid var(--border); word-break: break-all; }
.vp-os .vs-trail tr:last-child td { border-bottom: 0; }
.vp-os .vs-trail-n { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; width: 1%; }
.vp-os .vs-trail-spark { font-family: var(--font-mono, ui-monospace, monospace); font-size: 1.25rem; line-height: 1; letter-spacing: 0.05em; margin: 0.4rem 0 0.2rem; overflow-x: auto; white-space: nowrap; }
.vp-os .vs-hard-state { font-size: var(--text-xs); font-weight: 700; white-space: nowrap; }
.vp-os .vs-hard-state.is-on { color: #16a34a; }
.vp-os .vs-hard-state.is-off { color: var(--text-3); }
.vp-os .vs-hard-state.is-work { color: #d97706; }
.vp-os .vs-hard-state.is-err { color: #dc2626; }

/* ── Stat cards ──────────────────────────────────────────────── */
.vp-os .vs-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--sp-3); }
.vp-os .vs-stat { background: var(--bg-surface-2); border: 1px solid var(--border); border-radius: var(--r); padding: var(--sp-4); }
.vp-os .vs-stat .n { font-family: var(--font-head); font-size: var(--text-xl); font-weight: 700; line-height: 1; color: var(--text); }
.vp-os .vs-stat .l { font-size: var(--text-xs); letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-2); margin-top: var(--sp-2); }

/* ── Class pills / misc ──────────────────────────────────────── */
.vp-os .vs-pills { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }
.vp-os .vs-pill { font-size: var(--text-xs); padding: var(--sp-1) var(--sp-3); border-radius: var(--r-full); background: var(--bg-surface-3); color: var(--text-2); border: 1px solid var(--border); }
.vp-os .vs-export { margin-top: var(--sp-4); }
.vp-os .vs-actions { white-space: nowrap; }

@media (max-width: 640px) {
  .vp-os .vs-metrics { gap: var(--sp-5); }
  .vp-os .vs-row { flex-wrap: wrap; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   VayuTalk — ephemeral end-to-end-encrypted chat (/os/talk).
   Two-pane messenger: conversation rail + thread. Shares the relay with the
   mobile app; styling matches the console's dark glass system.
   ═══════════════════════════════════════════════════════════════════════════ */
.vp-os .vtalk {
  display: grid;
  grid-template-columns: minmax(15rem, 19rem) minmax(0, 1fr);
  gap: var(--sp-4);
  height: calc(100vh - 13rem);
  min-height: 30rem;
  margin-top: var(--sp-4);
}

/* ── Left rail ─────────────────────────────────────────────────────────────*/
.vp-os .vtalk-side {
  display: flex; flex-direction: column; min-height: 0;
  background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: var(--r-md); overflow: hidden;
}
.vp-os .vtalk-identity {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4); border-bottom: 1px solid var(--border);
}
.vp-os .vtalk-identity-meta { display: flex; flex-direction: column; min-width: 0; }
.vp-os .vtalk-identity-meta strong {
  font-size: var(--text-sm); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vp-os .vtalk-status {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: var(--text-xs); color: var(--text-2);
}
.vp-os .vtalk-status::before {
  content: ""; width: 7px; height: 7px; border-radius: var(--r-full);
  background: var(--text-3); transition: background var(--t);
}
.vp-os .vtalk-status[data-state="online"] { color: var(--ok); }
.vp-os .vtalk-status[data-state="online"]::before { background: var(--ok); box-shadow: 0 0 8px var(--ok-dim); }
.vp-os .vtalk-status[data-state="offline"] { color: var(--warn); }
.vp-os .vtalk-status[data-state="offline"]::before { background: var(--warn); }

.vp-os .vtalk-newchat { display: flex; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); }
.vp-os .vtalk-newchat .input { flex: 1; min-width: 0; }

/* Safety-number verify (collapsible E2E check). */
.vp-os .vtalk-safety { margin: 0 var(--sp-4) var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg-surface-2); }
.vp-os .vtalk-safety__sum { display: flex; align-items: center; gap: 8px; padding: 8px 10px; font-size: var(--text-xs); font-weight: 600; color: var(--text-2); cursor: pointer; list-style: none; }
.vp-os .vtalk-safety__sum::-webkit-details-marker { display: none; }
.vp-os .vtalk-safety__sum:hover { color: var(--text); }
.vp-os .vtalk-safety[open] .vtalk-safety__sum { color: var(--brand); }
.vp-os .vtalk-safety__body { padding: 0 10px 10px; display: grid; gap: 8px; }
.vp-os .vtalk-safety__num { font-family: var(--font-mono); font-size: 0.8rem; letter-spacing: 0.06em; color: var(--text); background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 8px; word-break: break-all; line-height: 1.6; }

/* Conversations header + search + empty state. */
.vp-os .vtalk-convos-head { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-2) var(--sp-4) 4px; }
.vp-os .vtalk-convos-title { font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-3); font-weight: 600; }
.vp-os .vtalk-search-wrap { position: relative; margin: 0 var(--sp-4) var(--sp-2); }
.vp-os .vtalk-search-ico { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--text-3); pointer-events: none; }
.vp-os .vtalk-search { width: 100%; padding-left: 30px; }
.vp-os .vtalk-convos:empty::before {
  content: "No conversations yet — start one above.";
  display: block; padding: var(--sp-6) var(--sp-4); text-align: center;
  font-size: var(--text-xs); color: var(--text-3); line-height: 1.5;
}

.vp-os .vtalk-convos {
  list-style: none; margin: 0; padding: var(--sp-2);
  overflow-y: auto; flex: 1; min-height: 0;
}
.vp-os .vtalk-convo {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3); border-radius: var(--r);
  cursor: pointer; transition: background var(--t-fast);
}
.vp-os .vtalk-convo:hover { background: var(--bg-surface-2); }
.vp-os .vtalk-convo--active { background: var(--brand-dim); }
.vp-os .vtalk-convo-meta { flex: 1; min-width: 0; }
.vp-os .vtalk-convo-name {
  display: block; font-size: var(--text-sm); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vp-os .vtalk-convo-badge {
  min-width: 1.25rem; height: 1.25rem; padding: 0 .35rem;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--text-xs); font-weight: 600; color: #fff;
  background: var(--brand); border-radius: var(--r-full);
}

/* Avatars (JS-built rail + Go-built header share the round chip look). */
.vp-os .vtalk-avatar {
  width: 2.1rem; height: 2.1rem; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--text-sm); font-weight: 600; color: #fff;
  background: linear-gradient(135deg, var(--brand), var(--accent));
  border-radius: var(--r-full); overflow: hidden;
}
/* When a real mailbox picture loads, it fills the round chip (no gradient). */
.vp-os .vtalk-avatar--img { background: none; }
.vp-os .vtalk-avatar--img img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ── Main pane ─────────────────────────────────────────────────────────────*/
.vp-os .vtalk-main {
  display: flex; flex-direction: column; min-height: 0; min-width: 0;
  background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: var(--r-md); overflow: hidden;
}
.vp-os .vtalk-main[data-empty] .vtalk-thread-head,
.vp-os .vtalk-main[data-empty] .vtalk-composer { display: none; }

.vp-os .vtalk-thread-head {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--border);
}
.vp-os .vtalk-head-meta { display: flex; flex-direction: column; min-width: 0; }
.vp-os .vtalk-head-meta strong { font-size: var(--text-base); color: var(--text); }

.vp-os .vtalk-thread {
  flex: 1; min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-4);
}

.vp-os .vtalk-hint {
  margin: auto; max-width: 24rem; text-align: center;
  color: var(--text-2); font-size: var(--text-sm);
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3);
}
.vp-os .vtalk-hint-badge {
  width: 3rem; height: 3rem; display: flex; align-items: center; justify-content: center;
  font-size: 1.5rem; border-radius: var(--r-full);
  background: var(--brand-dim); border: 1px solid var(--border-strong);
}

/* ── Bubbles ───────────────────────────────────────────────────────────────*/
.vp-os .vtalk-msg { display: flex; max-width: 78%; }
.vp-os .vtalk-msg--in { align-self: flex-start; }
.vp-os .vtalk-msg--out { align-self: flex-end; }
.vp-os .vtalk-bubble {
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md);
  background: var(--bg-surface-2); border: 1px solid var(--border);
  animation: vtalk-pop var(--t-spring);
}
.vp-os .vtalk-msg--out .vtalk-bubble {
  background: linear-gradient(135deg, var(--brand), #0284c7);
  border-color: transparent; color: #fff;
}
.vp-os .vtalk-bubble-text { font-size: var(--text-sm); line-height: 1.45; white-space: pre-wrap; word-break: break-word; }
.vp-os .vtalk-bubble-foot {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-top: .35rem; font-size: var(--text-xs); opacity: .8;
}
.vp-os .vtalk-msg--in .vtalk-bubble-foot { color: var(--text-2); }
.vp-os .vtalk-bubble-status.is-read { color: var(--ok); opacity: 1; }
.vp-os .vtalk-msg--out .vtalk-bubble-status.is-read { color: #d1fae5; }
.vp-os .vtalk-bubble-status.is-error { color: var(--warn); opacity: 1; }
.vp-os .vtalk-bubble-status.is-expired { color: var(--text-3); }

.vp-os .vtalk-msg--gone { animation: vtalk-fade var(--t-slow) forwards; }
@keyframes vtalk-pop { from { transform: translateY(6px) scale(.98); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes vtalk-fade { to { transform: scale(.96); opacity: 0; } }

/* Burn-after-read countdown — appears once a message is read and ticks down. */
.vp-os .vtalk-bubble-burn {
  font-variant-numeric: tabular-nums; font-weight: 600;
  color: var(--warn); opacity: 1; white-space: nowrap;
}
.vp-os .vtalk-msg--out .vtalk-bubble-burn { color: #fed7aa; }
/* An armed (reading, counting down) message gets a subtle warm ring. */
.vp-os .vtalk-msg--armed .vtalk-bubble { box-shadow: inset 0 0 0 1px var(--warn-dim, rgba(245,158,11,.25)); }
/* Live-mode messages read as hotter: a dashed accent edge. */
.vp-os .vtalk-msg--live .vtalk-bubble { border: 1px dashed rgba(245, 158, 11, .55); }

/* Live-mode composer toggle. */
.vp-os .vtalk-live { cursor: pointer; user-select: none; gap: 4px; }
.vp-os .vtalk-live input { accent-color: var(--warn); width: 15px; height: 15px; }

/* ── VayuTor — onion services control page ─────────────────────────────────── */
.vp-os .vt-hero {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap;
}
.vp-os .vt-hero__main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.vp-os .vt-state {
  display: inline-flex; align-items: center; gap: 0.5em;
  font-size: var(--text-xs); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  width: fit-content;
}
.vp-os .vt-dot { width: 0.6rem; height: 0.6rem; border-radius: 50%; background: currentColor; }
.vp-os .vt-state--on { color: var(--ok); }
.vp-os .vt-state--on .vt-dot { animation: vp-live-pulse 1.6s ease-in-out infinite; }
.vp-os .vt-state--warn { color: var(--warn); }
.vp-os .vt-state--off { color: var(--text-3); }
.vp-os .vt-hero__count { display: flex; align-items: baseline; gap: 0.4em; }
.vp-os .vt-count { font-size: 2.4rem; font-weight: 700; line-height: 1; color: var(--brand); font-variant-numeric: tabular-nums; }
.vp-os .vt-hero__action { margin: 0; }

.vp-os .vt-warn { border-color: var(--warn); background: var(--warn-dim); }

/* Onion address cards. */
.vp-os .vt-onions { display: grid; gap: var(--sp-3); }
.vp-os .vt-onion {
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4); background: var(--bg-surface);
}
.vp-os .vt-onion__host { font-weight: 600; color: var(--text); margin-bottom: 4px; }
.vp-os .vt-onion__row { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.vp-os .vt-onion__addr {
  font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
  font-size: var(--text-xs); color: var(--brand);
  background: var(--bg-surface-2); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: 0.3rem 0.5rem;
  overflow-wrap: anywhere; word-break: break-all; flex: 1; min-width: 0;
}
.vp-os .vt-copy.is-copied { color: var(--ok); border-color: var(--ok); }

.vp-os .vt-note__list { margin: 0; padding-left: 1.1rem; display: grid; gap: 6px; color: var(--text-2); }

/* Tor bootstrap log tail shown while publishing (wraps, scrolls, never overflows). */
.vp-os .vt-log { margin: 0; padding: 8px 10px; border-radius: 8px; background: var(--bg-surface-3); border: 1px solid var(--border); white-space: pre-wrap; word-break: break-word; overflow-x: auto; font-family: var(--mono, monospace); line-height: 1.45; }

/* Operator bridge configuration (paste obfs4 lines — no server access needed). */
.vp-os .vt-bridges__input { width: 100%; box-sizing: border-box; resize: vertical; min-height: 76px; padding: 10px 12px; border-radius: 8px; background: var(--bg-surface-2); border: 1px solid var(--border); color: var(--text); font-family: var(--mono, monospace); font-size: 12px; line-height: 1.5; }
.vp-os .vt-bridges__input:focus { outline: none; border-color: var(--accent); }
.vp-os .vt-bridges__row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 10px; }
.vp-os .vt-bridges__on { color: var(--ok, #34d399); }
.vp-os .vt-bridges__warn { color: var(--warn, #f59e0b); max-width: 60ch; }

/* Opt-in per-page onion analytics (aggregate, privacy-safe). */
.vp-os .vt-pages__table { overflow-x: auto; }
.vp-os .vt-pages__t { width: 100%; border-collapse: collapse; font-size: 13px; }
.vp-os .vt-pages__t th { text-align: left; font-weight: 600; color: var(--text-muted, #9ca3af); padding: 6px 10px; border-bottom: 1px solid var(--border); }
.vp-os .vt-pages__t td { padding: 6px 10px; border-bottom: 1px solid var(--border); vertical-align: top; }
.vp-os .vt-pages__t td code { word-break: break-all; }
.vp-os .vt-pages__num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.vp-os .vt-pages__actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 12px; }

/* Onion health & alerts. */
.vp-os .vt-health__now { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.vp-os .vt-health__badge { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: 999px; font-size: 12px; font-weight: 600; border: 1px solid var(--border); }
.vp-os .vt-health__badge--sm { padding: 2px 8px; font-size: 11px; }
.vp-os .vt-health__badge--ok { color: var(--ok, #34d399); border-color: color-mix(in srgb, var(--ok, #34d399) 40%, transparent); }
.vp-os .vt-health__badge--warn { color: var(--warn, #f59e0b); border-color: color-mix(in srgb, var(--warn, #f59e0b) 40%, transparent); }
.vp-os .vt-health__badge--err { color: var(--danger, #f87171); border-color: color-mix(in srgb, var(--danger, #f87171) 45%, transparent); }
.vp-os .vt-health__badge--off { color: var(--text-muted, #9ca3af); }
.vp-os .vt-health__log { margin-top: 12px; display: grid; gap: 6px; }
.vp-os .vt-health__row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.vp-os .vt-health__ago { margin-left: auto; white-space: nowrap; }

/* Vanity (custom-prefix) onion address generator. */
.vp-os .vt-vanity__run { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.vp-os .vt-vanity__form { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.vp-os .vt-vanity__select, .vp-os .vt-vanity__input { padding: 8px 10px; border-radius: 8px; background: var(--bg-surface-2); border: 1px solid var(--border); color: var(--text); font-size: 13px; }
.vp-os .vt-vanity__input { font-family: var(--mono, monospace); width: 10ch; text-transform: lowercase; }
.vp-os .vt-vanity__select:focus, .vp-os .vt-vanity__input:focus { outline: none; border-color: var(--accent); }

/* Off-screen buffer used by the clipboard fallback (no inline styles). */
.vp-os .vt-copy-buf { position: fixed; left: -9999px; top: 0; opacity: 0; }

@media (max-width: 560px) {
  .vp-os .vt-hero { align-items: flex-start; }
  .vp-os .vt-hero__action { width: 100%; }
  .vp-os .vt-hero__action .btn { width: 100%; }
}

/* ── Composer ──────────────────────────────────────────────────────────────*/
.vp-os .vtalk-composer {
  border-top: 1px solid var(--border); padding: var(--sp-3) var(--sp-4);
  display: flex; flex-direction: column; gap: var(--sp-2);
}
.vp-os .vtalk-input {
  width: 100%; resize: none; min-height: 2.6rem; max-height: 10rem;
  padding: var(--sp-3); border-radius: var(--r);
  background: var(--bg-base); color: var(--text);
  border: 1px solid var(--border); font: inherit; font-size: var(--text-sm);
}
.vp-os .vtalk-input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-dim); }
.vp-os .vtalk-input:disabled { opacity: .5; }
.vp-os .vtalk-composer-actions { display: flex; align-items: center; gap: var(--sp-3); }
.vp-os .vtalk-opt { display: inline-flex; align-items: center; gap: var(--sp-2); }
.vp-os .vtalk-opt .input { width: auto; }
.vp-os .vtalk-opt--spacer { flex: 1; }
.vp-os .vtalk-composer-actions .btn { margin-left: var(--sp-2); }

/* ── Responsive: stack the rail above the thread ───────────────────────────*/
@media (max-width: 800px) {
  .vp-os .vtalk { grid-template-columns: 1fr; height: auto; }
  .vp-os .vtalk-side { max-height: 40vh; }
  .vp-os .vtalk-thread { min-height: 22rem; }
  .vp-os .vtalk-msg { max-width: 90%; }
}

/* ── VayuTalk: key verification + reachability ──────────────────────────────*/
.vp-os .vtalk-thread-head { flex-wrap: wrap; position: relative; }
.vp-os .vtalk-head-meta { flex: 1; }
.vp-os .vtalk-verify-btn {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .35rem .7rem; font-size: var(--text-xs); font-weight: 600;
  color: var(--text-2); background: var(--bg-surface-2);
  border: 1px solid var(--border); border-radius: var(--r-full); cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.vp-os .vtalk-verify-btn:hover { background: var(--bg-surface-3); color: var(--text); }
.vp-os .vtalk-verify-btn.is-verified { color: var(--ok); border-color: var(--ok); background: var(--ok-dim); }

/* Rename / Keep sit beside Verify; share its pill look. */
.vp-os .vtalk-head-actions { display: inline-flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.vp-os .vtalk-head-btn {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .35rem .7rem; font-size: var(--text-xs); font-weight: 600;
  color: var(--text-2); background: var(--bg-surface-2);
  border: 1px solid var(--border); border-radius: var(--r-full); cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.vp-os .vtalk-head-btn:hover { background: var(--bg-surface-3); color: var(--text); }
.vp-os .vtalk-head-btn.is-on { color: var(--brand); border-color: var(--brand); background: var(--brand-dim); }

/* Kept pin in the conversation row (a chat you chose to preserve across reloads). */
.vp-os .vtalk-convo-pin { flex: none; font-size: .8em; opacity: .85; line-height: 1; }

.vp-os .vtalk-verify {
  flex-basis: 100%; margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg-base); border: 1px solid var(--border); border-radius: var(--r);
}
.vp-os .vtalk-verify-intro { font-size: var(--text-xs); color: var(--text-2); margin: 0 0 var(--sp-3); line-height: 1.5; }
.vp-os .vtalk-safety-row { display: flex; align-items: baseline; gap: var(--sp-3); margin-bottom: var(--sp-2); }
.vp-os .vtalk-safety-label { min-width: 3rem; font-size: var(--text-xs); color: var(--text-3); text-transform: uppercase; letter-spacing: .04em; }
.vp-os .vtalk-safety-code {
  font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text);
  letter-spacing: .06em; word-spacing: .15em; line-height: 1.6;
  overflow-wrap: anywhere;
}
.vp-os .vtalk-verify-toggle {
  display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3);
  font-size: var(--text-sm); color: var(--text); cursor: pointer;
}
.vp-os .vtalk-safety-missing { margin-top: var(--sp-2); font-size: var(--text-xs); color: var(--warn); line-height: 1.5; }

.vp-os .vtalk-convo--verified .vtalk-convo-name::after {
  content: "🛡"; margin-left: .35rem; font-size: .8em; opacity: .9;
}

.vp-os .vtalk-warn {
  margin-bottom: var(--sp-3); padding: var(--sp-3);
  font-size: var(--text-xs); color: var(--warn); line-height: 1.5;
  background: var(--warn-dim); border: 1px solid var(--warn);
  border-radius: var(--r);
}

/* "Chat as" identity switcher (admins with multiple mailboxes) */
.vp-os .vtalk-as {
  font-family: var(--font-body); font-size: var(--text-sm); font-weight: 600;
  color: var(--text); background: var(--bg-surface-2);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: .2rem .5rem; max-width: 100%;
}
.vp-os .vtalk-as:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-dim); }

/* ============================================================================
   VayuMail — Accounts section (enterprise HTMX redesign)
   Collapsible mailbox cards, stat strip, native <meter> storage, device
   live-refresh. All rules scoped under .vp-os; no inline styles (CSP-safe).
   ============================================================================ */

/* Stat strip — at-a-glance summary above the mailbox list. */
.vp-os .vm-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
}
.vp-os .vm-stat {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-4) var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: 2px;
  box-shadow: var(--sh-sm);
}
.vp-os .vm-stat__v { font-family: var(--font-head); font-size: var(--text-2xl); font-weight: 700; color: var(--text); line-height: 1.1; }
.vp-os .vm-stat__l { font-size: var(--text-xs); color: var(--text-3); text-transform: uppercase; letter-spacing: .04em; }
.vp-os .vm-stat--warn { border-color: var(--warn); background: var(--warn-dim); }
.vp-os .vm-stat--warn .vm-stat__v { color: var(--warn); }

/* ── VayuMail: Monetization-style shell (premium tab bar + lifting stat cards) ─ */
/* One place restyles the sub-nav and the stat strip across every VayuMail page. */
.vp-os .vmtabs {
  display: flex; flex-wrap: wrap; gap: var(--sp-1);
  margin: 0 0 var(--sp-5); padding: 5px;
  border: 1px solid var(--border); border-radius: var(--r-full);
  background: var(--bg-surface); box-shadow: var(--sh-sm);
  width: fit-content; max-width: 100%;
}
.vp-os .vmtabs .tab {
  padding: .45rem .95rem; border: 0; border-radius: var(--r-full);
  color: var(--text-2); font-size: var(--text-sm); font-weight: 600;
  transition: color var(--t-fast), background var(--t-fast);
}
.vp-os .vmtabs .tab:hover { color: var(--text); background: var(--bg-surface-2); text-decoration: none; }
.vp-os .vmtabs .tab--active,
.vp-os .vmtabs .tab--active:hover { color: #fff; background: var(--brand); }

/* Stat tiles gain the Monetization stat-card lift + top accent. */
.vp-os .vm-stat { position: relative; overflow: hidden; transition: border-color var(--t), box-shadow var(--t), transform var(--t); }
.vp-os .vm-stat::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(90deg, var(--brand), transparent);
  opacity: 0; transition: opacity var(--t);
}
.vp-os .vm-stat:hover { border-color: var(--border-strong); box-shadow: var(--sh); transform: translateY(-2px); }
.vp-os .vm-stat:hover::before { opacity: .85; }
@media (prefers-reduced-motion: reduce) { .vp-os .vm-stat:hover { transform: none; } }

/* Collapsible mailbox cards. */
.vp-os .vm-acct-list { display: flex; flex-direction: column; gap: var(--sp-3); }
.vp-os .vm-acct {
  padding: 0;
  overflow: hidden;
  transition: border-color var(--t), box-shadow var(--t);
}
.vp-os .vm-acct[open] { border-color: var(--border-strong); box-shadow: var(--sh); }
.vp-os .vm-acct__sum {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.vp-os .vm-acct__sum::-webkit-details-marker { display: none; }
.vp-os .vm-acct__sum:hover { background: var(--bg-surface-2); }
.vp-os .vm-acct__avatar {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  border-radius: var(--r-full);
  background: var(--brand-dim);
  color: var(--brand);
  display: grid; place-items: center;
  font-weight: 700; font-size: var(--text-base);
}
.vp-os .vm-acct__id { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.vp-os .vm-acct__email { font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vp-os .vm-acct__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vp-os .vm-acct__badges { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
.vp-os .vm-acct__store { display: flex; align-items: center; gap: var(--sp-2); flex: 0 0 auto; }
.vp-os .vm-acct__chev {
  flex: 0 0 auto;
  width: 0; height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--text-3);
  transition: transform var(--t);
}
.vp-os .vm-acct[open] .vm-acct__chev { transform: rotate(180deg); }

/* Native storage meter — no inline style, survives HTMX swaps. */
.vp-os .vm-meter { width: 84px; height: 8px; border-radius: var(--r-full); background: var(--bg-surface-3); border: none; }
.vp-os .vm-meter::-webkit-meter-bar { background: var(--bg-surface-3); border-radius: var(--r-full); border: none; }
.vp-os .vm-meter::-webkit-meter-optimum-value { background: var(--brand); border-radius: var(--r-full); }
.vp-os .vm-meter::-webkit-meter-suboptimum-value { background: var(--warn); border-radius: var(--r-full); }
.vp-os .vm-meter::-webkit-meter-even-less-good-value { background: var(--danger); border-radius: var(--r-full); }
.vp-os .vm-meter:-moz-meter-optimum::-moz-meter-bar { background: var(--brand); }

/* Expanded card body. */
.vp-os .vm-acct__body {
  padding: var(--sp-4) var(--sp-5) var(--sp-5);
  border-top: 1px solid var(--border);
  background: var(--bg-surface-2);
}
.vp-os .vm-acct__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--sp-4);
  margin-bottom: var(--sp-4);
}
.vp-os .vm-acct__meta { margin-bottom: var(--sp-3); }
.vp-os .vm-acct__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* Device card: live indicator + pending-attention banner. */
.vp-os .vm-card-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-4); }
.vp-os .vm-card-head .card-title { margin-bottom: 0; }
.vp-os .vm-live { font-size: var(--text-xs); color: var(--ok); display: inline-flex; align-items: center; gap: 4px; }
.vp-os .vm-attention {
  background: var(--warn-dim);
  border: 1px solid var(--warn);
  color: var(--text);
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  font-size: var(--text-sm);
}
.vp-os .vm-poller { display: none; }

@media (max-width: 640px) {
  .vp-os .vm-acct__store { display: none; }
  .vp-os .vm-acct__badges { flex: 1 1 100%; }
}

/* ── VayuMail DNS tab: collapsible sections + verification ──────────────────── */
.vp-os .vm-sec { padding: 0; overflow: hidden; transition: border-color var(--t), box-shadow var(--t); }
.vp-os .vm-sec[open] { border-color: var(--border-strong); box-shadow: var(--sh); }
.vp-os .vm-sec__head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.vp-os .vm-sec__head::-webkit-details-marker { display: none; }
.vp-os .vm-sec__head:hover { background: var(--bg-surface-2); }
.vp-os .vm-sec__title { font-family: var(--font-head); font-weight: 600; color: var(--text); flex: 1 1 auto; min-width: 0; }
.vp-os .vm-sec__meta { flex: 0 0 auto; display: flex; align-items: center; gap: var(--sp-2); }
.vp-os .vm-sec__chev { flex: 0 0 auto; color: var(--text-3); transition: transform var(--t); font-size: var(--text-sm); }
.vp-os .vm-sec[open] .vm-sec__chev { transform: rotate(180deg); }
.vp-os .vm-sec__body { padding: 0 var(--sp-5) var(--sp-5); }
.vp-os .vm-sec__body > p:first-child { margin-top: 0; }

/* Record type chip + copy button + value cell. */
.vp-os .vm-tag {
  display: inline-block;
  padding: 1px var(--sp-2);
  border-radius: var(--r-sm);
  background: var(--brand-dim);
  color: var(--brand);
  font-family: var(--font-mono, monospace);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: .02em;
}
.vp-os .vm-dns-table td { vertical-align: top; }
.vp-os .vm-rec-val { display: inline-block; max-width: 100%; }
.vp-os .vm-copy {
  margin-left: var(--sp-2);
  padding: 1px var(--sp-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-surface-2);
  color: var(--text-2);
  font-size: var(--text-xs);
  cursor: pointer;
  vertical-align: middle;
  transition: border-color var(--t), color var(--t);
}
.vp-os .vm-copy:hover { border-color: var(--brand); color: var(--brand); }

/* Verification section: per-domain groups + re-check control. */
.vp-os .vm-verify-head { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-4); flex-wrap: wrap; }
.vp-os .vm-verify-dom { margin-top: var(--sp-4); }
.vp-os .vm-verify-dom:first-of-type { margin-top: 0; }
.vp-os .vm-sub-title {
  font-family: var(--font-head);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-2);
  margin: 0 0 var(--sp-2);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}
.vp-os .vm-spin { color: var(--text-3); font-size: var(--text-xs); }
.vp-os .htmx-indicator { opacity: 0; transition: opacity var(--t); }
.vp-os .htmx-request .htmx-indicator,
.vp-os .htmx-request.htmx-indicator { opacity: 1; }

/* ── VayuMail Mailbox: per-domain directory cards ──────────────────────────── */
.vp-os .vm-dom-card + .vm-dom-card { margin-top: var(--sp-4); }
.vp-os .vm-dom-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  margin-bottom: var(--sp-3);
}
.vp-os .vm-dom-name { font-family: var(--font-head); font-weight: 600; font-size: var(--text-base); color: var(--text); }
.vp-os .vm-dom-count { font-size: var(--text-xs); color: var(--text-3); }

/* ── VayuMail Outbox: per-domain filter chips ──────────────────────────────── */
.vp-os .vm-fchip-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-3) 0; }
.vp-os .vm-fchip {
  padding: 3px var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--bg-surface);
  color: var(--text-2);
  font-size: var(--text-xs);
  cursor: pointer;
  transition: border-color var(--t), color var(--t), background var(--t);
}
.vp-os .vm-fchip:hover { border-color: var(--brand); color: var(--brand); }
.vp-os .vm-fchip--on { background: var(--brand-dim); border-color: var(--brand); color: var(--brand); font-weight: 600; }

/* Outbox table: fit the viewport with no horizontal scroll. Fixed layout + a
   colgroup; long cells truncate (nowrap+ellipsis) or wrap within their column. */
.vp-os .vm-outbox-table { table-layout: fixed; width: 100%; }
.vp-os .vm-outbox-table th, .vp-os .vm-outbox-table td { overflow: hidden; vertical-align: top; }
.vp-os .vm-outbox-table td.vm-oc-nowrap { white-space: nowrap; text-overflow: ellipsis; }
.vp-os .vm-outbox-table td.vm-oc-wrap { white-space: normal; overflow-wrap: anywhere; word-break: break-word; }
.vp-os .vm-outbox-table td.vm-oc-act { white-space: normal; }
.vp-os .vm-outbox-table td.vm-oc-act .btn { margin: 0 2px 2px 0; }
/* Primary-only (7 col) widths. */
.vp-os .vm-outbox-table .vm-ocw-to { width: 19%; }
.vp-os .vm-outbox-table .vm-ocw-subj { width: 24%; }
.vp-os .vm-outbox-table .vm-ocw-status { width: 9%; }
.vp-os .vm-outbox-table .vm-ocw-tries { width: 7%; }
.vp-os .vm-outbox-table .vm-ocw-err { width: 17%; }
.vp-os .vm-outbox-table .vm-ocw-when { width: 13%; }
.vp-os .vm-outbox-table .vm-ocw-act { width: 11%; }
/* Multi-domain (8 col) widths — sizes the From column too. */
.vp-os .vm-outbox-table--multi .vm-ocw-from { width: 12%; }
.vp-os .vm-outbox-table--multi .vm-ocw-to { width: 15%; }
.vp-os .vm-outbox-table--multi .vm-ocw-subj { width: 19%; }
.vp-os .vm-outbox-table--multi .vm-ocw-status { width: 8%; }
.vp-os .vm-outbox-table--multi .vm-ocw-tries { width: 6%; }
.vp-os .vm-outbox-table--multi .vm-ocw-err { width: 15%; }
.vp-os .vm-outbox-table--multi .vm-ocw-when { width: 13%; }
.vp-os .vm-outbox-table--multi .vm-ocw-act { width: 12%; }
/* Outbox auto-clear control. */
.vp-os .vm-retention { display: inline-flex; align-items: center; gap: var(--sp-2); }
.vp-os .vm-retention select { width: auto; }

/* Per-mailbox profile picture: uploaded avatar fills the initials chip, and the
   in-card upload/remove control. */
.vp-os .vm-acct__avatar--img { object-fit: cover; background: none; padding: 0; }
.vp-os .vm-acct__avatar-edit { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: var(--sp-3) 0; }
.vp-os .vm-avatar-form { display: inline-flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin: 0; }
.vp-os .vm-avatar-form input[type=file] { max-width: 220px; }

/* Prebuilt cartoon picker — an alternative to uploading a file. */
.vp-os .vm-acct__avatar-pick { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); }
.vp-os .vm-cartoon-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.vp-os .vm-cartoon {
  padding: 2px; border: 1px solid var(--border); border-radius: var(--r-full);
  background: var(--bg-surface-2); cursor: pointer; line-height: 0;
  transition: border-color var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast);
}
.vp-os .vm-cartoon:hover { border-color: var(--brand); transform: translateY(-1px); box-shadow: 0 0 0 3px var(--brand-dim); }
.vp-os .vm-cartoon:focus-visible { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-dim); }
.vp-os .vm-cartoon__img { width: 40px; height: 40px; border-radius: var(--r-full); display: block; }

/* Accounts grouped by domain (VayuDomains): a header per domain over its cards. */
.vp-os .vm-acct-domain + .vm-acct-domain { margin-top: var(--sp-5); }
.vp-os .vm-acct-domain > .vm-dom-head { margin-bottom: var(--sp-3); }

/* Per-mailbox sub-sections inside a card: forwarding + vacation live here so
   every setting for one address sits together, each divided from the block above. */
.vp-os .vm-acct__sub { margin: var(--sp-3) 0 0; padding-top: var(--sp-3); border-top: 1px solid var(--border); }
.vp-os .vm-acct__sub > .field-label { display: block; margin-bottom: var(--sp-2); }
.vp-os .vm-card-fwd { margin: 0; align-items: center; }
.vp-os details.vm-acct__sub > summary .field-label { margin: 0; }

/* PGP public key block inside a mailbox card. The armour is shown in a readonly
   textarea rather than a <pre>: it scrolls in a fixed height, and select-all
   still works when the clipboard API is unavailable (insecure context, or a
   browser that refuses the permission) — which is the copy fallback. */
.vp-os .vm-pgp__armor {
  width: 100%;
  resize: vertical;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
  margin-bottom: var(--sp-2);
}
.vp-os .vm-pgp > .vm-row { align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.vp-os .vm-pgp__wkd { word-break: break-all; }

/* In the VayuPGP key table the armour is only a clipboard source, not something
   to read, so it is taken out of flow. clip-path rather than display:none —
   a hidden element's value is still readable by script, but a display:none
   textarea cannot be select()ed, which is the fallback when the clipboard API
   is refused. */
.vp-os .vm-pgp__armor.hidden-armor {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  border: 0;
  clip-path: inset(50%);
  overflow: hidden;
}

/* ══════════════════════════════════════════════════════════════════════════
   VayuAPI — API Keys console (fine-grained key manager)
   Every rule is CSP-safe (no inline styles): the handlers emit only class
   hooks, all presentation lives here. Layout uses the shared design tokens so
   the console tracks the light/dark themes automatically.
   ══════════════════════════════════════════════════════════════════════════ */

/* Intro / lead paragraph — hold it to a comfortable reading measure. */
.vp-os .ak-intro { max-width: 78ch; }

/* One-time token reveal banner: an accent-framed card that appears after a
   create or rotate. It is the only moment the full secret is shown. */
.vp-os .ak-token-banner { border-color: var(--brand); background: var(--brand-dim); }
.vp-os .ak-token-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); }
.vp-os .ak-token-input { flex: 1 1 340px; min-width: 0; }

/* Issued-keys table: keep rows readable and let the action buttons wrap
   without stretching the row height. */
.vp-os .ak-table td { vertical-align: middle; }
.vp-os .ak-key-label { font-weight: 600; color: var(--text); margin-bottom: 2px; }
.vp-os .ak-row-actions { white-space: normal; }
.vp-os .ak-row-actions .btn { margin: 0 var(--sp-1) var(--sp-1) 0; }
.vp-os .ak-empty { text-align: center; padding: var(--sp-6) var(--sp-4); }

/* Capability badges: a compact monospace chip per granted section:action, with
   a muted "+N more" overflow marker so a wide grant set never bloats the row. */
.vp-os .ak-caps { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); }
.vp-os .ak-cap {
  display: inline-block; padding: 1px var(--sp-2);
  font-family: var(--font-mono); font-size: var(--text-xs); line-height: 1.5;
  color: var(--text-2); background: var(--bg-surface-3);
  border: 1px solid var(--border); border-radius: var(--r-sm);
}
.vp-os .ak-cap-more { font-size: var(--text-xs); color: var(--text-3); font-style: italic; }

/* Scoped-key create form: the label/expiry/rate inputs sit on one wrapping row,
   each field flexing to fit while the rate stays narrow. */
.vp-os .ak-create-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-4); margin-bottom: var(--sp-4); }
.vp-os .ak-field-grow { flex: 1 1 240px; }
.vp-os .ak-field-narrow { flex: 0 0 120px; max-width: 140px; }

/* Toolbar above the permission grid: the "Permissions" label on the left and
   the full-access (superuser) toggle on the right. */
.vp-os .ak-grid-toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-3); margin: var(--sp-5) 0 var(--sp-2); }
.vp-os .ak-superuser { display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer; font-size: var(--text-sm); color: var(--text-2); }

/* The 12×6 permission grid: section rows × action columns. Checkboxes centre in
   their cells; the section name column stays left-aligned and never wraps. */
.vp-os .ak-grid th, .vp-os .ak-grid td { text-align: center; padding: var(--sp-2); }
.vp-os .ak-grid-section { text-align: left; font-weight: 600; color: var(--text-2); white-space: nowrap; }
.vp-os .ak-grid-all { color: var(--text-3); font-weight: 500; }
.vp-os .ak-grid input[type="checkbox"], .vp-os .ak-superuser input[type="checkbox"] { accent-color: var(--brand); cursor: pointer; width: 16px; height: 16px; }
/* Full access selected → the grid is dimmed and inert; the grant is implicit. */
.vp-os .ak-grid--disabled { opacity: 0.4; pointer-events: none; }

.vp-os .ak-create-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin-top: var(--sp-4); }

/* Third-party service credential cards (IndexNow, OpenRouter, Ollama, n8n,
   custom): header with title + enable toggle, then the secret/endpoint fields
   and the save/reveal/delete action row. */
.vp-os .ak-cred-card + .ak-cred-card { margin-top: var(--sp-4); }
.vp-os .ak-cred-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); margin-bottom: var(--sp-3); }
.vp-os .ak-cred-desc { max-width: 68ch; margin-top: var(--sp-1); }
.vp-os .ak-cred-toggle { display: inline-flex; align-items: center; gap: var(--sp-2); flex-shrink: 0; margin: 0; }
.vp-os .ak-cred-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); }

/* Custom-credential add form: name / endpoint / secret inputs + Add button. */
.vp-os .ak-cc-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-3); margin-bottom: var(--sp-4); }

/* ── Claude connector page (ADR-0139, Stage 2) ─────────────────────────────
   Three grant choices sit side by side and wrap to a single column on narrow
   viewports; the full-control card is accent-framed so the "give Claude the
   keys" option reads as the headline. Config snippets use a scrollable mono
   block so a long endpoint/key never forces horizontal page scroll. */
.vp-os .cx-grant-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--sp-4); margin-bottom: var(--sp-3); }
.vp-os .cx-grant { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-4); border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-surface-2); }
.vp-os .cx-grant--full { border-color: var(--brand); background: var(--brand-dim); }
.vp-os .cx-grant-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.vp-os .cx-grant p { flex: 1 1 auto; margin: 0; }
.vp-os .cx-grant .btn { margin-top: var(--sp-2); }
.vp-os .cx-code {
  margin: var(--sp-2) 0 0; padding: var(--sp-3);
  font-size: var(--text-xs); line-height: 1.55; white-space: pre;
  color: var(--text-2); background: var(--bg-surface-3);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  overflow-x: auto;
}

/* ── OAuth consent screen (ADR-0140) — shown on the auth-page shell ───────── */
.oauth-consent { max-width: 30rem; }
.oauth-choices { display: flex; flex-direction: column; gap: var(--sp-3); margin: var(--sp-4) 0; }
.oauth-choice {
  display: grid; grid-template-columns: auto 1fr; gap: 2px var(--sp-3);
  align-items: start; padding: var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--r-md);
  cursor: pointer;
}
.oauth-choice input { grid-row: span 2; margin-top: 2px; accent-color: var(--brand); }
.oauth-choice-title { font-weight: 600; color: var(--text); }
.oauth-choice-desc { font-size: var(--text-sm); color: var(--text-2); }
.oauth-actions { display: flex; gap: var(--sp-3); margin-top: var(--sp-4); }

/* ══════════════════════════════════════════════════════════════════════════
   ADR-0136 — native View Transitions (cross-document + HTMX swaps)
   A CSS at-rule only; lives in this same-origin stylesheet, so it satisfies
   style-src 'self' with zero CSP change and needs no JavaScript. Same-origin
   full-page navigations (sidebar links) and HTMX swaps (globalViewTransitions)
   crossfade instead of hard-cutting. Fully progressive — browsers without
   support just navigate normally. Motion is neutralised under reduced-motion.
   ══════════════════════════════════════════════════════════════════════════ */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: vp-vt-out 160ms cubic-bezier(0.4,0,1,1) both; }
::view-transition-new(root) { animation: vp-vt-in 240ms cubic-bezier(0,0,0.2,1) both; }
@keyframes vp-vt-out { to { opacity: 0; } }
@keyframes vp-vt-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* API Keys live filter (ADR-0136 Alpine island). Progressive: inert without JS. */
.vp-os .ak-filter { margin-bottom: var(--sp-3); }
.vp-os .ak-filter-input { max-width: 340px; }

/* ═══════════════════════════════════════════════════════════════════════════
   VayuMail — reading and composing, premium pass.

   The reading pane was a terminal dump: the body rendered in a 13px monospace
   <pre> capped at 65vh with its OWN scrollbar, so in full view you scrolled a box
   inside a box and the text used two thirds of a screen it had all of. Mail is
   long-form reading; it gets a reading column, a real type scale, and a header
   built from the same grammar as the Monetization page.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── The reading column ─────────────────────────────────────────────────── */

.vp-os .vm-msg-body {
  /* Proportional, not monospace: plain-text mail still preserves the author's
     line breaks (white-space: pre-wrap), but nothing about it requires a fixed
     pitch, and 13px mono is why this read like a log file. */
  font-family: var(--font-sans, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
  font-size: 0.95rem;
  line-height: 1.7;
  color: var(--text);
  /* ~72 characters is the comfortable measure for continuous reading. */
  max-width: 72ch;
  margin-top: 1.1rem;
  overflow-wrap: anywhere;
}
.vp-os .vm-msg-body .vm-pre { font-family: inherit; font-size: inherit; line-height: inherit; }

/* Quoted history: present but recessive, and never the first thing you read. */
.vp-os .vm-quote { margin-top: 1.1rem; }
.vp-os .vm-quote > summary {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .3rem .7rem;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  font-size: var(--text-xs);
  color: var(--text-3);
  background: var(--bg-surface-2);
  list-style: none;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.vp-os .vm-quote > summary::-webkit-details-marker { display: none; }
.vp-os .vm-quote > summary:hover { color: var(--text); border-color: var(--border-strong); }
.vp-os .vm-pre--quoted { margin-top: .8rem; }

/* The raw source IS a dump, so it keeps a cap and its own monospace. */
.vp-os .vm-raw {
  max-height: 60vh;
  overflow: auto;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 12px;
  line-height: 1.5;
  background: var(--bg-surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: .75rem;
  margin-top: .6rem;
}

/* Sanitised HTML mail: constrain what a sender's markup can do to the console. */
.vp-os .vm-html { max-width: 72ch; line-height: 1.7; }
.vp-os .vm-html img { max-width: 100%; height: auto; }
.vp-os .vm-html table { max-width: 100%; display: block; overflow-x: auto; }
.vp-os .vm-html blockquote {
  margin: .9rem 0;
  padding-left: .9rem;
  border-left: 2px solid var(--border-strong);
  color: var(--text-2);
}

/* ── Header: identity, then metadata as a grid ──────────────────────────── */

.vp-os .vm-msg-subject {
  font-family: var(--font-head, inherit);
  font-size: 1.35rem;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.015em;
  margin-bottom: .85rem;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .5rem;
}
.vp-os .vm-msg-from-row {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--border);
}
.vp-os .vm-msg-from-meta { min-width: 0; flex: 1; display: grid; gap: 2px; }
.vp-os .vm-msg-fromname { font-size: 0.95rem; }
/* Metadata reads as label/value pairs rather than a run of bold-prefixed lines. */
.vp-os .vm-msg-from-meta > .muted.text-sm {
  display: grid;
  grid-template-columns: 3.2rem 1fr;
  gap: .5rem;
  align-items: baseline;
}
.vp-os .vm-msg-from-meta > .muted.text-sm strong {
  font-weight: 600;
  color: var(--text-3);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* ── Full view: a centred reading column, not an edge-to-edge stretch ───── */

.vp-os #vm-readpane.vm-readpane--full {
  /* Scroll behaviour lives here — this is the one scroll container. */
  padding: 0;
  overscroll-behavior: contain;
}
.vp-os #vm-readpane.vm-readpane--full .vm-reader {
  max-width: 62rem;
  margin: 0 auto;
  padding: 1.6rem 2rem 3rem;
}
/* The action bar stays reachable however far you have read — the same rule the
   member portal's close button needed. */
.vp-os #vm-readpane.vm-readpane--full .vm-actions,
.vp-os #vm-readpane.vm-readpane--full .vm-reader-top {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--bg-surface);
  padding-top: .75rem;
  padding-bottom: .75rem;
  margin-bottom: 0;
}
.vp-os #vm-readpane.vm-readpane--full .vm-reader-top { border-bottom: 1px solid var(--border); }
@media (max-width: 768px) {
  .vp-os #vm-readpane.vm-readpane--full .vm-reader { padding: 1.1rem 1.15rem 2.5rem; }
  .vp-os .vm-msg-subject { font-size: 1.15rem; }
  .vp-os .vm-msg-from-meta > .muted.text-sm { grid-template-columns: 2.6rem 1fr; }
}

/* Actions: one primary, the rest quiet, wrapping instead of overflowing. */
.vp-os .vm-actions { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }

/* ── Attachments ────────────────────────────────────────────────────────── */

.vp-os .vm-attach { margin-top: 1rem; }
.vp-os .vm-attach-list { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .5rem; }
.vp-os .vm-attach-chip {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .45rem .7rem;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-surface-2);
  text-decoration: none;
  color: var(--text);
  font-size: var(--text-sm);
  transition: border-color var(--t-fast), transform var(--t-fast);
}
.vp-os .vm-attach-chip:hover { border-color: var(--accent); transform: translateY(-1px); }
.vp-os .vm-attach-size { color: var(--text-3); font-size: var(--text-xs); }

@media (prefers-reduced-motion: reduce) {
  .vp-os .vm-attach-chip, .vp-os .vm-quote > summary { transition: none; }
  .vp-os .vm-attach-chip:hover { transform: none; }
}

/* ── Composer: a real editor bar ─────────────────────────────────────────────
   The message field was a bare textarea. Formatting now has a toolbar, a word
   count and a preview — and every control writes plain text into the body,
   because that is exactly what gets delivered. */

.vp-os .vm-editor { display: grid; gap: 0; }
.vp-os .vm-ed-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
  margin-bottom: .35rem;
}

.vp-os .vm-ed-bar {
  display: flex;
  align-items: center;
  gap: .15rem;
  flex-wrap: wrap;
  padding: .3rem .35rem;
  border: 1px solid var(--border);
  border-bottom: 0;
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  background: var(--bg-surface-2);
}
.vp-os .vm-ed-btn {
  min-width: 32px;
  height: 32px;
  padding: 0 .5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-2);
  font-size: var(--text-sm);
  line-height: 1;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.vp-os .vm-ed-btn:hover { background: var(--bg-surface); color: var(--text); border-color: var(--border); }
.vp-os .vm-ed-btn:active { transform: translateY(1px); }
.vp-os .vm-ed-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.vp-os .vm-ed-btn[aria-pressed="true"] {
  background: var(--accent-dim);
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
}
.vp-os .vm-ed-btn--wide { min-width: auto; font-weight: 600; }
.vp-os .vm-ed-sep { width: 1px; height: 18px; background: var(--border); margin: 0 .25rem; }
.vp-os .vm-ed-spacer { flex: 1; }

.vp-os .vm-ed-area {
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.9rem;
  line-height: 1.65;
  resize: vertical;
}

/* Preview shares the reading column's type so it previews the READER's
   experience, not the editor's. */
.vp-os .vm-ed-preview {
  border: 1px solid var(--border);
  border-top: 0;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  background: var(--bg-surface);
  padding: 1rem 1.1rem;
  min-height: 18rem;
  max-width: 72ch;
  font-size: 0.95rem;
  line-height: 1.7;
  color: var(--text);
  overflow-wrap: anywhere;
}
.vp-os .vm-pv-h { font-weight: 700; font-size: 1.05rem; margin: .8rem 0 .3rem; }
.vp-os .vm-pv-q {
  border-left: 2px solid var(--border-strong);
  padding-left: .8rem;
  color: var(--text-2);
}
.vp-os .vm-pv-hr { border-top: 1px solid var(--border); margin: .9rem 0; height: 0; }
.vp-os .vm-pv-blank { height: .55rem; }

@media (max-width: 560px) {
  /* Keep every control tappable rather than letting the bar shrink them. */
  .vp-os .vm-ed-btn { min-width: 38px; height: 38px; }
}
@media (prefers-reduced-motion: reduce) {
  .vp-os .vm-ed-btn { transition: none; }
  .vp-os .vm-ed-btn:active { transform: none; }
}

/* ── Install health ──────────────────────────────────────────────────────────
   A pass/fail list with the consequence spelled out, because "installable" is a
   conjunction of a dozen requirements and knowing WHICH one failed is the whole
   value. Failures carry their explanation; passes stay quiet. */

.vp-os .pwa-row {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  padding: .55rem .2rem;
  border-bottom: 1px solid var(--border);
  font-size: var(--text-sm);
}
.vp-os .pwa-row:last-child { border-bottom: 0; }
.vp-os .pwa-mark {
  flex: none;
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: 11px;
  font-weight: 700;
  margin-top: 1px;
}
.vp-os .pwa-row--ok .pwa-mark { background: var(--ok-dim); color: var(--ok); }
.vp-os .pwa-row--bad .pwa-mark { background: var(--danger-dim, rgba(239, 68, 68, .14)); color: var(--danger); }
.vp-os .pwa-row--warn .pwa-mark { background: var(--warn-dim); color: var(--warn); }
.vp-os .pwa-name { font-weight: 600; color: var(--text); }
.vp-os .pwa-row--bad .pwa-name { color: var(--danger); }
.vp-os .pwa-detail {
  font-size: var(--text-xs);
  color: var(--text-3);
  margin-top: 2px;
  overflow-wrap: anywhere;
}
/* The consequence, shown only where something is wrong. */
.vp-os .pwa-why {
  font-size: var(--text-xs);
  color: var(--text-2);
  margin-top: .3rem;
  padding-left: .6rem;
  border-left: 2px solid var(--border-strong);
  line-height: 1.5;
}
.vp-os .pwa-browser { margin-top: 1.2rem; }
.vp-os .pwa-probe-rows { min-height: 2rem; }

/* ── VayuMail account recovery (ADR-0144) ─────────────────────────────────── */
.vp-os .rec-list { margin: .5rem 0 0; padding-left: 1.2rem; display: grid; gap: .25rem; }
.vp-os .rec-list code { font-size: .82rem; }
.vp-os .rec-status { margin-top: .6rem; }
/* The codes are shown exactly once, so the block is deliberately loud — this is
   the moment the operator has to act, and a quiet panel is one people scroll
   past and then cannot get back. */
.vp-os .rec-codes {
  margin-top: .9rem;
  padding: 1rem;
  border: 1px solid var(--warn, #f59e0b);
  border-radius: 12px;
  background: color-mix(in srgb, var(--warn, #f59e0b) 8%, transparent);
}
.vp-os .rec-codes__warn { font-size: .85rem; font-weight: 600; margin-bottom: .75rem; }
.vp-os .rec-codes__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
  gap: .5rem;
  margin-bottom: .85rem;
}
.vp-os .rec-codes__code {
  display: block;
  padding: .45rem .6rem;
  border-radius: 8px;
  border: 1px solid var(--border, #2a2a2a);
  background: var(--surface, rgba(127, 127, 127, .08));
  font-family: var(--font-mono);
  font-size: .9rem;
  letter-spacing: .04em;
  text-align: center;
  /* Selectable as a block so "copy all" is not the only route. */
  user-select: all;
}
.vp-os .rec-codes__actions { display: flex; flex-wrap: wrap; gap: .5rem; }

/* ---------------------------------------------------------------------------
   Editor → Write with AI panel.

   The panel borrows the Monetization grammar (.mon-acc summaries with icon,
   subtitle and status chip) so the busiest surface in the product does not have
   its own dialect. The controls sit in a two-column grid that collapses to one
   on a narrow panel.
   --------------------------------------------------------------------------- */
/* The panel body is a flex COLUMN, so a <details> is a flex item and shrinks
   below its natural height whenever the panel is shorter than its content — and
   .mon-acc sets overflow:hidden, so the shrunk box silently clipped its own
   fields (measured: a 261px body inside a 121px box on a 700px-tall window, with
   "Language" and "Creativity" cut off entirely). flex:none makes each section
   keep its content height; the panel already scrolls. */
.ai-panel .mon-acc { margin: 0 0 .7rem; flex: none; }
/* Same reasoning for the prompt field, the status line and the button row. */
.ai-panel > .pm-field,
.ai-panel > .ai-status,
.ai-panel > .pm-row { flex: none; }
.ai-panel .mon-acc__body { padding: .85rem .95rem 1rem; }

.ai-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: .3rem .8rem;
}
.ai-grid .pm-field { margin-bottom: .55rem; }
/* Free-text and range inputs read better across the full width. */
.ai-grid .pm-field:has(> input[type="range"]) { grid-column: 1 / -1; }

.pm-help {
  margin: .35rem 0 0;
  font-size: .76rem;
  line-height: 1.45;
  color: var(--os-muted, #94a3b8);
}

/* The status line is the only place a provider failure is explained, so it has
   to look like a message rather than the neutral hint it replaces. */
.ai-status {
  margin: .2rem 0 .8rem;
  padding: .55rem .7rem;
  border-radius: 9px;
  font-size: .82rem;
  line-height: 1.5;
  border: 1px solid transparent;
  color: var(--os-muted, #94a3b8);
  background: rgba(127, 127, 127, .08);
}
.ai-status--err {
  color: #fca5a5;
  background: rgba(239, 68, 68, .1);
  border-color: rgba(239, 68, 68, .32);
}
.ai-status--busy {
  color: #93c5fd;
  background: rgba(59, 130, 246, .1);
  border-color: rgba(59, 130, 246, .3);
}
@media (prefers-color-scheme: light) {
  .ai-status--err { color: #b91c1c; }
  .ai-status--busy { color: #1d4ed8; }
}
:root[data-theme="light"] .ai-status--err { color: #b91c1c; }
:root[data-theme="light"] .ai-status--busy { color: #1d4ed8; }

/* A range input inherits almost nothing from .pm-input, so give it a sane size. */
.ai-panel input[type="range"] {
  width: 100%;
  padding: 0;
  height: 1.6rem;
  background: transparent;
  border: 0;
  accent-color: var(--os-accent, #6366f1);
}

/* ── Per-site tool tiles (ADR-0154) ──────────────────────────────────────────
   These render inside .mon-stack, next to the accordions, and must read as
   members of the same family: same frame, same icon chip, same title/subtitle
   rhythm. The difference is that a tool is a LINK, not a disclosure, so it gets
   an affordance the accordion does not — a chevron that leans on hover.

   Written because the markup shipped without it. Three classes were emitted for
   two releases with no rule matching them, so every tile collapsed to inline
   text — title and description run together, underlined on hover by the default
   anchor style. It passed every test: the link was present, the page was
   CSP-safe, and nothing anywhere asserted it would look like anything. */
.vp-os .scoped-tool {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-surface);
  text-decoration: none; color: inherit;
  transition: border-color var(--t-fast), background var(--t-fast), box-shadow var(--t-fast);
}
.vp-os a.scoped-tool:hover,
.vp-os a.scoped-tool:focus-visible {
  text-decoration: none;               /* the underline was the whole complaint */
  border-color: var(--border-strong);
  background: var(--bg-surface-2);
  box-shadow: var(--sh-sm);
}
.vp-os a.scoped-tool:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The inner grammar is .mon-acc__ic / __head / __title / __sub / .mon-chip —
   the accordion summary's, reused rather than re-declared. This band and the
   administration band sit on the same page one under the other, and while they
   were two components with matching-by-hand rules they drifted: the tools had
   no chip, longer subtitles and a different title weight, so the page read as
   two designs stacked. There is one set of rules now, and no way to drift. */
/* A link leans; a disclosure rotates. Different affordance, same family. */
.vp-os .scoped-tool::after {
  content: "›"; flex: none; color: var(--text-3); font-size: 1.15rem; line-height: 1;
  transition: transform var(--t-fast), color var(--t-fast);
}
.vp-os a.scoped-tool:hover::after { transform: translateX(3px); color: var(--text); }
/* A tool that is not scoped yet is not a link and must not pretend to be. */
.vp-os .scoped-tool--soon { opacity: 0.72; cursor: default; }
.vp-os .scoped-tool--soon::after { content: none; }
@media (prefers-reduced-motion: reduce) {
  .vp-os a.scoped-tool:hover::after { transform: none; }
}
@media (max-width: 640px) {
  .vp-os .scoped-tool { align-items: flex-start; }
  /* .mon-acc__sub truncates with an ellipsis, which is right on a wide row and
     wrong on a phone where the subtitle is most of what there is to read. */
  .vp-os .scoped-tool .mon-acc__sub { white-space: normal; overflow: visible; }
}

/* ── form-grid / field--check ────────────────────────────────────────────────
   `.form-grid` is used on nearly every VayuOS card that has more than one input
   and was defined NOWHERE — not here, not in admin.css. Every one of those
   forms has been rendering as a plain stack while its class name promised a
   grid. Found by the gate that was written for the tool tiles, which is the
   point of writing gates rather than fixing the one instance in front of you.

   `.field--check` is a checkbox or radio row: the control sits beside its label
   rather than above it, so a stack of options reads as a list of choices. */
.vp-os .form-grid {
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  align-items: start; margin-bottom: var(--sp-4);
}
/* Anything that wants the full width of the grid says so. A textarea in a
   240px column is not a place anyone writes a paragraph. */
.vp-os .form-grid > .field:has(textarea) { grid-column: 1 / -1; }
.vp-os .field--check {
  display: grid; grid-template-columns: auto 1fr; align-items: center;
  gap: var(--sp-1) var(--sp-3); grid-column: 1 / -1;
}
.vp-os .field--check > input { grid-row: 1; justify-self: start; margin: 0; }
.vp-os .field--check > .field-label { grid-row: 1; margin: 0; cursor: pointer; }
.vp-os .field--check > .field-hint { grid-column: 2; grid-row: 2; }
@media (max-width: 640px) {
  .vp-os .form-grid { grid-template-columns: 1fr; gap: var(--sp-3); }
}

/* The provisioning log, shown verbatim on the site console. Scrolls in its own
   box so a long log never widens the page — the rule every wide block here
   follows. */
.vp-os .vm-logbox {
  max-height: 320px; overflow: auto; margin: 0;
  padding: var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg-surface-2); color: var(--text-2);
  white-space: pre; tab-size: 2;
}

/* ── Classes that were emitted with no rule behind them ──────────────────────
   Each element below carried NO styled class at all, so it rendered as bare
   inline text: a status pill as a run-on word, a form input as an unstyled
   browser box, a warning banner as a plain paragraph. This is the `scoped-tool`
   defect — markup shipped with nothing matching it — found twenty-one more times
   by a source-wide sweep after the per-page gate was fixed to stop letting a
   longer class name answer for a shorter one.

   The distinction that decided what got a rule: an element that also carries a
   styled base class (a `btn`, a `card`, a `mon-acc__sum`) is already styled, and
   its extra token is a JavaScript hook rather than a missing rule. Those are
   left alone. Only elements with nothing at all are given a look here. */

/* Status pills on the site list. Same grammar as .badge, which they should
   probably have used — kept as their own class because the markup is shipped
   and renaming it is a separate change from making it visible. */
.vp-os .pill {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: 0.2em 0.6em; border-radius: var(--r-full);
  font-size: var(--text-xs); font-weight: 600; white-space: nowrap;
  border: 1px solid var(--border); background: var(--bg-surface-2); color: var(--text-2);
}
.vp-os .pill--ok     { background: var(--ok-dim);   color: var(--ok);   border-color: transparent; }
.vp-os .pill--accent { background: var(--brand-dim); color: var(--brand); border-color: transparent; }
.vp-os .pill--muted  { color: var(--text-3); }

/* Trend indicator beside a security figure. Direction is carried by colour AND
   by the glyph the markup already supplies, so it survives a colour-blind
   reader and a monochrome print. */
.vp-os .trend { font-size: var(--text-xs); font-weight: 650; white-space: nowrap; color: var(--text-3); }
.vp-os .trend--up   { color: var(--ok); }
.vp-os .trend--down { color: var(--danger); }

/* The line under a stat tile's number. Muted and small: it qualifies the figure
   above it and must never compete with it. */
.vp-os .stat-card__sub { margin-top: 2px; font-size: var(--text-xs); color: var(--text-3); line-height: 1.4; }

/* Warning notice. This one carried the security-update banner and the favicon
   upload rules, both of which had been rendering as unstyled paragraphs. */
.vp-os .warn-box {
  border: 1px solid var(--warn); background: var(--warn-dim); color: var(--text);
  border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
  font-size: var(--text-sm); line-height: 1.55; margin-bottom: var(--sp-4);
}

/* A row with its ends pushed apart. Replaces an inline style attribute that was
   doing this by hand — which is also why the class had no rule: the styling had
   been put somewhere assertCSPSafe forbids. */
.vp-os .flex-between { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }

/* Preformatted output: a restore command, a manifest, a key. Scrolls inside its
   own box rather than widening the page. */
.vp-os .code-block {
  font-family: var(--font-mono); font-size: var(--text-xs); line-height: 1.5;
  background: var(--bg-surface-2); border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: var(--sp-3); overflow-x: auto; white-space: pre; color: var(--text-2);
}

/* A list that is structure rather than prose — no bullets, no indent. */
.vp-os .reset-list { list-style: none; margin: 0; padding: 0; }

/* Inline result of an SEO or IndexNow action. */
.vp-os .seo-status {
  font-size: var(--text-sm); color: var(--text-2);
  border-left: 2px solid var(--border-strong); padding-left: var(--sp-3);
}

/* A text input that had been rendering as the raw browser control on a page
   sitting beside inputs that did not. Matched to the console's own field look. */
.vp-os .field-input {
  width: 100%; padding: var(--sp-2) var(--sp-3);
  background: var(--bg-surface-2); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  font-size: var(--text-sm); font-family: inherit;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.vp-os .field-input:focus-visible {
  outline: none; border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-dim);
}

/* The add-an-ad-slot form. Also replaces an inline style attribute. */
.vp-os .ads-form { display: grid; gap: var(--sp-3); max-width: 42rem; }

/* Text beside the site mark in Theme Studio. */
.vp-os .cz-logo__meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

/* The anonymous VayuTalk code — an identity to read aloud and copy, so it is
   given the weight of one rather than of a sentence. */
.vp-os .vtalk-anon {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-surface); padding: var(--sp-4); margin-bottom: var(--sp-4);
}

/* Live intelligence view container. */
.vp-os .vm-liveview { display: block; }

/* Subject line in a mail list: the primary thing to click on that row. */
.vp-os .vm-subj-link { color: var(--text); text-decoration: none; font-weight: 600; }
.vp-os .vm-subj-link:hover { color: var(--brand); text-decoration: underline; }

/* The summary of a collapsible group in the editor's block picker. */
.vp-os .pm-group-title {
  cursor: pointer; list-style: none; padding: var(--sp-2) var(--sp-3);
  font-size: var(--text-xs); font-weight: 650; color: var(--text-2);
  text-transform: uppercase; letter-spacing: 0.04em;
}
.vp-os .pm-group-title::-webkit-details-marker { display: none; }
.vp-os .pm-group-title:hover { color: var(--text); background: var(--bg-surface-2); }

/* Permission checkboxes in the API-key console. Sized so a row of them is
   clickable rather than pixel-hunting. */
.vp-os .ak-perm,
.vp-os .ak-perm-all { width: 15px; height: 15px; accent-color: var(--brand); cursor: pointer; flex: none; }
