/**
 * CubeWP Console — component kit (U1).
 *
 * The shared visual language every phase builds with. Consumes tokens.css
 * exclusively — a raw hex here is a bug. Components are prefixed cw- and
 * coexist with legacy classes until each surface is rebuilt (U2–U7); the
 * legacy contrast/focus overrides at the bottom fix the audit's a11y
 * findings platform-wide without waiting for those rebuilds.
 */

/* ══ Header bar (shell) ═════════════════════════════════════════════════ */

.cw-header {
  height: var(--cw-header-h);
  display: flex; align-items: center; gap: var(--cw-s4);
  padding: 0 var(--cw-s6);
  background: var(--cw-surface);
  border-bottom: 1px solid var(--cw-border);
  position: sticky; top: 0; z-index: 800;
}
.cw-crumbs {
  display: flex; align-items: center; gap: var(--cw-s2);
  font: var(--cw-small); color: var(--cw-text-soft);
  min-width: 0; flex: 1;
}
.cw-crumbs .cw-crumb-sep { color: var(--cw-border-strong); }
.cw-crumbs .cw-crumb-current { color: var(--cw-ink); font-weight: 600; }
.cw-header-actions { display: flex; align-items: center; gap: var(--cw-s3); }

/* Bell relocated into the header (was position:fixed) */
/* The bell was originally a FLOATING control: dashboard.css still declares
   `position: fixed; top: 14px; right: 18px`. Two things follow, and both bite.

   1. It must be `relative`, not `static`. .notif-badge is absolutely
      positioned at top/right -4px; with a static parent it resolves against
      the VIEWPORT instead and pins itself to the page's top-right corner,
      which also forces a horizontal scrollbar.
   2. The inherited top/right MUST be cleared. `static` merely made them inert
      — switching to `relative` reactivates them as offsets and shunts the bell
      down 14px and left 18px. That is why "just set relative" looks broken. */
.cw-header .notif-bell {
  position: relative;
  top: auto; right: auto; bottom: auto; left: auto;
  width: 36px; height: 36px; box-shadow: none;
  border: 1px solid var(--cw-border);
}
.cw-header .notif-bell:hover { border-color: var(--cw-accent-border); }
/* The badge's ring is a hardcoded #fff in dashboard.css — a white halo on a
   dark header. Match whatever the bell is actually sitting on. */
.cw-header .notif-badge { border-color: var(--cw-surface); }

/* Account menu */
.cw-account { position: relative; }
.cw-account-btn {
  display: inline-flex; align-items: center; gap: var(--cw-s2);
  height: 36px; padding: 0 var(--cw-s3);
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-full); cursor: pointer;
  font: var(--cw-small); color: var(--cw-text); font-family: inherit;
  transition: border-color var(--cw-t-micro);
}
.cw-account-btn:hover { border-color: var(--cw-border-strong); }
.cw-avatar {
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--cw-accent); color: var(--cw-accent-ink);
  display: inline-flex; align-items: center; justify-content: center;
  font: 600 12px/1 var(--cw-font); text-transform: uppercase;
}

/* ══ Buttons ════════════════════════════════════════════════════════════ */

.cw-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--cw-s2);
  font: 600 14px/1 var(--cw-font); border-radius: var(--cw-r-md);
  height: 38px; padding: 0 var(--cw-s4); cursor: pointer; white-space: nowrap;
  border: 1px solid transparent;
  /* ANCHORS TOO. .cw-btn is used on <a> as often as <button> — Visit, Open
     site, WP Admin, the agency cross-link — and without this the browser kept
     its default underline, so half the buttons in three consoles rendered
     underlined and looked unfinished. */
  text-decoration: none;
  transition: background var(--cw-t-micro), border-color var(--cw-t-micro), color var(--cw-t-micro);
}
.cw-btn:disabled { opacity: .55; cursor: not-allowed; }
.cw-btn-sm { height: 32px; padding: 0 var(--cw-s3); font-size: 13px; }

.cw-btn-primary   { background: var(--cw-accent); color: var(--cw-accent-ink); }
.cw-btn-primary:hover:not(:disabled) { background: var(--cw-accent-hover); }
.cw-btn-secondary { background: var(--cw-surface); color: var(--cw-text); border-color: var(--cw-border-strong); }
.cw-btn-secondary:hover:not(:disabled) { border-color: var(--cw-text-faint); background: var(--cw-surface-2); }
.cw-btn-ghost     { background: none; color: var(--cw-text-soft); }
.cw-btn-ghost:hover:not(:disabled) { background: var(--cw-surface-2); color: var(--cw-ink); }
.cw-btn-danger    { background: var(--cw-danger); color: #fff; }
.cw-btn-danger:hover:not(:disabled) { background: #B91C1C; }
.cw-btn-icon      { width: 36px; padding: 0; }

/* ══ Status badges — the Health language (§16.5) ════════════════════════ */

.cw-badge {
  display: inline-flex; align-items: center; gap: 6px;
  font: var(--cw-micro); font-weight: 600;
  padding: 3px 10px; border-radius: var(--cw-r-full);
  border: 1px solid var(--cw-border); background: var(--cw-surface-2); color: var(--cw-text-soft);
}
.cw-badge .cw-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.cw-badge-ok     { background: var(--cw-ok-bg);     border-color: var(--cw-ok-border);     color: var(--cw-ok); }
.cw-badge-warn   { background: var(--cw-warn-bg);   border-color: var(--cw-warn-border);   color: var(--cw-warn); }
.cw-badge-danger { background: var(--cw-danger-bg); border-color: var(--cw-danger-border); color: var(--cw-danger); }
.cw-badge-info   { background: var(--cw-info-bg);   border-color: var(--cw-info-border);   color: var(--cw-info); }
/* Breathing dot — in-progress operations ONLY. Calm, 2s, reduced-motion aware. */
.cw-badge-pulse .cw-dot { animation: cw-breathe 2s ease-in-out infinite; }
@keyframes cw-breathe { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

/* ══ Cards ══════════════════════════════════════════════════════════════ */

.cw-card {
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-lg); padding: var(--cw-s5);
  transition: box-shadow var(--cw-t-micro), border-color var(--cw-t-micro);
}
.cw-card-hover:hover { box-shadow: var(--cw-e1); border-color: var(--cw-border-strong); }
.cw-card-title { font: var(--cw-heading); color: var(--cw-ink); margin: 0 0 var(--cw-s3); }

.cw-stat { display: flex; flex-direction: column; gap: var(--cw-s1); }
/* The number must dominate its label — it's the reason the card exists. */
.cw-stat-value {
  font: 700 32px/38px var(--cw-font); color: var(--cw-ink);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.cw-stat-label {
  font: 600 11px/16px var(--cw-font); color: var(--cw-text-soft);
  text-transform: uppercase; letter-spacing: .07em;
}
.cw-stat-delta { font: var(--cw-micro); }
.cw-stat-delta.up { color: var(--cw-ok); }
.cw-stat-delta.down { color: var(--cw-danger); }

/* ══ Skeletons — replace every "Loading…" string ════════════════════════ */

.cw-skel {
  position: relative; overflow: hidden;
  background: var(--cw-surface-2); border-radius: var(--cw-r-sm);
  min-height: 14px;
}
/* Shimmer animates ONLY transform — no layout, no paint of the parent, and it
   gets its own compositor layer. `will-change` is deliberately absent: these
   render in their dozens and promoting every one costs more than it saves. */
.cw-skel::after {
  content: ''; position: absolute; inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .55), transparent);
  animation: cw-shimmer 1.4s cubic-bezier(.4, 0, .2, 1) infinite;
}
@keyframes cw-shimmer { to { transform: translateX(100%); } }
/* Dark mode: a white sweep over a dark plate reads as a flash. */
[data-theme="dark"] .cw-skel::after {
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .07), transparent);
}
/* tokens.css already neutralises animation globally under prefers-reduced-
   motion; this makes the fallback deliberate rather than incidental — a calm
   static plate instead of a frozen mid-sweep gradient. */
@media (prefers-reduced-motion: reduce) {
  .cw-skel::after { display: none; }
  .cw-skel { background: var(--cw-surface-2); }
}

.cw-skel-text  { height: 14px; }
.cw-skel-title { height: 22px; width: 40%; }
.cw-skel-block { height: 96px; border-radius: var(--cw-r-lg); }

/* ── Skeleton component set ─────────────────────────────────
   The vocabulary every page composes its own layout from. Sizes deliberately
   mirror the real components (see the paired rule noted on each) so swapping
   skeleton for content shifts nothing. */
.cw-skel-line   { height: 12px; border-radius: var(--cw-r-sm); }
.cw-skel-head   { height: 30px; width: 260px; border-radius: var(--cw-r-sm); }  /* --cw-display */
.cw-skel-badge  { height: 20px; width: 76px; border-radius: var(--cw-r-full); }
.cw-skel-btn    { height: 36px; width: 116px; border-radius: var(--cw-r-md); }
.cw-skel-input  { height: 38px; width: 100%; border-radius: var(--cw-r-md); }
.cw-skel-avatar { height: 34px; width: 34px; border-radius: var(--cw-r-md); flex: none; }
.cw-skel-chip   { height: 32px; width: 84px; border-radius: var(--cw-r-full); flex: none; }
.cw-skel-chart  { height: 140px; border-radius: var(--cw-r-md); }

.cw-skel-card {
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-lg); padding: var(--cw-s5);
  display: flex; flex-direction: column; gap: var(--cw-s3);
}
.cw-skel-stack { display: flex; flex-direction: column; gap: var(--cw-s3); }
.cw-skel-row   { display: flex; align-items: center; gap: var(--cw-s3); }
.cw-skel-grid  { display: grid; gap: var(--cw-s4); }
.cw-skel-grid-3 { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.cw-skel-grid-cards { grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); gap: var(--cw-s5); }

/* Table skeleton — same 5-column rhythm as .bl-inv-table / .cw-table. */
.cw-skel-table { background: var(--cw-surface); border: 1px solid var(--cw-border); border-radius: var(--cw-r-lg); overflow: hidden; }
.cw-skel-tr {
  display: grid; grid-template-columns: 2fr 1fr 1fr 90px; gap: var(--cw-s4);
  align-items: center; padding: var(--cw-s4) var(--cw-s5);
  border-bottom: 1px solid var(--cw-border);
}
.cw-skel-tr:last-child { border-bottom: 0; }
.cw-skel-th { background: var(--cw-surface-2); }

/* First-frame placeholder for the two template grids. It sits in static markup
   so it paints before JS runs; JS then swaps in the full card-grid skeleton.
   Shaped like one row of cards rather than a bar, so the swap doesn't jump. */
.cs-demo-loading-skel {
  min-height: 210px; border-radius: var(--cw-r-lg);
  background: var(--cw-surface-2);
  position: relative; overflow: hidden;
}
.cs-demo-loading-skel::after {
  content: ''; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .55), transparent);
  animation: cw-shimmer 1.4s cubic-bezier(.4, 0, .2, 1) infinite;
}
[data-theme="dark"] .cs-demo-loading-skel::after {
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .07), transparent);
}
@media (prefers-reduced-motion: reduce) { .cs-demo-loading-skel::after { display: none; } }

/* ── Boot chrome (K2) ───────────────────────────────────────
   Show the real sidebar and header while the first request is in flight, so
   the loading state has the app's actual two-column geometry instead of one
   full-bleed skeleton. Beats `.hidden`'s !important by specificity + order. */
html.cw-booting #dash-sidebar.hidden { display: flex !important; }
html.cw-booting #cw-header.hidden    { display: flex !important; }

/* Nothing in the chrome is clickable yet — the panels behind it have no data,
   so a click would navigate to a blank tab. It reads as present, not ready. */
html.cw-booting #dash-sidenav,
html.cw-booting .cw-header-actions,
html.cw-booting .dash-sidebar-footer { pointer-events: none; }
html.cw-booting #dash-sidenav { opacity: .55; }
/* The two genuinely data-dependent bits of chrome get placeholders rather than
   showing empty. */
html.cw-booting #nav-email {
  display: block; width: 130px; height: 12px; border-radius: var(--cw-r-sm);
  background: var(--cw-surface-2); color: transparent; overflow: hidden;
}
html.cw-booting .cw-avatar { color: transparent; background: var(--cw-surface-2); }

/* Boot skeleton container — overrides .dash-loading's centred spinner box so
   the skeleton fills the content column exactly like the real page does. */
.dash-skel {
  display: block !important; text-align: left !important;
  padding: 0 !important; min-height: 0 !important;
}
/* Scoped to the SKELETON's head, never to .ov-head itself — the real one
   gets its 6px from the h1's own margin, and adding a gap there would push
   the loaded page 6px further down than the placeholder it replaced. Flex
   also stops the two bars' margins collapsing into each other, which is why
   the block measured 58px against the real 70. */
.cw-skel-ovhead { display: flex; flex-direction: column; gap: 6px; }
/* The fleet pills are drawn for every account that has a site, so the boot
   skeleton shows the row too. (An account with NO sites gets a different
   screen entirely — firstRun() — which no single skeleton can also match.) */
.cw-skel-ovpill { height: 34px; width: 104px; border-radius: var(--cw-r-full); }
.cw-skel-ovrow { height: 20px; border-radius: var(--cw-r-sm); }
/* 3px above and below centres a 34px bar in the greeting’s 40px line box.
   The 6px that follows is the wrapper’s gap, not a margin here — leaving both
   in made the head 76px against the real 70. */
