/* ============================================================================
   @verseva/design · components.css
   The component contract rendered as CSS. Framework-light: plain classes on
   the tokens; no build step required. Values are extracted VERBATIM from the
   design board's specimen CSS (board/index.html renders every class below in
   every contract state). Renames from board-only specimen names are noted
   inline; specimen scaffolding (device frames, state simulators' wrappers)
   is not shipped.

   Contract floor (docs/component-contract.md): all states shipped, 2px
   focus-visible ring, ≥44px touch targets, 4.5:1 labels / 3:1 parts, never
   color-alone, motion on transform/opacity via the duration/easing tokens.
   ========================================================================= */

/* ---- Button ---- */
.btn{
  appearance:none;border:0;cursor:pointer;font-family:var(--font-sans);
  font-weight:var(--btn-weight);font-size:.9375rem;line-height:1;
  height:40px;padding:0 var(--s-4);border-radius:var(--r-btn);
  display:inline-flex;align-items:center;gap:var(--s-2);
  transition:background var(--dur-1) var(--ease-standard),color var(--dur-1) var(--ease-standard),transform var(--dur-1) var(--ease-standard),box-shadow var(--dur-1) var(--ease-standard);
}
.btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--bg),0 0 0 4px var(--focus)}
.btn-primary{background:var(--accent-fill,var(--accent));color:var(--accent-ink)}
.btn-primary:hover{background:var(--accent-fill-hover,var(--accent-hover))}
.btn-secondary{background:var(--surface);border:1px solid var(--hairline);color:var(--text-1)}
.btn-secondary:hover{background:var(--surface-2)}
.btn-ghost{background:transparent;color:var(--text-1)}
.btn-ghost:hover{background:var(--surface-2)}
.btn-destructive{background:var(--danger-bg);color:var(--danger);border:1px solid transparent}
.btn-destructive:hover{border-color:var(--danger)}
.btn.sm{height:32px;padding:0 var(--s-3);font-size:.875rem}
.btn.lg{height:48px;padding:0 var(--s-5);font-size:1rem}
.btn.icon{width:40px;padding:0;justify-content:center}
.btn.sm.icon{width:32px}
.btn:active{transform:translateY(1px)}
.btn:disabled,.btn.is-disabled{opacity:.45;cursor:not-allowed}
.spinner{width:14px;height:14px;border-radius:50%;border:2px solid currentColor;border-right-color:transparent;animation:dc-spin .7s linear infinite}
@keyframes dc-spin{to{transform:rotate(360deg)}}

/* ---- Input / field ---- */
.field{display:grid;gap:var(--s-2)}
.field label{font-size:.875rem;font-weight:500}
.field input{
  height:40px;padding:0 var(--s-3);border-radius:var(--r-sm);
  border:1px solid var(--hairline);background:var(--surface);color:var(--text-1);
  font:inherit;font-size:.9375rem;
  transition:border-color var(--dur-1) var(--ease-standard),box-shadow var(--dur-1) var(--ease-standard);
}
.field input::placeholder{color:var(--text-3)}
.field input:focus-visible{outline:none;border-color:var(--focus);box-shadow:0 0 0 3px color-mix(in srgb,var(--focus) 25%,transparent)}
.field .help{font-size:.75rem;color:var(--text-3)}
.field.error input{border-color:var(--danger)}
.field.error .help{color:var(--danger)}
.field input:disabled{background:var(--surface-2);color:var(--text-3);cursor:not-allowed}

/* ---- Selection controls ---- */
.sel{display:flex;align-items:center;gap:var(--s-2);font-size:.9375rem;cursor:pointer}
.sel input{accent-color:var(--accent);width:18px;height:18px}
.switch{position:relative;width:40px;height:22px;border-radius:var(--r-pill);background:var(--surface-2);border:1px solid var(--hairline);transition:background var(--dur-2) var(--ease-standard)}
.switch::after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--text-2);transition:transform var(--dur-2) var(--ease-standard),background var(--dur-2) var(--ease-standard)}
.sel input:checked+.switch{background:var(--accent);border-color:transparent}
.sel input:checked+.switch::after{transform:translateX(18px);background:var(--accent-ink)}
.sel input.sw{position:absolute;opacity:0;width:40px;height:22px;margin:0;cursor:pointer}
.sel.switch-wrap{position:relative}
.sel input.sw:focus-visible+.switch{box-shadow:0 0 0 2px var(--bg),0 0 0 4px var(--focus)}

/* ---- Card (board name: .card-demo; specimen max-width dropped) ---- */
.card{border:1px solid var(--hairline);border-radius:var(--r-md);background:var(--surface);box-shadow:var(--e-1);overflow:hidden}
.card .hd{padding:var(--s-4) var(--s-5);border-bottom:1px solid var(--hairline)}
.card .hd h4{font-size:1rem;font-weight:600}
.card .bd{padding:var(--s-5);color:var(--text-2);font-size:.9375rem}
.card .ft{padding:var(--s-3) var(--s-5);border-top:1px solid var(--hairline);display:flex;justify-content:flex-end;gap:var(--s-2)}

/* ---- Top navigation bar (board name: .nav-demo) ---- */
.topnav{border:1px solid var(--hairline);border-radius:var(--r-md);background:var(--surface);display:flex;align-items:center;gap:var(--s-5);padding:0 var(--s-5);height:60px}
.topnav nav{display:flex;gap:var(--s-4);flex:1}
.topnav nav a{text-decoration:none;font-size:.9375rem;color:var(--text-2)}
.topnav nav a.active{color:var(--text-1);font-weight:600;border-bottom:2px solid var(--accent);padding-bottom:2px}

/* ---- Table (board name: .table-demo) ---- */
.table{width:100%;border-collapse:collapse;font-size:.9375rem}
.table th{text-align:left;font-family:var(--font-mono);font-size:.6875rem;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--text-3);padding:var(--s-3) var(--s-3);border-bottom:1px solid var(--hairline)}
.table td{padding:var(--s-3);border-bottom:1px solid var(--hairline)}
.table tr:hover td{background:var(--surface-2)}
.table .num{text-align:right;font-variant-numeric:tabular-nums}
.table th.num{text-align:right}

/* ---- Badge / status chip (always paired with text, never a dot alone) ---- */
.badge{display:inline-flex;align-items:center;gap:6px;font-size:.75rem;font-weight:500;letter-spacing:.01em;padding:3px 10px;border-radius:var(--r-pill)}
.badge svg{width:10px;height:10px}
.badge.ok{color:var(--success);background:var(--success-bg)}
.badge.warn{color:var(--warn);background:var(--warn-bg)}
.badge.err{color:var(--danger);background:var(--danger-bg)}
.badge.neutral{color:var(--text-2);background:var(--surface-2)}

/* ---- Toast ---- */
.toast{display:flex;align-items:center;gap:var(--s-3);max-width:360px;background:var(--surface-2);border:1px solid var(--hairline);border-radius:var(--r-md);box-shadow:var(--e-2);padding:var(--s-3) var(--s-4);font-size:.875rem}
.toast .dot{width:8px;height:8px;border-radius:50%;flex:0 0 auto}
.toast.ok .dot{background:var(--success)}
.toast.err .dot{background:var(--danger)}
.toast button{margin-left:auto;background:none;border:0;color:var(--text-3);cursor:pointer;font-size:1rem;line-height:1}

/* ---- Modal / dialog (board name: .modal-demo; overlay is the consumer's) ---- */
.modal{width:min(100%,420px);background:var(--surface);border:1px solid var(--hairline);border-radius:var(--r-lg);box-shadow:var(--e-3);overflow:hidden}
.modal .bd{padding:var(--s-5)}
.modal h4{font-size:1.2rem;font-weight:600;margin-bottom:var(--s-2)}
.modal p{color:var(--text-2);font-size:.9375rem}
.modal .ft{padding:var(--s-4) var(--s-5);border-top:1px solid var(--hairline);display:flex;justify-content:flex-end;gap:var(--s-2)}

/* ---- Skeleton (loading state; skeletons mirror real layout) ---- */
.skel{height:10px;border-radius:4px;background:var(--surface-2);width:100%;position:relative;overflow:hidden}
.skel::after{content:"";position:absolute;inset:0;transform:translateX(-100%);background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--text-1) 7%,transparent),transparent);animation:dc-shimmer 1.4s var(--ease-standard) infinite}
@keyframes dc-shimmer{to{transform:translateX(100%)}}

/* ---- Segmented control ---- */
.seg{display:inline-flex;background:var(--surface-2);border:1px solid var(--hairline);border-radius:var(--r-pill);padding:3px;gap:2px}
.seg button{border:0;background:transparent;color:var(--text-2);font:inherit;font-size:.875rem;padding:7px 16px;border-radius:var(--r-pill);cursor:pointer;transition:background var(--dur-1) var(--ease-standard),color var(--dur-1) var(--ease-standard)}
.seg button[aria-selected="true"]{background:var(--surface);color:var(--text-1);font-weight:600;box-shadow:var(--e-1)}
.seg button:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}