.cw-skel-ovg { height: 34px; width: 100%; max-width: 300px;
               border-radius: var(--cw-r-sm); margin: 3px 0; }
.cw-skel-ovs { height: 15px; width: 100%; max-width: 220px;
               border-radius: var(--cw-r-sm); margin: 4px 0 5px; }
.cw-skel-ovl { height: 16px; border-radius: var(--cw-r-sm); }
.cw-skel-ovv { height: 38px; width: 92px; border-radius: var(--cw-r-sm); }
.cw-skel-ovd { height: 16px; border-radius: var(--cw-r-sm); }
.cw-skel-ovt { height: 16px; width: 118px; border-radius: var(--cw-r-sm);
               margin-bottom: var(--cw-s3); }

/* ── Reveal: skeleton → content ─────────────────────────────
   opacity + transform only. Applied by CW.reveal() to whatever just replaced
   a skeleton, so content arrives instead of snapping in. */
.cw-reveal { animation: cw-reveal 220ms cubic-bezier(.2, .8, .3, 1) both; }
@keyframes cw-reveal {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .cw-reveal { animation: none; }
}

/* ══ Toast queue (replaces the single #toast element for new code) ══════ */

.cw-toasts {
  position: fixed; right: var(--cw-s5); bottom: var(--cw-s5); z-index: 1200;
  display: flex; flex-direction: column; gap: var(--cw-s2);
  pointer-events: none;
}
.cw-toast {
  pointer-events: auto;
  display: flex; align-items: center; gap: var(--cw-s3);
  min-width: 260px; max-width: 380px;
  background: var(--cw-ink); color: #fff;
  border-radius: var(--cw-r-md); padding: var(--cw-s3) var(--cw-s4);
  font: var(--cw-small); box-shadow: var(--cw-e2);
  border-left: 3px solid var(--cw-accent);
  animation: cw-toast-in var(--cw-t-std) both;
}
.cw-toast-ok     { border-left-color: var(--cw-ok); }
.cw-toast-danger { border-left-color: var(--cw-danger); }
.cw-toast-warn   { border-left-color: var(--cw-warn); }
.cw-toast-action {
  margin-left: auto; background: none; border: 0; cursor: pointer;
  color: var(--cw-chart-3); font: 600 13px/1 var(--cw-font);
}
.cw-toast.cw-toast-leaving { animation: cw-toast-out var(--cw-t-std) both; }
@keyframes cw-toast-in  { from { opacity: 0; transform: translateY(8px); } }
@keyframes cw-toast-out { to   { opacity: 0; transform: translateY(8px); } }

/* ══ Empty states ═══════════════════════════════════════════════════════ */

.cw-empty {
  display: flex; flex-direction: column; align-items: center; gap: var(--cw-s3);
  padding: var(--cw-s8) var(--cw-s5); text-align: center;
}
.cw-empty svg { color: var(--cw-border-strong); }
.cw-empty-title { font: var(--cw-heading); color: var(--cw-ink); }
.cw-empty-text  { font: var(--cw-small); color: var(--cw-text-soft); max-width: 340px; }

/* ══ Table ══════════════════════════════════════════════════════════════ */

.cw-table { width: 100%; border-collapse: collapse; font: var(--cw-small); }
.cw-table th {
  text-align: left; font: var(--cw-micro); color: var(--cw-text-soft);
  text-transform: uppercase; letter-spacing: .04em;
  padding: var(--cw-s2) var(--cw-s3); border-bottom: 1px solid var(--cw-border);
}
.cw-table td { padding: var(--cw-s3); border-bottom: 1px solid var(--cw-surface-2); color: var(--cw-text); }
.cw-table tr:hover td { background: var(--cw-bg); }
.cw-table .cw-num { font-variant-numeric: tabular-nums; text-align: right; }

/* ══ Forms ══════════════════════════════════════════════════════════════ */

.cw-field { display: flex; flex-direction: column; gap: var(--cw-s1); margin-bottom: var(--cw-s4); }
.cw-label { font: 600 13px/18px var(--cw-font); color: var(--cw-text); }
.cw-help  { font: var(--cw-micro); color: var(--cw-text-soft); }
.cw-input, .cw-select, .cw-textarea {
  font: var(--cw-body); font-family: inherit; color: var(--cw-ink);
  background: var(--cw-surface); border: 1px solid var(--cw-border-strong);
  border-radius: var(--cw-r-sm); padding: 9px var(--cw-s3); width: 100%; box-sizing: border-box;
  transition: border-color var(--cw-t-micro), box-shadow var(--cw-t-micro);
}
.cw-input:focus, .cw-select:focus, .cw-textarea:focus {
  outline: none; border-color: var(--cw-accent);
  box-shadow: 0 0 0 3px var(--cw-accent-subtle);
}
.cw-field-error .cw-input { border-color: var(--cw-danger); }
.cw-error-text { font: var(--cw-micro); color: var(--cw-danger); }

.cw-copy {
  display: flex; align-items: center; gap: var(--cw-s2);
  background: var(--cw-surface-2); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-sm); padding: 8px var(--cw-s3);
  font: 500 13px/20px var(--cw-font-mono); color: var(--cw-ink);
}
.cw-copy button {
  margin-left: auto; background: none; border: 0; cursor: pointer;
  color: var(--cw-accent); display: inline-flex; padding: 2px;
}

/* ══ Side panel (informational) + Dialog (destructive) — §16.1.2 ════════ */

.cw-scrim {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(22, 22, 31, .32);
  opacity: 0; transition: opacity var(--cw-t-std);
}
.cw-scrim.open { opacity: 1; }

.cw-panel {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 1001;
  width: min(480px, 100vw); background: var(--cw-surface);
  box-shadow: var(--cw-e2); display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform var(--cw-t-panel);
}
.cw-panel.cw-panel-wide { width: min(640px, 100vw); }
.cw-panel.open { transform: translateX(0); }
.cw-panel-head {
  display: flex; align-items: center; gap: var(--cw-s3);
  padding: var(--cw-s4) var(--cw-s5); border-bottom: 1px solid var(--cw-border);
}
.cw-panel-title { font: var(--cw-title); color: var(--cw-ink); flex: 1; min-width: 0; }
.cw-panel-context { font: var(--cw-micro); color: var(--cw-text-soft); }
.cw-panel-body { flex: 1; overflow-y: auto; padding: var(--cw-s5); }
.cw-panel-foot { padding: var(--cw-s4) var(--cw-s5); border-top: 1px solid var(--cw-border); display: flex; gap: var(--cw-s3); justify-content: flex-end; }
.cw-panel-close {
  background: none; border: 0; cursor: pointer; color: var(--cw-text-faint);
  font-size: 20px; line-height: 1; padding: var(--cw-s1);
}
.cw-panel-close:hover { color: var(--cw-ink); }

.cw-dialog {
  position: fixed; top: 50%; left: 50%; z-index: 1001;
  transform: translate(-50%, -46%) scale(.98); opacity: 0;
  width: min(440px, calc(100vw - 32px));
  background: var(--cw-surface); border-radius: var(--cw-r-lg);
  box-shadow: var(--cw-e2); padding: var(--cw-s6);
  transition: transform var(--cw-t-std), opacity var(--cw-t-std);
}
.cw-dialog.open { transform: translate(-50%, -50%) scale(1); opacity: 1; }
.cw-dialog-danger { border-top: 3px solid var(--cw-danger); }

/* ══ Dropdown menu (keyboard-navigable — replaces kebab pattern) ════════ */

/* FIXED, not absolute. CW.menu() positions this from
   anchor.getBoundingClientRect() and clamps against window.innerHeight /
   innerWidth — both viewport coordinates. Under `absolute` those resolve
   against the DOCUMENT instead, so the menu was drawn exactly scrollY pixels
   too high: on a scrolled Sites page it floated over the middle of the screen,
   detached from the button that opened it. The JS was always written for
   fixed; the CSS disagreed. */
.cw-menu {
  position: fixed; z-index: 900; min-width: 200px;
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-md); box-shadow: var(--cw-e2); padding: var(--cw-s1);
}
.cw-menu [role="menuitem"] {
  display: flex; align-items: center; gap: var(--cw-s2); width: 100%;
  font: var(--cw-small); color: var(--cw-text); font-family: inherit;
  background: none; border: 0; border-radius: var(--cw-r-sm);
  padding: 8px var(--cw-s3); cursor: pointer; text-align: left;
}
.cw-menu [role="menuitem"]:hover,
.cw-menu [role="menuitem"]:focus-visible { background: var(--cw-surface-2); color: var(--cw-ink); }
.cw-menu [role="menuitem"].cw-menu-danger { color: var(--cw-danger); }
.cw-menu-sep { height: 1px; background: var(--cw-border); margin: var(--cw-s1) 0; }

/* ══ Tabs (primary + secondary — §16.3) ═════════════════════════════════ */

.cw-tabs { display: flex; gap: var(--cw-s1); border-bottom: 1px solid var(--cw-border); }
.cw-tab {
  font: 600 14px/20px var(--cw-font); color: var(--cw-text-soft);
  background: none; border: 0; border-bottom: 2px solid transparent;
  padding: var(--cw-s3) var(--cw-s4); cursor: pointer; font-family: inherit;
  transition: color var(--cw-t-micro);
}
.cw-tab:hover { color: var(--cw-ink); }
.cw-tab[aria-selected="true"] { color: var(--cw-accent); border-bottom-color: var(--cw-accent); }
.cw-subtabs { display: flex; gap: var(--cw-s2); flex-wrap: wrap; }
.cw-subtab {
  font: 600 13px/18px var(--cw-font); color: var(--cw-text-soft);
  background: none; border: 1px solid transparent; border-radius: var(--cw-r-full);
  padding: 6px var(--cw-s4); cursor: pointer; font-family: inherit;
}
.cw-subtab:hover { background: var(--cw-surface-2); color: var(--cw-ink); }
.cw-subtab[aria-selected="true"] { background: var(--cw-accent-subtle); border-color: var(--cw-accent-border); color: var(--cw-accent); }

/* ══ Banner ═════════════════════════════════════════════════════════════ */

.cw-banner {
  display: flex; align-items: flex-start; gap: var(--cw-s3);
  border-radius: var(--cw-r-md); padding: var(--cw-s3) var(--cw-s4);
  font: var(--cw-small); border: 1px solid var(--cw-border); background: var(--cw-surface-2);
}
.cw-banner-warn   { background: var(--cw-warn-bg);   border-color: var(--cw-warn-border); }
.cw-banner-danger { background: var(--cw-danger-bg); border-color: var(--cw-danger-border); }
.cw-banner-info   { background: var(--cw-info-bg);   border-color: var(--cw-info-border); }

/* ══ Overview — the daily screen (U2) ═══════════════════════════════════ */

.ov-head { margin-bottom: var(--cw-s5); }
/* The greeting is the strongest thing on the page — it sets the whole tone. */
.ov-greeting { font: 700 34px/40px var(--cw-font); color: var(--cw-ink); margin: 0 0 6px; letter-spacing: -.02em; }
.ov-fleetline { font: 450 15px/24px var(--cw-font); color: var(--cw-text-soft); margin: 0; }

.ov-fleet { display: flex; flex-wrap: wrap; gap: var(--cw-s2); margin-bottom: var(--cw-s6); }
.ov-pill {
  display: inline-flex; align-items: center; gap: var(--cw-s2);
  font: var(--cw-small); color: var(--cw-text);
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-full); padding: 6px var(--cw-s4);
}
.ov-pill strong { color: var(--cw-ink); font-weight: 700; font-variant-numeric: tabular-nums; }
.ov-pill .cw-dot { width: 8px; height: 8px; border-radius: 50%; }
.ov-pill-ok   .cw-dot { background: var(--cw-ok); }
.ov-pill-warn .cw-dot { background: var(--cw-warn); }
.ov-pill-info .cw-dot { background: var(--cw-accent); animation: cw-breathe 2s ease-in-out infinite; }

.ov-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--cw-s4); margin-bottom: var(--cw-s7);
}

.ov-section { margin-bottom: var(--cw-s7); }
.ov-section-title {
  font: var(--cw-micro); color: var(--cw-text-soft); text-transform: uppercase;
  letter-spacing: .06em; margin: 0 0 var(--cw-s3);
}

.ov-list { display: flex; flex-direction: column; gap: var(--cw-s2); }
.ov-item {
  display: flex; align-items: center; gap: var(--cw-s3);
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-left-width: 3px; border-radius: var(--cw-r-md);
  padding: var(--cw-s3) var(--cw-s4);
}
.ov-item .cw-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.ov-item-icon {
  width: 24px; height: 24px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  font: 700 12px/1 var(--cw-font);
}
.ov-item-warn   { border-left-color: var(--cw-warn); }
.ov-item-warn   .cw-dot { background: var(--cw-warn); }
.ov-item-warn   .ov-item-icon { background: var(--cw-warn-bg); color: var(--cw-warn); }
.ov-item-danger { border-left-color: var(--cw-danger); }
.ov-item-danger .cw-dot { background: var(--cw-danger); }
.ov-item-danger .ov-item-icon { background: var(--cw-danger-bg); color: var(--cw-danger); }
.ov-item-info   { border-left-color: var(--cw-accent); }
.ov-item-info   .cw-dot { background: var(--cw-accent); }
.cw-dot-pulse { animation: cw-breathe 2s ease-in-out infinite; }
.ov-item-main { flex: 1; min-width: 0; }
.ov-item-title { font: 600 14px/20px var(--cw-font); color: var(--cw-ink); }
.ov-item-sub { font: var(--cw-micro); color: var(--cw-text-soft); margin-top: 2px; }
.ov-steps {
  font: var(--cw-micro); color: var(--cw-text-soft); white-space: pre-line;
  margin: 4px 0 0; font-family: inherit;
}