/* ---- Filter chip row ---- */
.chiprow{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.fchip{display:inline-flex;align-items:center;gap:6px;font-size:.8125rem;padding:6px 12px;border-radius:var(--r-pill);border:1px solid var(--hairline);background:var(--surface);color:var(--text-2);cursor:pointer;transition:all var(--dur-1) var(--ease-standard)}
.fchip[aria-pressed="true"]{background:color-mix(in srgb,var(--accent) 14%,transparent);border-color:color-mix(in srgb,var(--accent) 36%,transparent);color:var(--text-1);font-weight:600}
.fchip .cnt{font-family:var(--font-mono);font-size:10px;color:var(--text-3)}
.fchip:focus-visible{outline:2px solid var(--focus);outline-offset:2px}

/* ---- Search field ---- */
.searchbox{display:flex;align-items:center;gap:8px;background:var(--surface);border:1px solid var(--hairline);border-radius:var(--r-sm);padding:8px 12px;color:var(--text-3);font-size:.875rem;max-width:300px}
.searchbox svg{width:15px;height:15px;flex:none}
.searchbox input{border:0;background:transparent;color:var(--text-1);font:inherit;outline:none;flex:1;min-width:0}
.searchbox kbd{font-family:var(--font-mono);font-size:10px;border:1px solid var(--hairline);border-radius:5px;padding:2px 6px;background:var(--surface-2);color:var(--text-3)}

/* ---- List rows + identity ---- */
.lrows{border:1px solid var(--hairline);border-radius:var(--r-md);overflow:hidden;background:var(--surface)}
.lrow{display:flex;align-items:center;gap:12px;padding:11px 14px;border-bottom:1px solid var(--hairline);transition:background var(--dur-1) var(--ease-standard)}
.lrow:last-child{border-bottom:0}
.lrow:hover{background:var(--surface-2)}
.avc{width:28px;height:28px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;background:var(--surface-2);border:1px solid var(--hairline);color:var(--text-2)}
.lrow .tx{flex:1;min-width:0}
.lrow .tx b{display:block;font-size:.9375rem;font-weight:600;color:var(--text-1)}
.metaline{font-size:12px;color:var(--text-3)}
.lrow .val{font-variant-numeric:tabular-nums;font-weight:600;font-size:.875rem}
.avstack{display:flex;padding-left:8px}
.avstack .avc{margin-left:-8px;border:2px solid var(--surface)}

/* ---- Sheet (mobile bottom sheet; board name: .sheet-demo) ---- */
.sheet{width:min(100%,340px);background:var(--surface);border:1px solid var(--hairline);border-radius:26px 26px var(--r-md) var(--r-md);box-shadow:var(--e-3);overflow:hidden}
.sheet .grab{width:36px;height:4px;border-radius:999px;background:var(--text-3);opacity:.4;margin:10px auto 4px}
.sheet .bd{padding:var(--s-4) var(--s-5) var(--s-5)}
.sheet h4{font-size:1.05rem;font-weight:600;margin-bottom:4px}
.sheet p{font-size:.875rem;color:var(--text-2)}
.sheet .ft{display:flex;gap:var(--s-2);padding:0 var(--s-5) var(--s-5)}
.sheet .ft .btn{flex:1;justify-content:center}

/* ---- NAVSHELL v2 (amended 2026-08-31, operator ruling: "so long and it
   does not make sense"). SINGLE tier, equal-width tabs, labels ALWAYS
   visible, constant height: the nav is the most stable object on screen.
   The frosted container + inset pill + mode-specific tier brightness stay
   (nav-tier-brightness law): LIGHT frame recessed grey / pill bright white;
   DARK inverted. Sub-sections of a tab NEVER stack a second tier on the
   shell: they live at the top of the tab's own content as a .seg or .fchip
   row. Deployment: position:fixed, insets 14px sides / 18px bottom.
   (v1's two-tier .navsub + active flex-growth are retired; the historical
   port source remains ufitra-experience.html, superseded by this ruling.) ---- */
.navshell{position:fixed;left:14px;right:14px;bottom:18px;z-index:14;display:flex;flex-direction:column;
  padding:var(--nav-gap);
  background:linear-gradient(var(--nav-frame),var(--nav-frame)), var(--glass-fill-3);
  backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));-webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
  border:1px solid var(--glass-border);border-radius:30px;box-shadow:var(--glass-shadow), var(--glass-glow), var(--glass-inset);overflow:hidden}
.navmain{position:relative;height:56px;display:flex;padding:6px 8px;background:var(--surface-body), var(--nav-main);
  border:1px solid var(--glass-border);border-radius:24px;box-shadow:var(--nav-pill-inset)}
.tab{flex:1 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;color:var(--text-3);cursor:pointer;border-radius:16px;padding:0 4px;transition:color var(--dur-2) var(--ease-standard), background var(--dur-2) var(--ease-standard), box-shadow var(--dur-2) var(--ease-standard);position:relative;min-width:44px}
.tab svg{width:20px;height:20px;transition:color var(--dur-2) var(--ease-standard);flex:none}
.tab span{font-size:10px;font-weight:700;letter-spacing:.01em;line-height:1.2}
.tab.on{color:var(--accent-on);background:var(--accent-bloom);box-shadow:var(--accent-active-glow)}
.tab.on svg{color:var(--accent-on);filter:drop-shadow(0 0 8px color-mix(in srgb,var(--accent) 50%,transparent))}
.tab:not(.on):hover{color:var(--text-2)}
.tab:active{transform:scale(.94)}
/* Mobile-only. Unlayered on purpose: a component class that sets display and
   ships unlayered cannot be hidden by a layered utility (md:hidden), so the
   responsive rule lives here, next to the rule it guards (case law 2026-07-18). */
@media (min-width:768px){.navshell{display:none}}

/* ---- Console navigation (desktop sidebar patterns) ---- */
.orgchip{display:flex;align-items:center;gap:9px;padding:8px;border:1px solid var(--hairline);border-radius:12px;background:var(--surface)}
.orgchip .sq{width:26px;height:26px;border-radius:8px;background:var(--accent-fill,var(--accent));color:var(--accent-ink);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:800;flex:none}
.orgchip b{display:block;font-size:.8125rem;line-height:1.2}
.orgchip small{display:block;font-size:10px;color:var(--text-3)}
.grouplabel{font-family:var(--font-mono);font-size:.625rem;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--text-3);margin:2px 0 6px}
/* Accordion console-nav variant (mechanics ported 1:1 from Spectre's rail):
   collapse = the HTML hidden attribute on .snav, never a height animation;
   the ONLY motion is the chevron. Doctrine: the group holding the active
   item is always forced open, and everything starts open for a new visitor.
   Persist a SHUT set (not open) so later-added groups default open. */
.sgroup{margin-top:var(--s-3)}
.sgroup-head{display:flex;align-items:center;gap:6px;width:100%;padding:0;margin:0 0 6px;border:0;background:none;cursor:pointer;text-align:left;color:inherit}
.sgroup-head .grouplabel{flex:1;margin:0}
.sgroup-head:hover .grouplabel{color:var(--text-2)}
.sgroup-head:focus-visible{outline:2px solid var(--focus);outline-offset:2px;border-radius:var(--r-sm)}
.sgroup-chev{flex:none;color:var(--text-3);transition:transform var(--dur-1) var(--ease-standard)}
.sgroup[data-open="false"] .sgroup-chev{transform:rotate(-90deg)}
@media (prefers-reduced-motion:reduce){.sgroup-chev{transition:none}}
.snav{display:grid;gap:2px}
.snav a{position:relative;display:flex;align-items:center;gap:9px;padding:7px 9px;border-radius:10px;font-size:.8125rem;color:var(--text-2);text-decoration:none;transition:background var(--dur-1) var(--ease-standard)}
.snav a:hover{background:var(--surface-2)}
.snav a svg{width:15px;height:15px;color:var(--text-3);flex:none}
.snav a.active{color:var(--text-1);background:color-mix(in srgb,var(--accent) 14%,transparent);font-weight:600;box-shadow:0 0 18px -6px color-mix(in srgb,var(--accent) 45%,transparent)}
.snav a.active svg{color:var(--accent)}
.snav .cnt{margin-left:auto;font-size:10px;font-family:var(--font-mono);background:var(--surface-2);border:1px solid var(--hairline);border-radius:999px;padding:1px 6px;color:var(--text-2)}

/* ---- Stat tile / KPI ---- */
.statrow{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:var(--s-4)}
.stat{border:1px solid var(--hairline);border-radius:var(--r-md);background:var(--surface);padding:var(--s-4);box-shadow:var(--e-1)}
.stat .num{font-family:var(--font-display);font-weight:var(--display-weight);font-size:2.1rem;line-height:1.05;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.stat .num i{color:var(--accent);font-style:normal}
.stat .lbl{font-size:.75rem;color:var(--text-3);margin-top:2px}
.stat .delta{margin-top:8px}

/* ---- Charts (takeaway captions are mandatory: label the meaning) ---- */
.chartcard{border:1px solid var(--hairline);border-radius:var(--r-md);background:var(--surface);padding:var(--s-4);box-shadow:var(--e-1)}
.chartcard h4{font-size:.9375rem;font-weight:600}
.chartcard .sub{font-size:.75rem;color:var(--text-3);margin-bottom:12px}
.takeaway{margin-top:12px;font-size:.8125rem;color:var(--text-2);border-top:1px solid var(--hairline);padding-top:9px}
.bars{display:flex;align-items:flex-end;gap:8px;height:130px;border-bottom:1px solid var(--chart-grid,var(--hairline));padding:0 2px}
.bar{flex:1;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;gap:4px;height:100%;cursor:default}
.bar .fill{width:100%;max-width:34px;background:var(--data-3,var(--accent));border-radius:4px 4px 0 0;transition:opacity var(--dur-1) var(--ease-standard)}
.bar:hover .fill{opacity:.82}
.bar .mlab{font-family:var(--font-mono);font-size:10px;color:var(--chart-label,var(--text-3))}
.bar .vlab{font-family:var(--font-mono);font-size:10px;color:var(--text-2)}
.heat{display:grid;grid-template-columns:repeat(14,1fr);gap:3px}
.heat span{aspect-ratio:1;border-radius:5px;background:var(--data-0);cursor:default}
.heat span.d1{background:var(--data-1)}
.heat span.d2{background:var(--data-2)}
.heat span.d3{background:var(--data-3)}
.heatlegend{display:flex;align-items:center;gap:5px;margin-top:10px;font-family:var(--font-mono);font-size:10px;color:var(--text-3)}
.heatlegend span{width:12px;height:12px;border-radius:4px;display:inline-block}

/* ---- Field extensions: select + textarea (same contract as input) ---- */
.field select,.field textarea{padding:0 var(--s-3);border-radius:var(--r-sm);border:1px solid var(--hairline);background:var(--surface);color:var(--text-1);font:inherit;font-size:.9375rem;transition:border-color var(--dur-1) var(--ease-standard),box-shadow var(--dur-1) var(--ease-standard)}
.field select{height:40px}
.field textarea{min-height:96px;padding:var(--s-3);resize:vertical;line-height:1.5}
.field select:focus-visible,.field textarea:focus-visible{outline:none;border-color:var(--focus);box-shadow:0 0 0 3px color-mix(in srgb,var(--focus) 25%,transparent)}
.field.error select,.field.error textarea{border-color:var(--danger)}

/* ---- Tab bar (in-page sections; the underline is accent, never a hairline) ---- */
.tabbar{display:flex;gap:var(--s-4);border-bottom:1px solid var(--hairline)}
.tabbar button{border:0;background:none;color:var(--text-2);font:inherit;font-size:13.5px;font-weight:500;padding:var(--s-2) 2px;cursor:pointer;transition:color var(--dur-1) var(--ease-standard)}
.tabbar button:hover{color:var(--text-1)}
.tabbar [aria-selected="true"]{color:var(--text-1);font-weight:600;box-shadow:inset 0 -2px 0 var(--accent)}
.tabbar button:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}