.ov-cols { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--cw-s6); }
@media (max-width: 900px) { .ov-cols { grid-template-columns: 1fr; } }

.ov-activity {
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-lg); padding: var(--cw-s2) var(--cw-s4);
}
/* Richer, taller activity rows — scannable at a glance (glyph · what · when). */
.ov-act {
  display: flex; align-items: flex-start; gap: var(--cw-s3);
  padding: 13px 0; border-bottom: 1px solid var(--cw-surface-2);
}
.ov-act:last-child { border-bottom: 0; }
.ov-act-glyph {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  font: 700 11px/1 var(--cw-font);
}
.ov-glyph-ok     { background: var(--cw-ok-bg);     color: var(--cw-ok); }
.ov-glyph-warn   { background: var(--cw-warn-bg);   color: var(--cw-warn); }
.ov-glyph-danger { background: var(--cw-danger-bg); color: var(--cw-danger); }
.ov-glyph-info   { background: var(--cw-info-bg);   color: var(--cw-accent); }
.ov-act-main { flex: 1; min-width: 0; }
.ov-act-title { font: 500 13.5px/19px var(--cw-font); color: var(--cw-text); }
.ov-act-sub { font: var(--cw-micro); color: var(--cw-text-soft); margin-top: 3px; }

.ov-spark { width: 100%; height: 24px; display: block; margin: 2px 0 4px; }
.ov-spark rect { fill: var(--cw-chart-3); }
.sd-warn { color: var(--cw-warn); font-weight: 700; }

/* Sidebar separator introduced when Launch was demoted below the workspace items */
.dash-sidenav-sep { height: 1px; background: var(--cw-border); margin: var(--cw-s3) var(--cw-s3); }

/* ══ Notification center — filters + day grouping (U6) ══════════════════ */

.notif-filters {
  display: flex; gap: 4px; padding: var(--cw-s3) var(--cw-s4) var(--cw-s2);
  border-bottom: 1px solid var(--cw-border); flex-wrap: wrap;
  position: sticky; top: 0; background: var(--cw-surface); z-index: 1;
}
.notif-filter {
  display: inline-flex; align-items: center; gap: 5px;
  font: var(--cw-micro); font-weight: 600; color: var(--cw-text-soft);
  background: none; border: 1px solid transparent; border-radius: var(--cw-r-full);
  padding: 4px 10px; cursor: pointer; font-family: inherit;
}
.notif-filter:hover { background: var(--cw-surface-2); color: var(--cw-ink); }
.notif-filter.is-on { background: var(--cw-accent-subtle); border-color: var(--cw-accent-border); color: var(--cw-accent); }
.notif-filter span {
  background: var(--cw-surface-2); border-radius: var(--cw-r-full);
  padding: 0 5px; font-size: 10px; color: var(--cw-text-soft);
}
.notif-filter.is-on span { background: var(--cw-surface); color: var(--cw-accent); }

.notif-day {
  font: var(--cw-micro); font-weight: 700; color: var(--cw-text-soft);
  text-transform: uppercase; letter-spacing: .06em;
  padding: var(--cw-s3) var(--cw-s4) 6px; background: var(--cw-surface);
}
.notif-item-action {
  display: inline-block; margin-top: 6px;
  font: var(--cw-micro); font-weight: 600; color: var(--cw-accent); text-decoration: none;
}
.notif-item-action:hover { text-decoration: underline; }

/* ══ Billing summary (U6) ═══════════════════════════════════════════════ */

.bl-summary {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--cw-s4); margin-bottom: var(--cw-s6);
}

/* ══ Support context (U6) ═══════════════════════════════════════════════ */

.sp-identity {
  display: flex; align-items: center; gap: var(--cw-s3); flex-wrap: wrap;
  background: var(--cw-surface-2); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-md); padding: var(--cw-s3) var(--cw-s4);
  font: var(--cw-small); color: var(--cw-text); margin-bottom: var(--cw-s4);
}
.sp-identity strong { color: var(--cw-ink); }
.sp-identity button {
  margin-left: auto; background: none; border: 0; cursor: pointer;
  color: var(--cw-accent); font: 600 12px/1 var(--cw-font); font-family: inherit;
}
.sp-expect {
  font: var(--cw-micro); color: var(--cw-text-soft);
  margin-top: var(--cw-s2);
}

/* ══ Provisioning takeover + arrival (U5) ═══════════════════════════════ */

.pv-takeover {
  position: fixed; inset: 0; z-index: 1300;
  background: linear-gradient(180deg, var(--cw-surface) 0%, var(--cw-bg) 100%);
  display: flex; align-items: center; justify-content: center;
  padding: var(--cw-s6); overflow-y: auto;
  animation: cw-fade-in var(--cw-t-std) both;
}
@keyframes cw-fade-in { from { opacity: 0; } }
.pv-inner { width: 100%; max-width: 520px; text-align: center; }

/* Breathing orb — the only "we're working" motion; calm, not a spinner race */
.pv-orb { position: relative; width: 84px; height: 84px; margin: 0 auto var(--cw-s6); }
.pv-orb span {
  position: absolute; inset: 0; border-radius: 50%;
  border: 2px solid var(--cw-accent-border);
  animation: pv-ripple 2.4s ease-out infinite;
}
.pv-orb span:nth-child(2) { animation-delay: .8s; }
.pv-orb span:nth-child(3) { animation-delay: 1.6s; }
.pv-orb::after {
  content: ''; position: absolute; inset: 30%;
  background: var(--cw-accent); border-radius: 50%;
  animation: cw-breathe 2.4s ease-in-out infinite;
}
@keyframes pv-ripple {
  0%   { transform: scale(.55); opacity: .9; }
  100% { transform: scale(1);   opacity: 0; }
}

.pv-title { font: var(--cw-display); color: var(--cw-ink); margin: 0 0 var(--cw-s2); }
.pv-sub { font: var(--cw-body); color: var(--cw-text-soft); margin: 0 auto var(--cw-s6); max-width: 400px; }

.pv-steps { list-style: none; margin: 0 auto; padding: 0; max-width: 320px; text-align: left; }
.pv-step {
  display: flex; align-items: center; gap: var(--cw-s3);
  font: var(--cw-body); color: var(--cw-text-faint);
  padding: 9px 0; transition: color var(--cw-t-std);
}
.pv-mark { width: 18px; text-align: center; font-size: 14px; flex: none; }
.pv-step.is-done   { color: var(--cw-text); }
.pv-step.is-done .pv-mark { color: var(--cw-ok); font-weight: 700; }
.pv-step.is-active { color: var(--cw-ink); font-weight: 600; }
.pv-step.is-active .pv-mark { color: var(--cw-accent); animation: pv-spin 1.4s linear infinite; }
@keyframes pv-spin { to { transform: rotate(360deg); } }

.pv-error {
  margin-top: var(--cw-s5); padding: var(--cw-s4);
  background: var(--cw-danger-bg); border: 1px solid var(--cw-danger-border);
  border-radius: var(--cw-r-md); font: var(--cw-small); color: var(--cw-text); text-align: left;
}

/* Arrival */
.pv-done { position: relative; animation: pv-rise var(--cw-t-panel) both; }
@keyframes pv-rise { from { opacity: 0; transform: translateY(10px); } }
.pv-check {
  width: 72px; height: 72px; margin: 0 auto var(--cw-s5);
  border-radius: 50%; background: var(--cw-ok-bg); color: var(--cw-ok);
  display: flex; align-items: center; justify-content: center;
}
.pv-domain {
  font: 600 17px/24px var(--cw-font-mono); color: var(--cw-accent);
  margin: 0 0 var(--cw-s3); word-break: break-all;
}
.pv-actions { display: flex; flex-wrap: wrap; gap: var(--cw-s2); justify-content: center; margin-top: var(--cw-s6); }
.pv-next { font: var(--cw-small); color: var(--cw-text-soft); margin-top: var(--cw-s5); }
.pv-link {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--cw-accent); font: inherit; font-weight: 600; text-decoration: underline;
}

.pv-confetti { position: absolute; inset: -20px 0 auto; height: 200px; overflow: hidden; pointer-events: none; }
.pv-confetti i {
  position: absolute; top: -12px; width: 7px; height: 11px; border-radius: 1px;
  animation: pv-fall 2.2s ease-in forwards;
}
@keyframes pv-fall {
  to { transform: translateY(220px) rotate(220deg); opacity: 0; }
}

/* ══ Sites — adaptive project view (U4) ═════════════════════════════════ */

.sv-tools { display: flex; align-items: center; gap: var(--cw-s2); flex-wrap: wrap; }
/* Search leads the toolbar — highest-frequency action at any fleet size. */
.sv-search { width: 220px; height: 34px; padding: 0 var(--cw-s3); margin-right: var(--cw-s2); }
.sites-toolbar { flex-wrap: wrap; gap: var(--cw-s2); }
.sv-sort { width: auto; height: 34px; padding: 0 var(--cw-s3); }
.sv-density {
  display: inline-flex; border: 1px solid var(--cw-border-strong);
  border-radius: var(--cw-r-md); overflow: hidden;
}
.sv-density button {
  background: var(--cw-surface); border: 0; cursor: pointer;
  padding: 0 10px; height: 34px; color: var(--cw-text-soft); font-size: 14px;
}
.sv-density button.is-on { background: var(--cw-accent-subtle); color: var(--cw-accent); }

/* Grid */
.sv-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: var(--cw-s5);
}

/* Six calm blocks with real breathing room: identity → health → evidence →
   actions. A HEALTHY card is deliberately plain — no coloured edge, nothing
   shouting — so an unhealthy one is impossible to miss. State is communicated
   through appearance, not just badges. */
.sc-card {
  display: flex; flex-direction: column;
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-lg); padding: var(--cw-s5);
  cursor: pointer;
  transition: box-shadow var(--cw-t-micro), border-color var(--cw-t-micro);
}
.sc-card:hover { box-shadow: var(--cw-e1); border-color: var(--cw-border-strong); }
.sc-card:focus-visible { outline: 2px solid var(--cw-accent); outline-offset: 2px; }

/* Only states that need you get an accent. Healthy stays quiet. */
.sc-attention { border-left: 3px solid var(--cw-warn); padding-left: calc(var(--cw-s5) - 2px); }
.sc-down {
  border-left: 3px solid var(--cw-danger); padding-left: calc(var(--cw-s5) - 2px);
  background: linear-gradient(90deg, var(--cw-danger-bg) 0%, var(--cw-surface) 42%);
}
.sc-provisioning, .sc-recovering {
  border-left: 3px solid var(--cw-accent); padding-left: calc(var(--cw-s5) - 2px);
}
.sc-removed { opacity: .6; }

/* Loading placeholder: the SHAPE of a card, never a fake card. It holds the
   layout so nothing jumps when the real data lands, and it is unmistakably
   not content — no borrowed numbers, no hover, no pointer. */
.sv-skel {
  min-height: 188px; border-style: dashed; background: var(--cw-surface-2);
  pointer-events: none; opacity: .55;
  animation: cw-skel-pulse 1.4s ease-in-out infinite;
}
.sv-skel:hover { box-shadow: none; border-color: var(--cw-border); }
@keyframes cw-skel-pulse { 0%, 100% { opacity: .35; } 50% { opacity: .6; } }
@media (prefers-reduced-motion: reduce) { .sv-skel { animation: none; } }

/* 1 — identity */
.sc-head { display: flex; align-items: center; gap: var(--cw-s3); margin-bottom: var(--cw-s4); }
.sc-mono {
  width: 34px; height: 34px; border-radius: var(--cw-r-md); flex: none;
  display: inline-flex; align-items: center; justify-content: center; overflow: hidden;
  color: #fff; font: 700 13px/1 var(--cw-font); letter-spacing: .02em;
}
.sc-fav-img { width: 34px; height: 34px; object-fit: contain; display: block; }
.sc-id { flex: 1; min-width: 0; }
.sc-name {
  font: 600 15px/21px var(--cw-font); color: var(--cw-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sc-sub { font: var(--cw-micro); color: var(--cw-text-soft); margin-top: 2px; }
.sc-menu { flex: none; font-size: 16px; line-height: 1; }

/* 2 — health (the only colour) + metadata */
.sc-health {
  display: flex; align-items: center; gap: var(--cw-s3); flex-wrap: wrap;
  padding-bottom: var(--cw-s4); border-bottom: 1px solid var(--cw-surface-2);
  margin-bottom: var(--cw-s4);
}
.sc-meta { font: var(--cw-micro); color: var(--cw-text-soft); }

/* 3 — evidence: labelled numbers, never decorative bars */
.sc-stats { display: flex; flex-direction: column; gap: var(--cw-s3); margin-bottom: var(--cw-s5); }
.sc-stat { display: flex; align-items: baseline; gap: var(--cw-s2); flex-wrap: wrap; }
.sc-stat-k {
  font: 600 11px/16px var(--cw-font); color: var(--cw-text-soft);
  text-transform: uppercase; letter-spacing: .06em; width: 62px; flex: none;
}
.sc-stat-v { font: 600 14px/20px var(--cw-font); color: var(--cw-ink); font-variant-numeric: tabular-nums; }
.sc-stat-v em { font-style: normal; font-weight: 450; color: var(--cw-text-faint); }
.sc-stat-s { font: var(--cw-micro); color: var(--cw-text-faint); }
.sc-of { font-weight: 450; color: var(--cw-text-soft); }

/* Provisioning: the card visibly works */
.sc-op {
  background: var(--cw-accent-subtle); border-radius: var(--cw-r-md);
  padding: var(--cw-s3) var(--cw-s4); margin-bottom: var(--cw-s5);
}
.sc-op-title { font: 600 13px/18px var(--cw-font); color: var(--cw-accent); }
.sc-op-steps {
  font: var(--cw-micro); color: var(--cw-text); white-space: pre-line;
  margin: 6px 0 8px; font-family: inherit;
}
.sc-op-bar { height: 3px; border-radius: 2px; background: var(--cw-accent-border); overflow: hidden; }
.sc-op-bar > i {
  display: block; height: 100%; width: 38%; border-radius: 2px;
  background: var(--cw-accent); animation: sc-indet 1.6s ease-in-out infinite;
}
@keyframes sc-indet {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(320%); }
}

/* 4 — actions */
.sc-foot { display: flex; align-items: center; gap: var(--cw-s2); margin-top: auto; }
.sc-foot .cw-btn { flex: 1; }

.sl-mono { width: 22px; height: 22px; border-radius: 5px; font-size: 9px; }

/* List */
/* Empty state gets the FULL width — never a grid cell. See paint(). */
.sv-empty-wrap { display: block; }
.sv-empty {
  gap: var(--cw-s3); padding: var(--cw-s8) var(--cw-s5);
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-lg);
}
.sv-empty .cw-btn { margin-top: var(--cw-s2); }
/* "Nothing needs attention" is good news, so it reads calm-positive rather
   than like a failed search. */
.sv-empty-ok { border-color: var(--cw-ok-border); background: var(--cw-ok-bg); }
.sv-empty-mark {
  width: 40px; height: 40px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--cw-surface); color: var(--cw-ok);
  font: 700 18px/1 var(--cw-font); border: 1px solid var(--cw-ok-border);
  margin-bottom: var(--cw-s1);
}

.sv-list { display: flex; flex-direction: column; }
.sl-head, .sl-row {
  display: grid; grid-template-columns: 24px 1fr 150px 90px 90px 40px;
  align-items: center; gap: var(--cw-s3);
}
.sl-head {
  font: var(--cw-micro); color: var(--cw-text-soft); text-transform: uppercase;
  letter-spacing: .04em; padding: 0 var(--cw-s3) var(--cw-s2);
}
.sl-row {
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-md); padding: 10px var(--cw-s3); margin-bottom: 6px;
  cursor: pointer; transition: border-color var(--cw-t-micro);
}
.sl-row:hover { border-color: var(--cw-border-strong); background: var(--cw-bg); }
.sl-fav { border-radius: 4px; }
.sl-name {
  font: 600 14px/20px var(--cw-font); color: var(--cw-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sl-views { font: var(--cw-small); color: var(--cw-text-soft); text-align: right; }
@media (max-width: 720px) {
  .sl-head { display: none; }
  .sl-row { grid-template-columns: 24px 1fr auto; }
  .sl-plan, .sl-views { display: none; }
}

/* ══ Site Detail (U3) — the central object ══════════════════════════════ */

.sd-head { display: flex; align-items: center; gap: var(--cw-s4); margin-bottom: var(--cw-s5); }
/* Same monogram as the site's card, one size up — the object you clicked is
   visibly the object you're now looking at. */
.sd-mono { width: 44px; height: 44px; border-radius: var(--cw-r-md); font-size: 16px; }
.sd-mono .sc-fav-img { width: 44px; height: 44px; }
/* Delete is present but never competes with Restore/Download; it earns colour
   only on intent. */
.sd-bk-del { color: var(--cw-text-soft); padding-left: 8px; padding-right: 8px; }
.sd-bk-del:hover { color: var(--cw-danger); background: var(--cw-danger-soft, rgba(220, 38, 38, .08)); }
.sd-bk-del svg { display: block; }
.sd-id { flex: 1; min-width: 0; }
.sd-name {
  font: var(--cw-display); color: var(--cw-ink); margin: 0 0 var(--cw-s2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sd-meta { display: flex; align-items: center; gap: var(--cw-s2); flex-wrap: wrap; }
.sd-sub { font: var(--cw-micro); color: var(--cw-text-soft); }
.sd-actions { display: flex; gap: var(--cw-s2); flex: none; }

.sd-tabs { margin-bottom: var(--cw-s6); }
.sd-body { min-height: 240px; }

.sd-grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: var(--cw-s5); }
@media (max-width: 980px) { .sd-grid { grid-template-columns: 1fr; } }
.sd-col { min-width: 0; }

.sd-conf { display: flex; flex-direction: column; }
.sd-conf-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--cw-s3);
  padding: 9px 0; border-bottom: 1px solid var(--cw-surface-2); font: var(--cw-small);
}
.sd-conf-row:last-child { border-bottom: 0; }
.sd-conf-row > span { color: var(--cw-text-soft); }
.sd-conf-row > strong { color: var(--cw-ink); font-weight: 600; text-align: right; }
.sd-tick { color: var(--cw-ok); font-weight: 700; }
.sd-conf-foot { font: var(--cw-micro); color: var(--cw-text-soft); margin-top: var(--cw-s3); }

.sd-bk-actions { display: flex; gap: var(--cw-s2); }
.sd-plan-now { display: flex; align-items: center; gap: var(--cw-s3); flex-wrap: wrap; }

.sd-danger { border-color: var(--cw-danger-border); }
.sd-danger-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--cw-s4); flex-wrap: wrap;
}
.sd-danger-row strong { color: var(--cw-ink); font: var(--cw-heading); }

/* Site rows become enterable (U3 entry point; U4 replaces them with cards) */
.site-row { cursor: pointer; }
.site-row:hover { background: var(--cw-bg); }

/* ══ Command palette (U8) ═══════════════════════════════════════════════ */