/* ---- Menu (dropdown) ---- */
.menu{position:relative;display:inline-block}
.menu-list{position:absolute;top:calc(100% + 6px);left:0;min-width:180px;background:var(--surface);border:1px solid var(--hairline);border-radius:var(--r-md);box-shadow:var(--e-2);padding:6px;display:grid;gap:2px;z-index:15}
.menu-list[hidden]{display:none}
.menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;border-radius:var(--r-sm);border:0;background:none;color:var(--text-1);font:inherit;font-size:13.5px;text-align:left;cursor:pointer}
.menu-item:hover{background:var(--surface-2)}
.menu-item:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
.menu-item.danger{color:var(--danger)}
.menu-sep{height:1px;background:var(--hairline);margin:4px 6px}

/* ---- Tooltip (inverse ground; keep the text short, it is not a doc).
   WCAG 1.4.13: hoverable (pointer-events restored while shown), dismissible
   (Escape via the react binding's .tiphide). ---- */
.tip{position:relative;display:inline-flex}
.tip .tipbox{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);background:var(--text-1);color:var(--bg);padding:5px 10px;border-radius:var(--r-sm);font-size:12px;line-height:1.4;width:max-content;max-width:220px;text-align:center;opacity:0;pointer-events:none;transition:opacity var(--dur-1) var(--ease-standard);z-index:15}
.tip:hover .tipbox,.tip:focus-within .tipbox{opacity:1;pointer-events:auto}
.tip .tipbox.tiphide{opacity:0;pointer-events:none}

/* ---- Breadcrumbs ---- */
.crumbs{display:flex;align-items:center;gap:var(--s-2);font-size:12.5px;color:var(--text-3)}
.crumbs a{color:var(--text-2);text-decoration:none}
.crumbs a:hover{color:var(--text-1)}
.crumbs [aria-current="page"]{color:var(--text-1);font-weight:600}

/* ---- Pagination ---- */
.pager{display:inline-flex;gap:4px;align-items:center}
.pager button{min-width:32px;height:32px;padding:0 6px;border-radius:var(--r-sm);border:0;background:none;color:var(--text-2);font:inherit;font-size:13px;cursor:pointer;font-variant-numeric:tabular-nums}
.pager button:hover{background:var(--surface-2)}
.pager [aria-current="page"]{background:color-mix(in srgb,var(--accent) 14%,transparent);color:var(--text-1);font-weight:600}
.pager button:disabled{opacity:.4;cursor:default;background:none}

/* ---- Progress (pair with a real number; never color-alone) ---- */
.progress{height:6px;border-radius:var(--r-pill);background:var(--surface-2);border:1px solid var(--hairline-soft);overflow:hidden}
.progress .fill{height:100%;background:var(--accent);border-radius:4px;transition:width var(--dur-3) var(--ease-standard)}

/* ---- Callout (status text on tints clears 4.5:1; the word leads) ---- */
.callout{display:flex;gap:var(--s-3);padding:var(--s-4) var(--s-5);border-radius:var(--r-md);font-size:13.5px;background:var(--surface);border:1px solid var(--hairline);color:var(--text-2)}
.callout b{color:var(--text-1);font-weight:600}
.callout.ok{background:var(--success-bg);border-color:transparent;color:var(--success)}
.callout.warn{background:var(--warn-bg);border-color:transparent;color:var(--warn)}
.callout.err{background:var(--danger-bg);border-color:transparent;color:var(--danger)}
.callout.ok b,.callout.warn b,.callout.err b{color:inherit}

/* ---- Empty state ---- */
.empty{display:grid;justify-items:center;gap:var(--s-3);padding:var(--s-7) var(--s-5);text-align:center;border:1px dashed var(--hairline-strong);border-radius:var(--r-lg);color:var(--text-2);font-size:13.5px}
.empty b{color:var(--text-1);font-family:var(--font-display);font-weight:var(--heading-weight);font-size:16px}

/* ---- Content accordion (native details; promoted from the storefront) ---- */
.acc{border:1px solid var(--hairline);border-radius:var(--r-md);background:var(--surface);overflow:hidden}
.acc details + details{border-top:1px solid var(--hairline)}
.acc summary{list-style:none;cursor:pointer;display:flex;justify-content:space-between;align-items:center;gap:var(--s-3);padding:var(--s-3) var(--s-4);font-weight:600;font-size:14px}
.acc summary::-webkit-details-marker{display:none}
.acc summary::after{content:"+";color:var(--text-3)}
.acc details[open] summary::after{content:"\2013"}
.acc .accbody{padding:0 var(--s-4) var(--s-4);color:var(--text-2);font-size:13.5px}