.cw-palette { position: fixed; inset: 0; z-index: 1400; }
.cw-pal-scrim {
  position: absolute; inset: 0; background: rgba(22, 22, 31, .45);
  animation: cw-fade-in var(--cw-t-micro) both;
}
.cw-pal-box {
  position: relative; margin: 12vh auto 0; width: min(560px, calc(100vw - 32px));
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-lg); box-shadow: var(--cw-e2); overflow: hidden;
  animation: cw-pal-in var(--cw-t-std) both;
}
@keyframes cw-pal-in { from { opacity: 0; transform: translateY(-8px) scale(.99); } }
.cw-pal-input {
  width: 100%; box-sizing: border-box; border: 0; outline: none;
  background: transparent; color: var(--cw-ink);
  font: 450 16px/24px var(--cw-font); padding: var(--cw-s4) var(--cw-s5);
  border-bottom: 1px solid var(--cw-border);
}
.cw-pal-input::placeholder { color: var(--cw-text-faint); }
.cw-pal-list { list-style: none; margin: 0; padding: var(--cw-s2); max-height: 46vh; overflow-y: auto; }
.cw-pal-item {
  display: flex; align-items: center; gap: var(--cw-s3);
  padding: 10px var(--cw-s3); border-radius: var(--cw-r-sm); cursor: pointer;
}
.cw-pal-item.is-on { background: var(--cw-accent-subtle); }
.cw-pal-title { flex: 1; min-width: 0; font: var(--cw-body); color: var(--cw-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cw-pal-item.is-on .cw-pal-title { color: var(--cw-accent); font-weight: 600; }
.cw-pal-hint { font: var(--cw-micro); color: var(--cw-text-soft); flex: none; }
.cw-pal-empty { padding: var(--cw-s5); text-align: center; color: var(--cw-text-soft); font: var(--cw-small); }
.cw-pal-foot {
  display: flex; gap: var(--cw-s4); padding: var(--cw-s2) var(--cw-s5);
  border-top: 1px solid var(--cw-border); background: var(--cw-surface-2);
  font: var(--cw-micro); color: var(--cw-text-soft);
}
.cw-pal-foot kbd {
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: 4px; padding: 1px 5px; margin-right: 3px;
  font: 500 11px/16px var(--cw-font-mono); color: var(--cw-text);
}
@media (max-width: 768px) { .cw-pal-box { margin-top: 6vh; } }

/* ══ Mobile shell (U7 / §12) ════════════════════════════════════════════ */

.cw-bottomnav { display: none; }

@media (max-width: 768px) {
  /* Sidebar is a desktop affordance — the bottom bar replaces it. */
  #dash-sidebar { display: none !important; }
  .dash-main-area { margin-left: 0 !important; width: 100% !important; }
  body.has-bottomnav .dash-content { padding-bottom: 88px; }

  .cw-bottomnav {
    display: flex; align-items: center; justify-content: space-around;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 900;
    height: 64px; padding-bottom: env(safe-area-inset-bottom, 0);
    background: var(--cw-surface); border-top: 1px solid var(--cw-border);
    box-shadow: 0 -1px 12px rgba(22, 22, 31, .06);
  }
  .cw-bn-item {
    position: relative; flex: 1;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    min-height: 48px;                      /* ≥44px touch target (audit fix) */
    background: none; border: 0; cursor: pointer; font-family: inherit;
    color: var(--cw-text-soft); font: var(--cw-micro);
    transition: color var(--cw-t-micro);
  }
  .cw-bn-item.is-on { color: var(--cw-accent); }
  .cw-bn-add {
    flex: none; width: 52px; height: 52px; margin-top: -18px;
    border-radius: 50%; border: 3px solid var(--cw-surface);
    background: var(--cw-accent); color: var(--cw-accent-ink);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer; box-shadow: var(--cw-e1);
  }
  .cw-bn-badge {
    position: absolute; top: 4px; right: 50%; transform: translateX(16px);
    min-width: 8px; height: 8px; border-radius: 50%; background: var(--cw-danger);
    font-size: 0;
  }

  /* Header stays, compacted. */
  .cw-header { padding: 0 var(--cw-s4); gap: var(--cw-s2); }
  .cw-crumbs { font-size: 12px; }
  #cw-new-site { display: none; }         /* the ➕ in the bar owns this on mobile */

  /* Panels become full-screen sheets; dialogs sit near the bottom. */
  .cw-panel { width: 100vw !important; border-radius: 0; }
  .cw-panel.open { transform: translateY(0); }
  .notif-panel {
    position: fixed; top: auto; left: 0; right: 0; bottom: 0;
    width: 100vw; max-height: 82vh; border-radius: var(--cw-r-lg) var(--cw-r-lg) 0 0;
  }
  .cw-toasts { left: var(--cw-s4); right: var(--cw-s4); bottom: 76px; }
  .cw-toast { max-width: none; }

  /* Content breathing room on small screens. */
  .dash-content { padding-left: var(--cw-s4) !important; padding-right: var(--cw-s4) !important; }
  .ov-greeting, .sd-name, .pv-title { font-size: 22px; line-height: 28px; }
  .sd-head { flex-wrap: wrap; }
  .sd-actions { width: 100%; }
  .sd-actions .cw-btn { flex: 1; }
  .cw-tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .cw-tabs::-webkit-scrollbar { display: none; }
  .sv-tools { width: 100%; }
  .sv-search { flex: 1; width: auto; }
}

/* Touch targets everywhere (audit fix — legacy kebab items were ~32px) */
/* TOUCH TARGETS.
 *
 * 38px is a comfortable button on a mouse and a miss on a thumb; both platform
 * guidelines land on 44px. Scoped to coarse pointers so desktop density is
 * unchanged — this is the one place where the same control genuinely wants two
 * different sizes. */
@media (pointer: coarse) {
  .cw-menu [role="menuitem"] { padding: 12px var(--cw-s3); }
  .notif-item-dismiss, .bk-del, .cw-panel-close { padding: 10px; }
  .cw-btn      { min-height: 44px; height: auto; padding-top: 0; padding-bottom: 0; }
  .cw-btn-sm   { min-height: 38px; }
  .cw-btn-icon { min-width: 44px; width: auto; }
  .cw-input, .cw-select, .cw-textarea { min-height: 44px; }
}

/* ══ Global a11y (audit fixes — apply platform-wide NOW) ════════════════ */

.cw-skip {
  position: absolute; left: -9999px; top: 0; z-index: 2000;
  background: var(--cw-accent); color: var(--cw-accent-ink);
  padding: 10px var(--cw-s4); border-radius: 0 0 var(--cw-r-md) 0;
  font: 600 14px/1 var(--cw-font); text-decoration: none;
}
.cw-skip:focus { left: 0; }

:focus-visible {
  outline: 2px solid var(--cw-accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Legacy contrast overrides — retire the failing #9c9cb5 tier everywhere
   until each surface is rebuilt on tokens (U2–U7). */
.notif-item-meta, .notif-prefs-note, .notif-pref-row em, .notif-empty,
.bk-sub, .bk-kind, .bk-empty, .bk-toolbar-note, .bk-decrypt-note,
.cl-domain, .cl-checking, .cl-note, .cl-plan-row span,
.mx-kpi-l, .mx-chart-label, .mx-empty, .mx-fact > span,
.tl-meta, .tl-time,
.site-meta, .section-desc, .ns-note, .upgrade-note {
  color: var(--cw-text-soft) !important;
}

/* ══ Plan (U9) — a control panel, not a pricing page ═══════════════════════
   The customer already bought. So the plan they're ON is the hero, their real
   usage lives inside it, and the other tiers are a quiet rail underneath.
   No gradients, no glass, no oversized shadows: weight comes from scale,
   spacing and restraint. Section rhythm 32px, card padding 24px. */

/* CAREFUL: the `font:` shorthand RESETS font-variant-numeric. Any rule below
   that sets `font:` on an element also carrying .cw-num wipes this out, so
   those rules restate tabular-nums themselves. Figures that jitter as they
   update are the fastest way to make a dashboard feel cheap. */
.cw-num { font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1; }

.pl-head { margin-bottom: var(--cw-s6); }
.pl-head-sub {
  font: var(--cw-body); color: var(--cw-text-soft);
  margin: var(--cw-s2) 0 0; max-width: 62ch;
}
.pl-section-title {
  font: var(--cw-title); color: var(--cw-ink);
  margin: var(--cw-s7) 0 var(--cw-s4);
}
.pl-section-title.is-hidden, .pl-up.is-hidden { display: none; }

/* ── Billing interval selector ──────────────────────────────
   Sits on the section heading row. `wrap` + `auto` margin so a long heading
   and the control never collide on narrow viewports — the control drops to
   its own line instead of overflowing. */
.pl-head-row {
  display: flex; align-items: center; gap: var(--cw-s4); flex-wrap: wrap;
}
.pl-head-row .pl-section-title { margin-right: auto; }
/* The title carries the row's top margin; the control aligns to its baseline
   box rather than adding a second, competing margin. */
.pl-interval {
  display: inline-flex; gap: 2px; padding: 3px;
  background: var(--cw-surface-2);
  border: 1px solid var(--cw-border);
  border-radius: 10px;
  margin: var(--cw-s7) 0 var(--cw-s4);
}
.pl-interval-opt {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px; border: 0; border-radius: 7px;
  background: transparent; color: var(--cw-text-soft);
  font: 600 13px/1 var(--cw-font); cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.pl-interval-opt:hover { color: var(--cw-ink); }
.pl-interval-opt.is-active {
  background: var(--cw-surface); color: var(--cw-ink);
  box-shadow: 0 1px 2px rgba(0,0,0,.08);
}
.pl-interval-save {
  font: 700 11px/1 var(--cw-font);
  padding: 3px 6px; border-radius: 5px;
  background: var(--cw-accent); color: var(--cw-accent-ink);
}
.pl-interval-save:empty { display: none; }

/* Same control inside the create-site modal: centred above the plan cards,
   no heading to sit beside. Reuses .pl-interval-opt so the two toggles are
   visually identical — they are the same control in two places. */
.cs-interval {
  display: inline-flex; gap: 2px; padding: 3px;
  margin: 0 auto var(--cw-s4);
  background: var(--cw-surface-2);
  border: 1px solid var(--cw-border);
  border-radius: 10px;
}
.cs-interval.hidden { display: none; }
/* The plan step is a column flex; this keeps the control centred in it. */
#cs-step-plan .cs-interval { align-self: center; }

/* ── "Need more resources?" on the Dedicated card ───────────
   Deliberately quiet: a secondary block inside the card, not an alert. It sits
   below the CTA and reads as part of the plan, not as an error state. */
.pl-up-more {
  margin-top: var(--cw-s4);
  padding-top: var(--cw-s4);
  border-top: 1px solid var(--cw-accent-border);
}
.pl-up-more-title { font: 600 13px/1.4 var(--cw-font); color: var(--cw-ink); }
.pl-up-more-text {
  font: var(--cw-micro); color: var(--cw-text-soft);
  margin: 4px 0 var(--cw-s3);
}
.pl-up-more-cta {
  display: inline-flex; align-items: center;
  padding: 7px 14px; border-radius: 8px; cursor: pointer;
  background: transparent; color: var(--cw-accent);
  border: 1px solid var(--cw-accent-border);
  font: 600 13px/1 var(--cw-font);
  transition: background .15s ease, border-color .15s ease;
}
.pl-up-more-cta:hover { background: var(--cw-surface); border-color: var(--cw-accent); }
.pl-up-more-cta:focus-visible { outline: 2px solid var(--cw-accent); outline-offset: 2px; }

/* ── Hero: the plan you're on ───────────────────────────── */
.pl-hero {
  background: var(--cw-surface);
  border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-lg);
  padding: var(--cw-s7);
  box-shadow: var(--cw-e1);
}
/* Dedicated earns a mark of distinction — one accent rule, nothing more. */
.pl-hero-dedicated {
  border-color: var(--cw-accent-border);
  box-shadow: inset 3px 0 0 var(--cw-accent), var(--cw-e1);
}

.pl-hero-main {
  display: grid; grid-template-columns: minmax(200px, 260px) 1fr;
  gap: var(--cw-s7); align-items: start;
}
.pl-eyebrow {
  font: var(--cw-micro); letter-spacing: .08em; text-transform: uppercase;
  color: var(--cw-text-faint); margin-bottom: var(--cw-s2);
}
.pl-hero-name {
  font: 700 34px/40px var(--cw-font); color: var(--cw-ink);
  letter-spacing: -.02em; margin-bottom: var(--cw-s2);
}
.pl-hero-price {
  font: 650 26px/32px var(--cw-font); color: var(--cw-ink);
  font-variant-numeric: tabular-nums;
  margin-bottom: var(--cw-s3);
}
.pl-hero-per { font: var(--cw-small); color: var(--cw-text-soft); margin-left: 2px; }

/* Stats rail — the usage context that makes an upgrade a decision rather than
   an advert. */
.pl-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: var(--cw-s6) var(--cw-s5);
}
.pl-stat-label {
  font: var(--cw-micro); letter-spacing: .04em; text-transform: uppercase;
  color: var(--cw-text-faint); margin-bottom: var(--cw-s2);
}
.pl-stat-value {
  font: 650 20px/26px var(--cw-font); color: var(--cw-ink);
  font-variant-numeric: tabular-nums;
}
.pl-stat-of  { font: 450 14px/20px var(--cw-font); color: var(--cw-text-soft); }
.pl-stat-sub { font: var(--cw-micro); color: var(--cw-text-soft); margin-top: var(--cw-s2); }

.pl-meter {
  height: 5px; border-radius: var(--cw-r-full); background: var(--cw-surface-2);
  overflow: hidden; margin-bottom: var(--cw-s1);
}
.pl-meter > i { display: block; height: 100%; background: var(--cw-ok); border-radius: inherit; }
.pl-meter-warn   > i { background: var(--cw-warn); }
.pl-meter-danger > i { background: var(--cw-danger); }
.pl-meter-pct { font: var(--cw-micro); color: var(--cw-text-soft); }

/* Infrastructure strip — quiet facts that say "this is looked after". */
.pl-infra {
  display: flex; flex-wrap: wrap; gap: var(--cw-s3) var(--cw-s7);
  margin-top: var(--cw-s7); padding-top: var(--cw-s5);
  border-top: 1px solid var(--cw-border);
}
.pl-infra-item { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pl-infra-k { font: var(--cw-micro); color: var(--cw-text-faint); }
.pl-infra-v {
  font: 500 13px/20px var(--cw-font); color: var(--cw-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 30ch;
}

.pl-hero-actions {
  display: flex; flex-wrap: wrap; gap: var(--cw-s3);
  margin-top: var(--cw-s6);
}

/* ── Upgrade rail ───────────────────────────────────────── */
/* Capped tracks, left-aligned — NOT `1fr`. With a tier hidden (you're on it),
   1fr stretches the survivors to fill the row and you're back to the equal-
   width pricing grid this redesign exists to kill. The upgrades are secondary
   to the hero and should read that way at every fleet size. */
.pl-upgrades {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 340px));
  justify-content: start; gap: var(--cw-s5); align-items: stretch;
}
.pl-up {
  display: flex; flex-direction: column;
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-lg); padding: var(--cw-s6);
  transition: border-color var(--cw-t-micro), box-shadow var(--cw-t-micro);
}
.pl-up:hover { border-color: var(--cw-border-strong); box-shadow: var(--cw-e1); }
.pl-up-featured { border-color: var(--cw-accent-border); background: var(--cw-accent-subtle); }
.pl-up-featured:hover { border-color: var(--cw-accent); }
.pl-up-eyebrow {
  font: var(--cw-micro); letter-spacing: .06em; text-transform: uppercase;
  color: var(--cw-accent); margin-bottom: var(--cw-s3);
}
.pl-up-top { margin-bottom: var(--cw-s4); }
.pl-up-name { font: var(--cw-heading); color: var(--cw-ink); margin-bottom: var(--cw-s1); }
.pl-up-price { display: flex; align-items: baseline; gap: 3px; }
.pl-up-amount {
  font: 700 26px/32px var(--cw-font); color: var(--cw-ink); letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.pl-up-per { font: var(--cw-small); color: var(--cw-text-soft); }

.pl-up-feat { list-style: none; margin: 0 0 var(--cw-s5); padding: 0; flex: 1; }
.pl-up-feat li {
  position: relative; padding-left: 22px; margin-bottom: var(--cw-s2);
  font: var(--cw-small); color: var(--cw-text);
}
.pl-up-feat li::before {
  content: '✓'; position: absolute; left: 0; top: 0;
  color: var(--cw-ok); font-weight: 700; font-size: 12px; line-height: 20px;
}
.pl-up-status { font: var(--cw-micro); color: var(--cw-text-soft); margin-top: var(--cw-s3); }
.pl-up-status:empty { display: none; }

/* The purchase buttons keep their legacy ids and classes — dashboard.js owns
   their label and disabled state. Only their appearance is restated here. */
.pl-up .btn-plan-sm {
  width: 100%; border-radius: var(--cw-r-md); border: 1px solid var(--cw-border-strong);
  background: var(--cw-surface); color: var(--cw-ink);
  font: 600 14px/20px var(--cw-font); padding: 10px var(--cw-s4); cursor: pointer;
  transition: background var(--cw-t-micro), border-color var(--cw-t-micro);
}
.pl-up .btn-plan-sm:hover:not(:disabled) { background: var(--cw-surface-2); border-color: var(--cw-ink); }
.pl-up-featured .btn-plan-sm {
  background: var(--cw-accent); border-color: var(--cw-accent); color: var(--cw-accent-ink);
}
.pl-up-featured .btn-plan-sm:hover:not(:disabled) {
  background: var(--cw-accent-hover); border-color: var(--cw-accent-hover);
}
.pl-up .btn-plan-sm:disabled { opacity: .55; cursor: default; }

/* ── Comparison ─────────────────────────────────────────── */
.pl-compare-card { padding: 0; overflow: hidden; }
.pl-compare-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.pl-table { width: 100%; border-collapse: collapse; min-width: 560px; }
.pl-table th, .pl-table td {
  padding: var(--cw-s4) var(--cw-s5); text-align: left;
  border-bottom: 1px solid var(--cw-border);
}
.pl-table thead th {
  font: var(--cw-micro); letter-spacing: .04em; text-transform: uppercase;
  color: var(--cw-text-faint); white-space: nowrap; background: var(--cw-surface-2);
}
.pl-table tbody th { font: 500 13px/20px var(--cw-font); color: var(--cw-text); }
.pl-table tbody td { font: var(--cw-small); color: var(--cw-text); }
.pl-table tbody tr:last-child th, .pl-table tbody tr:last-child td { border-bottom: 0; }
.pl-table .is-current { background: var(--cw-accent-subtle); }
.pl-table thead .is-current { color: var(--cw-accent); }
.pl-th-tag {
  display: block; font: var(--cw-micro); text-transform: none; letter-spacing: 0;
  color: var(--cw-accent); opacity: .8;
}
.pl-yes { color: var(--cw-ok); font-weight: 700; }
.pl-no  { color: var(--cw-text-faint); }

/* ── Site picker: segmented chips (U9), shared with the Domain tab ─────── */
.site-picker { display: flex; flex-wrap: wrap; gap: var(--cw-s2); margin-bottom: var(--cw-s6); }
.site-picker .site-picker-pill {
  display: inline-flex; align-items: center; gap: var(--cw-s2);
  padding: 6px 12px 6px 6px; border-radius: var(--cw-r-full);
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  font: 500 13px/20px var(--cw-font); color: var(--cw-text);
  cursor: pointer; max-width: 100%;
  transition: border-color var(--cw-t-micro), box-shadow var(--cw-t-micro), background var(--cw-t-micro);
}
.site-picker .site-picker-pill:hover { border-color: var(--cw-border-strong); box-shadow: var(--cw-e1); }
.site-picker .site-picker-pill.active {
  border-color: var(--cw-accent); background: var(--cw-accent-subtle); color: var(--cw-ink);
}
.site-picker .site-picker-pill:focus-visible { outline: 2px solid var(--cw-accent); outline-offset: 2px; }
.site-picker .spp-mark {
  width: 22px; height: 22px; border-radius: var(--cw-r-full); font-size: 9px; flex: none;
}
.site-picker .spp-mark .sc-fav-img { width: 22px; height: 22px; }
.spp-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spp-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--cw-text-faint); }
.spp-dot-ok     { background: var(--cw-ok); }
.spp-dot-warn   { background: var(--cw-warn); }
.spp-dot-danger { background: var(--cw-danger); }
.spp-dot-info   { background: var(--cw-info); }
.site-picker .site-picker-pill.is-removed { opacity: .6; }

/* ── Responsive ─────────────────────────────────────────── */
@media (max-width: 860px) {
  .pl-hero { padding: var(--cw-s6); }
  .pl-hero-main { grid-template-columns: 1fr; gap: var(--cw-s6); }
  .pl-hero-name { font: 700 28px/34px var(--cw-font); }
  .pl-infra { gap: var(--cw-s4); }
  .pl-hero-actions .cw-btn { flex: 1 1 auto; }
}

/* ══ Domain (U10) — connection as an infrastructure workflow ═══════════════
   Replaces a title + a sentence + one alert box. Density comes from putting
   real facts on the page, not from shrinking the spacing. */

.dv-head { margin-bottom: var(--cw-s6); }
.dv-head-sub {
  font: var(--cw-body); color: var(--cw-text-soft);
  margin: var(--cw-s2) 0 0; max-width: 66ch;
}
.dv-section-title {
  font: var(--cw-title); color: var(--cw-ink);
  margin: var(--cw-s7) 0 var(--cw-s4);
}
.dv-eyebrow {
  font: var(--cw-micro); letter-spacing: .08em; text-transform: uppercase;
  color: var(--cw-text-faint); margin-bottom: var(--cw-s2);
}

/* ── 1. Platform domain ─────────────────────────────────── */
.dv-platform { padding: var(--cw-s6); }
.dv-platform-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--cw-s4); flex-wrap: wrap;
}
.dv-platform-id { min-width: 0; }
.dv-platform-url {
  font: 650 22px/28px var(--cw-font); color: var(--cw-ink);
  text-decoration: none; word-break: break-all;
}
.dv-platform-url:hover { color: var(--cw-accent); text-decoration: underline; }
.dv-platform-note {
  font: var(--cw-small); color: var(--cw-text-soft);
  margin-top: var(--cw-s2); max-width: 58ch;
}
.dv-facts {
  display: flex; flex-wrap: wrap; gap: var(--cw-s3) var(--cw-s7);
  margin-top: var(--cw-s5); padding-top: var(--cw-s5);
  border-top: 1px solid var(--cw-border);
}
.dv-fact { display: flex; flex-direction: column; gap: 2px; }
.dv-fact-k { font: var(--cw-micro); color: var(--cw-text-faint); }
.dv-fact-v { font: 500 13px/20px var(--cw-font); color: var(--cw-text); }
.dv-platform-actions { display: flex; flex-wrap: wrap; gap: var(--cw-s3); margin-top: var(--cw-s5); }

/* ── 2. Custom domain: upsell, connected, connect form ──── */
.dv-upsell {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--cw-s7); padding: var(--cw-s6);
  border-color: var(--cw-accent-border); background: var(--cw-accent-subtle);
}
.dv-upsell-main { min-width: 0; }
.dv-upsell-title { font: var(--cw-title); color: var(--cw-ink); margin: 0 0 var(--cw-s2); }
.dv-upsell-text { font: var(--cw-small); color: var(--cw-text-soft); margin: 0 0 var(--cw-s4); max-width: 60ch; }
.dv-benefits { list-style: none; margin: 0; padding: 0; }
.dv-benefits li {
  position: relative; padding-left: 24px; margin-bottom: var(--cw-s2);
  font: var(--cw-small); color: var(--cw-text);
}
.dv-benefits li::before {
  content: '✓'; position: absolute; left: 0; top: 0;
  color: var(--cw-accent); font-weight: 700; font-size: 12px; line-height: 20px;
}
.dv-benefits strong { color: var(--cw-ink); font-weight: 600; }
.dv-upsell-cta { flex: none; align-self: center; }

.dv-connected { padding: var(--cw-s6); }
.dv-domain-row { display: flex; align-items: center; gap: var(--cw-s4); flex-wrap: wrap; }
.dv-domain-id { flex: 1; min-width: 0; }
.dv-domain {
  font: 650 20px/26px var(--cw-font); color: var(--cw-ink);
  word-break: break-all; display: block;
}

/* The status text is set by dashboard.js (textContent + .ok/.pending/.error),
   so it stays a <span> — restated here as a badge to match every other status
   in the console. Uses console tokens, not the legacy --success/--warn pair. */
.dv-connected .domain-status {
  display: inline-flex; align-items: center; gap: var(--cw-s2);
  padding: 3px 10px; border-radius: var(--cw-r-full);
  border: 1px solid var(--cw-border); background: var(--cw-surface-2);
  font: var(--cw-micro); color: var(--cw-text-soft); white-space: nowrap;
}
.dv-connected .domain-status.ok {
  background: var(--cw-ok-bg); border-color: var(--cw-ok-border); color: var(--cw-ok);
}
.dv-connected .domain-status.pending {
  background: var(--cw-warn-bg); border-color: var(--cw-warn-border); color: var(--cw-warn);
}
.dv-connected .domain-status.error {
  background: var(--cw-danger-bg); border-color: var(--cw-danger-border); color: var(--cw-danger);
}

.dv-connect { padding: var(--cw-s6); }
.dv-label { display: block; font: var(--cw-micro); color: var(--cw-text-soft); margin-bottom: var(--cw-s2); }
.dv-form-row { display: flex; gap: var(--cw-s3); flex-wrap: wrap; }
.dv-input {
  flex: 1 1 260px; min-width: 0;
  padding: 10px var(--cw-s4); border-radius: var(--cw-r-md);
  border: 1px solid var(--cw-border-strong); background: var(--cw-surface);
  color: var(--cw-ink); font: var(--cw-body);
}
.dv-input::placeholder { color: var(--cw-text-faint); }
.dv-input:focus { outline: 2px solid var(--cw-accent); outline-offset: 1px; border-color: var(--cw-accent); }
.dv-form-hint { font: var(--cw-micro); color: var(--cw-text-soft); margin: var(--cw-s3) 0 0; }
.dv-form-hint code {
  font-family: var(--cw-font-mono); font-size: 11px;
  background: var(--cw-surface-2); padding: 1px 4px; border-radius: var(--cw-r-sm);
}

/* Nameservers: the one thing the customer must copy exactly, so it reads as
   data — monospaced, in a well, selectable. Scoped to #ns-box so the
   create-site flow's own list is untouched. */
#ns-box { margin-top: var(--cw-s5); padding: var(--cw-s6); background: var(--cw-surface); border: 1px solid var(--cw-border); border-radius: var(--cw-r-lg); }
#ns-box .ns-label { font: var(--cw-heading); color: var(--cw-ink); margin: 0 0 var(--cw-s4); }
#ns-box .ns-list { display: flex; flex-direction: column; gap: var(--cw-s2); }
#ns-box .ns-entry {
  font-family: var(--cw-font-mono); font-size: 13px; line-height: 20px;
  color: var(--cw-ink); background: var(--cw-surface-2);
  border: 1px solid var(--cw-border); border-radius: var(--cw-r-md);
  padding: 10px var(--cw-s4); user-select: all; word-break: break-all;
}
#ns-box .ns-note { font: var(--cw-small); color: var(--cw-text-soft); margin: var(--cw-s4) 0 0; }

/* ── 3. Connection workflow ─────────────────────────────── */
.dv-steps {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--cw-s4);
  counter-reset: dv;
}
.dv-step {
  position: relative; display: flex; gap: var(--cw-s3);
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-lg); padding: var(--cw-s5);
}
/* The connector is what turns four cards into one pipeline. */
.dv-step:not(:last-child)::after {
  content: ''; position: absolute; top: 50%; right: calc(var(--cw-s4) * -1);
  width: var(--cw-s4); height: 1px; background: var(--cw-border-strong);
}
.dv-step-mark {
  flex: none; width: 26px; height: 26px; border-radius: var(--cw-r-full);
  display: inline-flex; align-items: center; justify-content: center;
  font: 600 12px/1 var(--cw-font);
  background: var(--cw-surface-2); color: var(--cw-text-soft);
  border: 1px solid var(--cw-border);
}
.dv-step-title { font: 600 13px/20px var(--cw-font); color: var(--cw-ink); }
.dv-step-text { font: var(--cw-micro); color: var(--cw-text-soft); margin-top: 2px; }

.dv-step.is-done .dv-step-mark {
  background: var(--cw-ok-bg); color: var(--cw-ok); border-color: var(--cw-ok-border);
}
.dv-step.is-now { border-color: var(--cw-accent); box-shadow: inset 2px 0 0 var(--cw-accent); }
.dv-step.is-now .dv-step-mark {
  background: var(--cw-accent); color: var(--cw-accent-ink); border-color: var(--cw-accent);
}

/* Locked: shown, not hidden. Seeing the machinery you'd be buying argues
   better than a padlock — but it must never look interactive. */
.dv-steps.is-locked { opacity: .55; filter: grayscale(1); pointer-events: none; }
.dv-steps-note { font: var(--cw-small); color: var(--cw-text-soft); margin: var(--cw-s4) 0 0; }

/* ── Responsive ─────────────────────────────────────────── */
@media (max-width: 1000px) {
  .dv-steps { grid-template-columns: repeat(2, 1fr); }
  /* The horizontal connector is a lie on a wrapped grid. */
  .dv-step:not(:last-child)::after { display: none; }
}
@media (max-width: 860px) {
  .dv-platform, .dv-upsell, .dv-connected, .dv-connect, #ns-box { padding: var(--cw-s5); }
  .dv-upsell { flex-direction: column; gap: var(--cw-s5); }
  .dv-upsell-cta { align-self: stretch; width: 100%; }
  .dv-platform-url { font: 650 18px/24px var(--cw-font); }
  .dv-steps { grid-template-columns: 1fr; }
  .dv-platform-actions .cw-btn { flex: 1 1 auto; }
}

/* ══ Billing (U11) — adaptive: free accounts never see billing UI ══════════
   Money pages earn trust through precision, not decoration. Amounts are
   tabular and right-aligned wherever they're compared; status is a badge, not
   a coloured word; nothing is styled to look more important than the number. */

.bl-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--cw-s5); flex-wrap: wrap; margin-bottom: var(--cw-s6);
}
.bl-head-main { min-width: 0; }
.bl-head-sub {
  font: var(--cw-body); color: var(--cw-text-soft);
  margin: var(--cw-s2) 0 0; max-width: 60ch;
}
.bl-section-title {
  font: var(--cw-title); color: var(--cw-ink);
  margin: var(--cw-s7) 0 var(--cw-s4);
}
.bl-eyebrow {
  font: var(--cw-micro); letter-spacing: .08em; text-transform: uppercase;
  color: var(--cw-text-faint); margin-bottom: var(--cw-s2);
}
.bl-loading { font: var(--cw-small); color: var(--cw-text-soft); padding: var(--cw-s6) 0; }

.bl-error { padding: var(--cw-s6); border-color: var(--cw-danger-border); }
.bl-error-title { font: var(--cw-heading); color: var(--cw-ink); margin-bottom: var(--cw-s2); }
.bl-error-text { font: var(--cw-small); color: var(--cw-text-soft); margin: 0 0 var(--cw-s4); }

/* ── Free state ─────────────────────────────────────────── */
.bl-free { padding: var(--cw-s7); }
.bl-free-main { max-width: 62ch; }
.bl-free-title { font: var(--cw-display); color: var(--cw-ink); margin: 0 0 var(--cw-s3); }
.bl-free-text { font: var(--cw-body); color: var(--cw-text-soft); margin: 0 0 var(--cw-s5); }
.bl-free-list { list-style: none; margin: 0 0 var(--cw-s6); padding: 0; }
.bl-free-list li {
  position: relative; padding-left: 24px; margin-bottom: var(--cw-s2);
  font: var(--cw-small); color: var(--cw-text);
}
.bl-free-list li::before {
  content: '·'; position: absolute; left: 8px; top: 0;
  color: var(--cw-text-faint); font-weight: 700; line-height: 20px;
}
.bl-free-list strong { color: var(--cw-ink); font-weight: 600; }
.bl-free-note { font: var(--cw-small); color: var(--cw-text-soft); margin: var(--cw-s4) 0 0; }

/* ── Summary cards ──────────────────────────────────────── */
.bl-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--cw-s4);
}
.bl-stat { padding: var(--cw-s5); }
.bl-stat-label {
  font: var(--cw-micro); letter-spacing: .04em; text-transform: uppercase;
  color: var(--cw-text-faint); margin-bottom: var(--cw-s2);
}
.bl-stat-value {
  font: 650 24px/30px var(--cw-font); color: var(--cw-ink);
  font-variant-numeric: tabular-nums;
}
.bl-stat-sub { font: var(--cw-micro); color: var(--cw-text-soft); margin-top: var(--cw-s2); }
.bl-link {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: var(--cw-micro); color: var(--cw-accent); text-decoration: underline;
}
.bl-link:hover { color: var(--cw-accent-hover); }