/* ---- Data-viz kit (synthesized 2026-08-31 from the portfolio's shipped
   viz: Spectre, the NEMIXO console, the UFITRA reference mockups).
   Doctrine carried in the classes: numbers ON the marks (no gridline
   forests; an axis is one hairline at most), denominator-first stats,
   deltas colored by MEANING not sign, one magnitude hue + the fixed
   --data-alt second series, identity never color-alone. ---- */

/* Stat micro-bar: a 4px proportional bar under a stat numeral */
.stat .microbar{height:4px;border-radius:2px;background:var(--surface-2);margin-top:8px;overflow:hidden}
.stat .microbar i{display:block;height:100%;border-radius:2px;background:var(--data-3)}

/* Trend delta: direction is the arrow, judgment is the class */
.trend{display:inline-flex;align-items:center;gap:4px;font-size:12px;font-weight:600;font-variant-numeric:tabular-nums}
.trend.good{color:var(--success)}
.trend.bad{color:var(--danger)}
.trend.flat{color:var(--text-3)}

/* Horizontal bar rows: label / track / mono count (axis-free) */
.hbars{display:grid;gap:8px}
.hbar{display:flex;align-items:center;gap:var(--s-3);font-size:12.5px}
.hbar .hlabel{width:88px;flex:none;color:var(--text-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hbar .htrack{height:8px;min-width:0;flex:1;border-radius:var(--r-pill);background:var(--surface-2);overflow:hidden}
.hbar .htrack i{display:block;height:100%;border-radius:var(--r-pill);background:var(--data-3)}
.hbar .htrack i.alt{background:var(--data-alt)}
.hbar .hcount{width:40px;flex:none;text-align:right;font-family:var(--font-mono);font-size:11.5px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--text-1)}

/* Activity strip + calendar cells: ONE intensity language via the ladder */
.actstrip{display:grid;grid-auto-flow:column;gap:4px}
.actstrip i,.actcal i{aspect-ratio:1;border-radius:4px;background:var(--data-0)}
.actcal{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}
.actstrip i[data-l="1"],.actcal i[data-l="1"]{background:var(--data-1)}
.actstrip i[data-l="2"],.actcal i[data-l="2"]{background:var(--data-2)}
.actstrip i[data-l="3"],.actcal i[data-l="3"]{background:var(--data-3)}
.actstrip i.today,.actcal i.today{box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 28%,transparent)}

/* Ring (the UFITRA pattern): rotate the svg, number inside the dial, label BELOW it
   (the label can be wider than the dial's clear center, so it never lives inside) */
.ring{display:inline-flex;flex-direction:column;align-items:center;gap:6px}
.ring .rdial{position:relative;display:inline-grid;place-items:center}
.ring .rdial svg{display:block;transform:rotate(-90deg)}
.ring .ringtrack{fill:none;stroke:var(--data-0);stroke-width:6}
.ring .ringfill{fill:none;stroke:var(--data-3);stroke-width:6;stroke-linecap:round;transition:stroke-dashoffset var(--dur-4) var(--ease-standard)}
.ring .rv{position:absolute;inset:0;display:grid;place-items:center;text-align:center}
.ring .rv b{font-family:var(--font-display);font-weight:var(--display-weight);font-variant-numeric:tabular-nums;font-size:18px;line-height:1}
.ring .rlbl{font-family:var(--font-mono);font-size:9.5px;color:var(--text-3);letter-spacing:.04em}

/* Mini state strip (the gate-squares pattern): word+glyph carried in title/aria */
.markstrip{display:inline-flex;gap:3px}
.markstrip i{width:7px;height:7px;border-radius:2px;background:var(--surface-2);border:1px solid var(--hairline-strong)}
.markstrip i.cleared{background:var(--success-bg);border-color:var(--success)}
.markstrip i.current{background:var(--data-3);border-color:transparent}
.markstrip i.attention{background:var(--danger-bg);border-color:var(--danger)}

/* Chart furniture: reference line, target band, legend, spark wrapper */
.spark{height:40px}
.spark svg,.vizplot svg{display:block;width:100%;height:100%}
.vizplot{position:relative}
.refline{stroke:var(--text-3);stroke-width:1;stroke-dasharray:2 3;opacity:.7}
.reftag{position:absolute;right:0;transform:translateY(-50%);font-family:var(--font-mono);font-size:9.5px;font-weight:600;letter-spacing:.04em;color:var(--text-3);background:var(--surface);border:1px solid var(--hairline);border-radius:6px;padding:2px 6px}
.vizlegend{display:flex;gap:var(--s-4);flex-wrap:wrap;font-size:11.5px;color:var(--text-2)}
.vizlegend i{display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--data-3);vertical-align:baseline}
.vizlegend i.alt{background:var(--data-alt)}
.xlabels{display:flex;justify-content:space-between;font-family:var(--font-mono);font-size:9.5px;color:var(--chart-label)}
.viztip{position:absolute;top:0;right:0;display:grid;gap:2px;background:var(--surface);border:1px solid var(--hairline);border-radius:var(--r-sm);box-shadow:var(--e-2);padding:6px 10px;font-size:11.5px;color:var(--text-2);pointer-events:none;z-index:5}
.viztip b{font-family:var(--font-mono);font-size:10px;color:var(--text-3);font-weight:600}
.viztip span{font-variant-numeric:tabular-nums;color:var(--text-1)}