/* ── Subscription cards ─────────────────────────────────── */
.bl-subs {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--cw-s4);
}
.bl-sub { padding: var(--cw-s5); display: flex; flex-direction: column; }
.bl-sub-top {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--cw-s3); margin-bottom: var(--cw-s4);
}
.bl-sub-id { min-width: 0; }
.bl-sub-plan { font: var(--cw-heading); color: var(--cw-ink); }
.bl-sub-domain {
  font: var(--cw-small); color: var(--cw-text-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bl-sub-facts {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--cw-s4); flex-wrap: wrap; flex: 1;
  padding-bottom: var(--cw-s4);
}
.bl-sub-amount {
  font: 650 22px/28px var(--cw-font); color: var(--cw-ink);
  font-variant-numeric: tabular-nums;
}
.bl-sub-per { font: var(--cw-small); color: var(--cw-text-soft); margin-left: 2px; }
.bl-sub-when { text-align: right; }
.bl-sub-when-k { display: block; font: var(--cw-micro); color: var(--cw-text-faint); }
.bl-sub-when-v { font: 500 13px/20px var(--cw-font); color: var(--cw-text); }
.bl-sub-actions {
  display: flex; gap: var(--cw-s2); flex-wrap: wrap;
  padding-top: var(--cw-s4); border-top: 1px solid var(--cw-border);
}
.bl-cancel { color: var(--cw-text-soft); }
.bl-cancel:hover:not(:disabled) { color: var(--cw-danger); }

/* ── Invoices ───────────────────────────────────────────── */
.bl-inv-card { padding: 0; overflow: hidden; }
.bl-inv-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.bl-inv-table { width: 100%; border-collapse: collapse; min-width: 480px; }
.bl-inv-table th, .bl-inv-table td {
  padding: var(--cw-s4) var(--cw-s5); text-align: left;
  border-bottom: 1px solid var(--cw-border); vertical-align: middle;
}
.bl-inv-table thead th {
  font: var(--cw-micro); letter-spacing: .04em; text-transform: uppercase;
  color: var(--cw-text-faint); background: var(--cw-surface-2); white-space: nowrap;
}
.bl-inv-table tbody tr:last-child td { border-bottom: 0; }
.bl-inv-title { font: 500 14px/20px var(--cw-font); color: var(--cw-ink); }
.bl-inv-date { font: var(--cw-micro); color: var(--cw-text-soft); margin-top: 2px; }
/* The number people scan for: right-aligned so digits line up column-wise.
   MUST out-specify `.bl-inv-table th, .bl-inv-table td { text-align: left }`
   above — a bare `.bl-inv-amount` loses to it and the column silently goes
   back to ragged-left, which is the whole reason to use tabular figures. */
.bl-inv-table th.bl-inv-amount,
.bl-inv-table td.bl-inv-amount {
  text-align: right; white-space: nowrap;
}
.bl-inv-table td.bl-inv-amount {
  font: 600 14px/20px var(--cw-font); color: var(--cw-ink);
  font-variant-numeric: tabular-nums;
}
.bl-inv-table th.bl-inv-link, .bl-inv-table td.bl-inv-link { text-align: right; }
.bl-inv-status {
  display: inline-flex; align-items: center; padding: 2px 9px;
  border-radius: var(--cw-r-full); border: 1px solid var(--cw-border);
  font: var(--cw-micro); background: var(--cw-surface-2); color: var(--cw-text-soft);
  white-space: nowrap;
}
.bl-inv-ok     { background: var(--cw-ok-bg);     border-color: var(--cw-ok-border);     color: var(--cw-ok); }
.bl-inv-warn   { background: var(--cw-warn-bg);   border-color: var(--cw-warn-border);   color: var(--cw-warn); }
.bl-inv-danger { background: var(--cw-danger-bg); border-color: var(--cw-danger-border); color: var(--cw-danger); }
.bl-inv-link { white-space: nowrap; }
.bl-inv-link a { font: 500 13px/20px var(--cw-font); color: var(--cw-accent); text-decoration: none; }
.bl-inv-link a:hover { text-decoration: underline; }
.bl-inv-none { color: var(--cw-text-faint); }

@media (max-width: 860px) {
  .bl-head { flex-direction: column; align-items: stretch; }
  .bl-head .cw-btn { width: 100%; }
  .bl-free { padding: var(--cw-s5); }
  .bl-free-title { font: 700 24px/30px var(--cw-font); }
  .bl-subs { grid-template-columns: 1fr; }
  .bl-sub-actions .cw-btn { flex: 1 1 auto; }
}

/* ══ Launch experience (L1–L4) ═════════════════════════════════════════════
   Creating a site should feel like a product, not an admin form. Weight comes
   from scale and restraint — no gradients, no glass. Motion is short and
   purposeful, and every animation here is inside a transition the user
   initiated, so prefers-reduced-motion (tokens.css) neutralises all of it. */

/* ── L4: compact hero ───────────────────────────────────── */
.ls-hero {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--cw-s6); flex-wrap: wrap; margin-bottom: var(--cw-s6);
}
.ls-hero-copy { min-width: 0; }
.ls-hero-title {
  font: 700 30px/36px var(--cw-font); color: var(--cw-ink);
  letter-spacing: -.02em; margin: 0;
}
.ls-hero-sub { font: var(--cw-body); color: var(--cw-text-soft); margin: var(--cw-s2) 0 0; }
.ls-hero-actions { display: flex; gap: var(--cw-s3); flex-wrap: wrap; }

.ls-start {
  display: flex; align-items: center; gap: var(--cw-s3); text-align: left;
  min-width: 260px; padding: var(--cw-s4) var(--cw-s5);
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-lg); cursor: pointer;
  transition: transform var(--cw-t-micro), box-shadow var(--cw-t-micro), border-color var(--cw-t-micro);
}
.ls-start:hover { transform: translateY(-2px); box-shadow: var(--cw-e2); border-color: var(--cw-accent); }
.ls-start:active { transform: translateY(0); }
.ls-start:focus-visible { outline: 2px solid var(--cw-accent); outline-offset: 2px; }
.ls-start-icon {
  width: 36px; height: 36px; border-radius: var(--cw-r-md); flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--cw-accent-subtle); color: var(--cw-accent);
  transition: background var(--cw-t-micro), color var(--cw-t-micro);
}
.ls-start:hover .ls-start-icon { background: var(--cw-accent); color: var(--cw-accent-ink); }
.ls-start-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ls-start-title { font: 600 14px/20px var(--cw-font); color: var(--cw-ink); }
.ls-start-desc { font: var(--cw-micro); color: var(--cw-text-soft); }

.ls-library-title { font: var(--cw-title); color: var(--cw-ink); margin: 0 0 var(--cw-s1); }
.ls-library-sub { font: var(--cw-small); color: var(--cw-text-soft); margin: 0 0 var(--cw-s5); }

/* Column count follows the CONTAINER, not the viewport. dashboard.css keyed
   its breakpoints off viewport width (4 columns above 1600px), but the grid
   never gets the viewport — the sidebar and page padding take ~300px first.
   A 1920px laptop therefore rendered 4 columns into ~1150px of space, giving
   cards too narrow to hold their own hover buttons (see .ls-library below).
   auto-fill + a real minimum can't drift out of sync with the layout. */
.ls-library .sites-templates-grid {
  /* min(330px, 100%) — NOT a bare 330px. A bare minimum is a floor the track
     cannot go below, so on a 375px phone the card renders 330px wide inside a
     ~327px column and pushes the whole page sideways. min() lets the track
     collapse to the container when the container is the smaller of the two. */
  grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr));
  gap: var(--cw-s5);
}

/* The hover actions overflowed both edges of a narrow card — two pill buttons
   with `white-space: nowrap` and 22px of padding each simply don't fit, and
   flex let them spill rather than shrink. That produced the "one button off
   each edge with a gap in the middle" look. Wrapping + inset padding means
   they sit side by side when there's room and stack when there isn't. */
.ls-library .cwp-templates-explore-hover-overlay {
  flex-wrap: wrap; padding: 0 var(--cw-s4); align-content: center;
}
.ls-library .cwp-templates-explore-preview-btn,
.ls-library .cwp-templates-explore-create-btn {
  padding: 0 18px; max-width: 100%; height: 40px; font-size: 14px;
}

/* ── L4: category chips ─────────────────────────────────── */
/* WRAP on anything desktop-sized. A single scrolling line hid the 11th
   category off the right edge on a laptop with no visible affordance that it
   was there — horizontal scroll is discoverable on touch, invisible on a
   trackpad. Only the mobile rule below opts into scrolling. */
.ls-chips {
  display: flex; gap: var(--cw-s2); flex-wrap: wrap;
  margin-bottom: var(--cw-s5);
  /* The :hover lift is 1px. `overflow-x: auto` forces overflow-y to compute to
     auto too, so without room above, the lifted chip's top border is sliced
     off by the scroll container. This padding IS the fix — don't remove it. */
  padding: 2px 0 var(--cw-s2);
}
.ls-chip {
  flex: none; padding: 7px 14px; border-radius: var(--cw-r-full);
  border: 1px solid var(--cw-border); background: var(--cw-surface);
  font: 500 13px/18px var(--cw-font); color: var(--cw-text); cursor: pointer;
  white-space: nowrap;
  transition: background var(--cw-t-micro), color var(--cw-t-micro),
              border-color var(--cw-t-micro), transform var(--cw-t-micro);
}
.ls-chip:hover { border-color: var(--cw-accent); color: var(--cw-accent); transform: translateY(-1px); }
.ls-chip:focus-visible { outline: 2px solid var(--cw-accent); outline-offset: 2px; }
.ls-chip.is-active {
  background: var(--cw-accent); border-color: var(--cw-accent);
  color: var(--cw-accent-ink); transform: none;
}
.ls-chip.is-active:hover { background: var(--cw-accent-hover); color: var(--cw-accent-ink); }

/* ── L1: site name + address ────────────────────────────── */
.ls-field-label {
  display: block; font: var(--cw-micro); color: var(--cw-text-soft);
  margin-bottom: var(--cw-s2);
}
.ls-addr {
  margin-top: var(--cw-s4); padding: var(--cw-s4);
  background: var(--cw-surface-2); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-md);
}
.ls-addr-label { font: var(--cw-micro); color: var(--cw-text-faint); margin-bottom: 2px; }
.ls-addr-value {
  font-family: var(--cw-font-mono); font-size: 15px; line-height: 24px;
  color: var(--cw-ink); word-break: break-all;
}
.ls-addr-value .tpl-sdpre-suffix { color: var(--cw-text-soft); }

.ls-status {
  display: flex; align-items: baseline; gap: var(--cw-s2); flex-wrap: wrap;
  margin-top: var(--cw-s3); min-height: 20px;
}
.ls-status-main { font: 600 13px/20px var(--cw-font); }
.ls-status-detail { font: var(--cw-micro); color: var(--cw-text-soft); }
.ls-status.available .ls-status-main { color: var(--cw-ok); }
.ls-status.taken     .ls-status-main { color: var(--cw-danger); }
.ls-status.checking  .ls-status-main { color: var(--cw-text-soft); }
.ls-ic {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%; font-size: 11px; font-weight: 700;
  align-self: center;
}
.ls-ic-ok { background: var(--cw-ok-bg); color: var(--cw-ok); }
.ls-ic-no { background: var(--cw-danger-bg); color: var(--cw-danger); }
.ls-spin {
  width: 14px; height: 14px; border-radius: 50%; align-self: center;
  border: 2px solid var(--cw-border-strong); border-top-color: var(--cw-accent);
  animation: ls-spin .7s linear infinite;
}
@keyframes ls-spin { to { transform: rotate(360deg); } }
.ls-continue:disabled { opacity: .5; cursor: not-allowed; }

/* ── L2: plan cards ─────────────────────────────────────── */
/* Two columns inside a 560px modal, not four cramped ones. Four cards at
   ~120px each were unreadable AND made the step so tall that the Continue
   button fell below the modal's scroll line.
   With three tiers the last one would orphan into a half-empty row, so it
   spans instead — the leftover gap read as a missing fourth plan. */
.ls-plans {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--cw-s3); align-items: stretch;
}
.ls-plans > .ls-plan:last-child:nth-child(odd) { grid-column: 1 / -1; }
/* Spanning gives the row real width, so its features read across rather than
   stacking into a narrow column. */
.ls-plans > .ls-plan:last-child:nth-child(odd) .ls-plan-feats {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2px var(--cw-s4);
}
.ls-plan {
  position: relative; display: flex; flex-direction: column; gap: var(--cw-s2);
  text-align: left; padding: var(--cw-s4); cursor: pointer;
  background: var(--cw-surface); border: 1px solid var(--cw-border);
  border-radius: var(--cw-r-lg);
  transition: transform var(--cw-t-micro), box-shadow var(--cw-t-micro), border-color var(--cw-t-micro);
}
.ls-plan:hover:not(:disabled) { transform: translateY(-2px); box-shadow: var(--cw-e1); border-color: var(--cw-border-strong); }
.ls-plan:focus-visible { outline: 2px solid var(--cw-accent); outline-offset: 2px; }
.ls-plan.selected {
  border-color: var(--cw-accent); box-shadow: 0 0 0 1px var(--cw-accent) inset;
  background: var(--cw-accent-subtle);
}
.ls-plan.cs-plan-row-disabled, .ls-plan:disabled {
  opacity: .5; cursor: not-allowed; transform: none; box-shadow: none;
}
.ls-plan-rec { border-color: var(--cw-accent-border); }
.ls-plan-badge {
  position: absolute; top: -9px; left: var(--cw-s4);
  padding: 2px 9px; border-radius: var(--cw-r-full);
  background: var(--cw-accent); color: var(--cw-accent-ink);
  font: var(--cw-micro); letter-spacing: .02em;
}
.ls-plan-head { display: flex; flex-direction: column; gap: 2px; }
.ls-plan-name { font: 600 13px/18px var(--cw-font); color: var(--cw-ink); }
.ls-plan-price {
  font: 700 20px/26px var(--cw-font); color: var(--cw-ink);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.ls-plan-per { font: var(--cw-micro); color: var(--cw-text-soft); margin-left: 3px; font-weight: 500; }
.ls-plan-feats { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.ls-plan-feat {
  position: relative; padding-left: 16px;
  font: 400 11.5px/17px var(--cw-font); color: var(--cw-text);
}
.ls-plan-feat::before {
  content: '✓'; position: absolute; left: 0; top: 0;
  color: var(--cw-ok); font-weight: 700;
}
.ls-plan-feat-no { color: var(--cw-text-faint); }
.ls-plan-feat-no::before { content: '–'; color: var(--cw-text-faint); }
.ls-plan-note {
  font: 400 11px/15px var(--cw-font); color: var(--cw-text-soft);
  padding-top: var(--cw-s2); border-top: 1px solid var(--cw-border);
}

/* The only way forward must never be the thing you have to hunt for. The modal
   body scrolls (max-height: 85vh), so the plan step's actions stick to its
   bottom instead of sliding off the end of the card grid.
   bottom MUST be 0, not a negative value: a sticky offset is the THRESHOLD at
   which the element pins, not a margin. `bottom: -32px` pinned the button 32px
   BELOW the container's bottom edge — permanently out of sight, which is
   exactly how the Continue action went missing. */
#cs-step-plan .btn-primary,
#cs-step-plan .cs-pay-methods {
  position: sticky; bottom: 0; z-index: 2;
  padding-bottom: var(--cw-s2);
}
/* NO background on the button. `#cs-step-plan .btn-primary` is (1,1,0) and
   beats `.btn-primary` (0,1,0), so a backdrop declared here repaints the CTA
   itself — the purple button rendered in the surface colour, i.e. a white bar
   on a white modal that looked like no button at all. The button is already
   opaque; it needs no backdrop of its own.
   .cs-pay-methods IS a bare container, so it keeps one to stop cards showing
   through the gaps between its buttons. */
#cs-step-plan .cs-pay-methods { background: var(--cw-surface); }
#cs-step-plan .btn-primary { margin-top: var(--cw-s4); }

/* ── L3: arrival ────────────────────────────────────────── */
.ls-done-top { text-align: center; }
.ls-done-mark {
  font-size: 46px; line-height: 1; margin-bottom: var(--cw-s3);
  animation: ls-pop .5s cubic-bezier(.34, 1.56, .64, 1) both;
}
@keyframes ls-pop {
  0%   { transform: scale(.4) rotate(-12deg); opacity: 0; }
  100% { transform: scale(1) rotate(0); opacity: 1; }
}
.ls-done-title { font: var(--cw-display); color: var(--cw-ink); margin: 0 0 var(--cw-s2); }
.ls-done-sub { font: var(--cw-small); color: var(--cw-text-soft); margin: 0 0 var(--cw-s5); }

.ls-done-addr {
  display: flex; align-items: center; justify-content: space-between; gap: var(--cw-s3);
  padding: var(--cw-s4); background: var(--cw-surface-2);
  border: 1px solid var(--cw-border); border-radius: var(--cw-r-md);
  margin-bottom: var(--cw-s4);
}
.ls-done-url {
  font-family: var(--cw-font-mono); font-size: 14px; color: var(--cw-ink);
  text-decoration: none; word-break: break-all; min-width: 0;
}
.ls-done-url:hover { color: var(--cw-accent); text-decoration: underline; }
.ls-copy {
  flex: none; background: none; border: 1px solid var(--cw-border-strong);
  border-radius: var(--cw-r-sm); padding: 5px 10px; cursor: pointer;
  font: var(--cw-micro); color: var(--cw-text);
  transition: border-color var(--cw-t-micro), color var(--cw-t-micro);
}
.ls-copy:hover { border-color: var(--cw-accent); color: var(--cw-accent); }

.ls-done-actions { display: flex; flex-wrap: wrap; gap: var(--cw-s2); margin-bottom: var(--cw-s6); }
.ls-btn-primary, .ls-btn-secondary {
  flex: 1 1 auto; text-align: center; text-decoration: none;
  padding: 10px var(--cw-s4); border-radius: var(--cw-r-md);
  font: 600 13px/20px var(--cw-font); cursor: pointer;
  transition: background var(--cw-t-micro), border-color var(--cw-t-micro), transform var(--cw-t-micro);
}
.ls-btn-primary { background: var(--cw-accent); color: var(--cw-accent-ink); border: 1px solid var(--cw-accent); }
.ls-btn-primary:hover { background: var(--cw-accent-hover); transform: translateY(-1px); }
.ls-btn-secondary { background: var(--cw-surface); color: var(--cw-ink); border: 1px solid var(--cw-border-strong); }
.ls-btn-secondary:hover { border-color: var(--cw-ink); transform: translateY(-1px); }

.ls-next { border-top: 1px solid var(--cw-border); padding-top: var(--cw-s5); }
.ls-next-title {
  font: var(--cw-micro); letter-spacing: .08em; text-transform: uppercase;
  color: var(--cw-text-faint); margin-bottom: var(--cw-s3);
}
.ls-next-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--cw-s1); }
.ls-next-item a {
  display: block; padding: var(--cw-s3); border-radius: var(--cw-r-md);
  text-decoration: none; transition: background var(--cw-t-micro);
}
.ls-next-item a:hover { background: var(--cw-surface-2); }
.ls-next-item a:focus-visible { outline: 2px solid var(--cw-accent); outline-offset: -2px; }
.ls-next-item-title { display: block; font: 600 13px/20px var(--cw-font); color: var(--cw-ink); }
.ls-next-item-text { display: block; font: var(--cw-micro); color: var(--cw-text-soft); }

.ls-done-foot { display: flex; gap: var(--cw-s2); margin-top: var(--cw-s5); }

@media (max-width: 720px) {
  /* Mobile keeps the single scrolling strip — swiping a chip row is natural on
     touch, and wrapping 12 chips would eat half the screen. */
  .ls-chips {
    flex-wrap: nowrap; overflow-x: auto;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .ls-chips::-webkit-scrollbar { display: none; }

  .ls-hero { flex-direction: column; align-items: stretch; }
  .ls-hero-title { font: 700 24px/30px var(--cw-font); }
  .ls-hero-actions { flex-direction: column; }
  .ls-start { min-width: 0; width: 100%; }
  .ls-plans { grid-template-columns: 1fr; }
  .ls-done-actions, .ls-done-foot { flex-direction: column; }
}

/* ══ Dark mode: legacy hardcoded surfaces (K3) ═════════════════════════════
   tokens.css remaps every VARIABLE for dark, but dashboard.css also contains
   ~80 literal hex values that no variable can reach. Those are what produced
   a dark app with white template cards, a white notification panel and white
   pagination. Overridden here because console.css loads last.

   Scope is deliberate: only surfaces and text. Brand accents, status tints and
   the traffic-light dots keep their literals — they read correctly on dark and
   are meant to be constant. */

html[data-theme="dark"] {
  /* Template library */
  --cwp-dk-surface: #17171F;
  --cwp-dk-raise:   #1E1E29;
  --cwp-dk-border:  #262632;
  --cwp-dk-ink:     #F4F4F9;
}

html[data-theme="dark"] .tpl-browser .cwp-templates-explore-card-header { background: var(--cwp-dk-raise); }
html[data-theme="dark"] .tpl-browser .cwp-templates-explore-card { background: var(--cwp-dk-surface); border-color: var(--cwp-dk-border); }
html[data-theme="dark"] .tpl-browser .cwp-card-tag-category { background: var(--cwp-dk-surface); color: var(--cwp-dk-ink); }
html[data-theme="dark"] .tpl-browser .cwp-card-title,
html[data-theme="dark"] .tpl-browser .cwp-card-demo { color: var(--cwp-dk-ink); }
html[data-theme="dark"] .tpl-browser .cwp-templates-explore-create-btn { background: var(--cwp-dk-surface); color: #9B8DF9; }
html[data-theme="dark"] .tpl-browser .cwp-templates-explore-create-btn:hover { background: var(--cwp-dk-raise); }
html[data-theme="dark"] .tpl-browser .cwp-templates-explore-search-box input {
  background: var(--cwp-dk-raise); border-color: var(--cwp-dk-border); color: var(--cwp-dk-ink);
}
html[data-theme="dark"] .tpl-browser .cwp-page-arrow,
html[data-theme="dark"] .tpl-browser .cwp-page-number {
  background: var(--cwp-dk-surface); border-color: var(--cwp-dk-border); color: var(--cwp-dk-ink);
}
html[data-theme="dark"] .tpl-browser .cwp-page-number.active {
  background: #7C6BF7; border-color: #7C6BF7; color: #fff;
}

/* Notification bell + slide-over panel */
html[data-theme="dark"] .notif-bell { background: var(--cwp-dk-surface); border-color: var(--cwp-dk-border); color: var(--cwp-dk-ink); }
html[data-theme="dark"] .notif-panel { background: var(--cwp-dk-surface); border-color: var(--cwp-dk-border); color: var(--cwp-dk-ink); }
html[data-theme="dark"] .notif-item.unread { background: #1E1B3A; }
html[data-theme="dark"] .notif-banner { background: var(--cwp-dk-raise); border-color: var(--cwp-dk-border); color: var(--cwp-dk-ink); }
html[data-theme="dark"] .notif-banner[data-sev="warn"]   { background: #2A2213; border-color: #4A3A1A; }
html[data-theme="dark"] .notif-banner[data-sev="danger"] { background: #2B1618; border-color: #4A2226; }
html[data-theme="dark"] .notif-banner[data-sev="info"]   { background: #1E1B3A; border-color: #332E63; }

/* Status pills that pair a light tint with dark text — unreadable inverted. */
html[data-theme="dark"] .bk-badge.ok      { background: #10281E; color: #34D399; }
html[data-theme="dark"] .bk-badge.pending { background: #1E1B3A; color: #9B8DF9; }

/* Support form controls (signup.css literals). */
html[data-theme="dark"] .support-radio { background: var(--cwp-dk-surface); }

/* Intro-pricing line on a plan card. The customer must never have to work out
   when the price changes — the transition is stated on the card itself. */
.pl-up-intro {
  font: var(--cw-micro); color: var(--cw-text-soft);
  margin-top: var(--cw-s2); line-height: 16px;
}
.pl-up-intro strong { color: var(--cw-ink); font-weight: 600; }

/* ── First run: an account with no sites (K4) ─────────────────
   Not a dashboard with the numbers missing — a starting point. */
.ov-first { max-width: 720px; }
.ov-first-sub {
  font: var(--cw-body); color: var(--cw-text-soft);
  margin: var(--cw-s3) 0 var(--cw-s6); max-width: 60ch;
}
.ov-first-actions { display: flex; gap: var(--cw-s3); flex-wrap: wrap; margin-bottom: var(--cw-s7); }
.ov-first-card { padding: var(--cw-s6); }
.ov-first-card-title {
  font: var(--cw-micro); letter-spacing: .08em; text-transform: uppercase;
  color: var(--cw-text-faint); margin-bottom: var(--cw-s4);
}
.ov-first-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--cw-s3); }
.ov-first-list li {
  position: relative; padding-left: 22px;
  font: var(--cw-small); color: var(--cw-text-soft);
}
.ov-first-list li::before {
  content: '✓'; position: absolute; left: 0; top: 0;
  color: var(--cw-ok); font-weight: 700; font-size: 12px; line-height: 20px;
}
.ov-first-list strong { color: var(--cw-ink); font-weight: 600; }
.ov-first-foot {
  font: var(--cw-micro); color: var(--cw-text-faint);
  margin-top: var(--cw-s5); padding-top: var(--cw-s4);
  border-top: 1px solid var(--cw-border);
}
@media (max-width: 720px) { .ov-first-actions .cw-btn { flex: 1 1 auto; } }

/* Storage: measurement pending. A spinner beside the label, never a meter —
   we draw no bar for a number we do not have. */
.pl-measuring { display: inline-flex; align-items: center; gap: var(--cw-s2); }
.pl-measuring .ls-spin { width: 11px; height: 11px; border-width: 2px; }

/* Introductory terms under the plan price. Secondary weight: it explains the
   headline rate, it does not compete with it. */
.pl-hero-intro {
  font: var(--cw-small); color: var(--cw-text-soft);
  margin: calc(var(--cw-s2) * -1) 0 var(--cw-s3);
}

/* Next-step banner in the plan hero. Accent-tinted so it reads as guidance,
   not as an error — the customer has done nothing wrong, there is simply one
   more step. Sits between the infrastructure facts and the actions. */
.pl-next {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--cw-s5); flex-wrap: wrap;
  margin-top: var(--cw-s5); padding: var(--cw-s4) var(--cw-s5);
  background: var(--cw-accent-subtle);
  border: 1px solid var(--cw-accent-border);
  border-radius: var(--cw-r-md);
}
.pl-next-body { min-width: 0; flex: 1 1 320px; }
.pl-next-title { font: 600 14px/20px var(--cw-font); color: var(--cw-ink); }
.pl-next-text {
  font: var(--cw-small); color: var(--cw-text-soft);
  margin-top: 2px; max-width: 62ch;
}
.pl-next .cw-btn { flex: none; }
@media (max-width: 720px) {
  .pl-next { flex-direction: column; align-items: stretch; }
  .pl-next .cw-btn { width: 100%; }
}

/* ── shared utilities ─────────────────────────────────────────────────────
   Visually hidden, still announced. For labels whose visual role is played by
   a placeholder or an icon.

   This lived in agency/assets/css/app.css, which meant the client portal used
   `cw-skip-label` and rendered the label in plain sight — the class simply did
   not exist on that page. A `cw-` name is a promise that the primitive is
   shared; it now is.                                                        */
.cw-skip-label {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