/* ---- Spacing utilities (the seam law's handrail). Rhythm stays at class
   level, and these ARE classes: mt-5 means margin-top: var(--s-5), straight
   off the scale, so a seam is never left to memory. Vertical + gap only;
   horizontal rhythm comes from layout (flex/grid), not margins. ---- */
.mt-1{margin-top:var(--s-1)}.mt-2{margin-top:var(--s-2)}.mt-3{margin-top:var(--s-3)}.mt-4{margin-top:var(--s-4)}.mt-5{margin-top:var(--s-5)}.mt-6{margin-top:var(--s-6)}.mt-7{margin-top:var(--s-7)}.mt-8{margin-top:var(--s-8)}.mt-9{margin-top:var(--s-9)}
.mb-1{margin-bottom:var(--s-1)}.mb-2{margin-bottom:var(--s-2)}.mb-3{margin-bottom:var(--s-3)}.mb-4{margin-bottom:var(--s-4)}.mb-5{margin-bottom:var(--s-5)}.mb-6{margin-bottom:var(--s-6)}.mb-7{margin-bottom:var(--s-7)}.mb-8{margin-bottom:var(--s-8)}.mb-9{margin-bottom:var(--s-9)}
.pt-1{padding-top:var(--s-1)}.pt-2{padding-top:var(--s-2)}.pt-3{padding-top:var(--s-3)}.pt-4{padding-top:var(--s-4)}.pt-5{padding-top:var(--s-5)}.pt-6{padding-top:var(--s-6)}.pt-7{padding-top:var(--s-7)}.pt-8{padding-top:var(--s-8)}.pt-9{padding-top:var(--s-9)}
.pb-1{padding-bottom:var(--s-1)}.pb-2{padding-bottom:var(--s-2)}.pb-3{padding-bottom:var(--s-3)}.pb-4{padding-bottom:var(--s-4)}.pb-5{padding-bottom:var(--s-5)}.pb-6{padding-bottom:var(--s-6)}.pb-7{padding-bottom:var(--s-7)}.pb-8{padding-bottom:var(--s-8)}.pb-9{padding-bottom:var(--s-9)}
.gap-1{gap:var(--s-1)}.gap-2{gap:var(--s-2)}.gap-3{gap:var(--s-3)}.gap-4{gap:var(--s-4)}.gap-5{gap:var(--s-5)}.gap-6{gap:var(--s-6)}.gap-7{gap:var(--s-7)}

/* ---- Motion kit (the doctrine in classes)
   Enter on --ease-entrance, leave for good on --ease-exit, settle direct
   manipulation on --ease-back. Attention is finite (pulse, hold, fade).
   1.4s is the house loop period; ambient loops (beam, marquee) never sit
   on data surfaces. Sanctioned non-transform channels, each earned:
   outline/box-shadow (.attn), grid fr tracks (.grow-*), mask-only paints. */

/* Entrance: fade + 10px rise; .mo-st staggers children 60ms apart, capped at 6 */
.mo-rise{animation:dc-rise var(--dur-3) var(--ease-entrance) backwards}
.mo-st>*{animation:dc-rise var(--dur-3) var(--ease-entrance) backwards}
.mo-st>*:nth-child(2){animation-delay:60ms}
.mo-st>*:nth-child(3){animation-delay:120ms}
.mo-st>*:nth-child(4){animation-delay:180ms}
.mo-st>*:nth-child(5){animation-delay:240ms}
.mo-st>*:nth-child(n+6){animation-delay:300ms}
@keyframes dc-rise{from{opacity:0;transform:translateY(10px)}}

/* Masked line reveal: transitions (interruptible), never keyframes; add .in to run */
.mo-lines>span{display:block;overflow:hidden}
.mo-lines>span>span{display:block;transition:transform var(--dur-4) var(--ease-entrance)}
.js .mo-lines>span>span{transform:translateY(110%)}
.js .mo-lines.in>span>span{transform:translateY(0)}
.mo-lines>span:nth-child(2)>span{transition-delay:70ms}
.mo-lines>span:nth-child(3)>span{transition-delay:140ms}
.mo-lines>span:nth-child(4)>span{transition-delay:210ms}

/* Spotlight: JS writes --mx/--my on pointermove; all the light lives here */
.spot{position:relative}
.spot::after{content:"";position:absolute;inset:0;border-radius:inherit;background:radial-gradient(320px circle at var(--mx,50%) var(--my,50%),color-mix(in srgb,var(--accent) 10%,transparent),transparent 65%);opacity:0;transition:opacity var(--dur-3) var(--ease-standard);pointer-events:none}
.spot:hover::after,.spot.lit::after{opacity:1}
@media (hover:none){.spot::after{display:none}}

/* Border beam (ambient): conic accent on a ring mask; mask colors are alpha-only */
@property --dc-angle{syntax:"<angle>";inherits:false;initial-value:0deg}
.beam{position:relative}
.beam::before{content:"";position:absolute;inset:-1px;border-radius:inherit;padding:1px;background:conic-gradient(from var(--dc-angle),transparent 0 72%,var(--accent) 92%,transparent 100%);-webkit-mask:linear-gradient(black 0 0) content-box,linear-gradient(black 0 0);-webkit-mask-composite:xor;mask:linear-gradient(black 0 0) content-box,linear-gradient(black 0 0);mask-composite:exclude;animation:dc-beam 4s linear infinite;pointer-events:none}
@keyframes dc-beam{to{--dc-angle:360deg}}

/* Rolling number: digit columns travel on transform; edges fade under a mask */
.ticker{display:inline-flex;overflow:hidden;line-height:1;font-variant-numeric:tabular-nums;mask-image:linear-gradient(transparent,black 22%,black 78%,transparent);-webkit-mask-image:linear-gradient(transparent,black 22%,black 78%,transparent)}
.ticker .td{display:block;height:1em;transform:translateY(calc(var(--d,0)*-1em));transition:transform var(--dur-4) var(--ease-emph)}
.ticker .td i{font-style:normal;display:block;height:1em}

/* Sequenced text swap (the Spectre stamp idiom): out fully, THEN in, by delay flip */
.xswap{display:inline-grid}
.xswap>span{grid-area:1/1;transition:opacity var(--dur-1) var(--ease-standard);white-space:nowrap}
.xswap .xa{transition-delay:var(--dur-1)}
.xswap .xb{opacity:0;transition-delay:0ms}
.xswap.on .xa{opacity:0;transition-delay:0ms}
.xswap.on .xb{opacity:1;transition-delay:var(--dur-1)}
@media (hover:hover){
  .xswap:hover .xa{opacity:0;transition-delay:0ms}
  .xswap:hover .xb{opacity:1;transition-delay:var(--dur-1)}
}

/* Attention ring (the console guide idiom): pulse twice, hold, fade; never persists.
   Beats sit above the interaction ladder, like the 1.4s loop period. */
.attn{outline:2px solid color-mix(in srgb,var(--accent) 60%,transparent);outline-offset:3px;scroll-margin-top:var(--attn-scroll,88px);animation:dc-attn 1.1s var(--ease-standard) 2,dc-attnoff 1.6s var(--ease-standard) 5s forwards}
@keyframes dc-attn{50%{outline-offset:6px;outline-color:color-mix(in srgb,var(--accent) 25%,transparent)}}
@keyframes dc-attnoff{to{outline-color:transparent}}

/* Height/width that must travel: fr tracks are the one sanctioned route.
   Disclosure chrome (accordion, nav groups) still snaps: chevron-only motion. */
.grow-y{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--dur-3) var(--ease-entrance)}
.grow-y>*{min-height:0;overflow:hidden;visibility:hidden;transition:visibility 0s linear var(--dur-3)}
.grow-y.open{grid-template-rows:1fr}
.grow-y.open>*{visibility:visible;transition-delay:0s}
.grow-x{display:grid;grid-template-columns:0fr;opacity:0;transition:grid-template-columns var(--dur-2) var(--ease-standard),opacity var(--dur-2) var(--ease-standard)}
.grow-x>*{min-width:0;overflow:hidden;white-space:nowrap}
.grow-x.open{grid-template-columns:1fr;opacity:1}

/* Marquee (ambient): two copies of the row make the loop seamless; hover pauses */
.marq{display:flex;overflow:hidden;mask-image:linear-gradient(90deg,transparent,black 8%,black 92%,transparent);-webkit-mask-image:linear-gradient(90deg,transparent,black 8%,black 92%,transparent)}
.marq .mrow{display:flex;align-items:center;gap:var(--s-6);padding-right:var(--s-6);flex:none;animation:dc-marq 22s linear infinite}
.marq:hover .mrow{animation-play-state:paused}
@keyframes dc-marq{to{transform:translateX(-100%)}}

/* Overlay choreography: scrim one beat faster than the panel; enter-only */
.ovl.open{animation:dc-fade var(--dur-1) var(--ease-standard)}
.modal{animation:dc-pop var(--dur-2) var(--ease-emph) backwards}
@keyframes dc-fade{from{opacity:0}}
@keyframes dc-pop{from{opacity:0;transform:translateY(6px) scale(.98)}}

/* Magnetic: JS moves it (no transition while tracking), settles on --ease-back */
.magnet{display:inline-block}

/* Visually hidden, still read: identity never rides on motion or color alone */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}

/* ---- Reduced motion (functional non-animated equivalents) ---- */
@media (prefers-reduced-motion:reduce){
  .skel::after{animation:none}
  .spinner{animation-duration:1.4s}
  .tab,.tab span,.btn,.switch,.switch::after{transition:none}
  .mo-rise,.mo-st>*,.beam::before,.marq .mrow,.ovl.open,.modal{animation:none}
  .js .mo-lines>span>span{transition:none;transform:none}
  .ticker .td,.spot::after,.xswap>span,.grow-y,.grow-x{transition:none}
  .attn{animation:dc-attnoff 1.6s var(--ease-standard) 5s forwards}
}
