/* cenovel.com: the Cenovel Systems look (owner, 2026-10-18), first built as direction A (Platinum, 2026-10-11). The
   shell and the components every page is built from, the documentation's shared bar, footer and colors included.
   Colors, sizes and motion come from tokens.css (the --cv-* names); nothing here sets a color literal except the
   faint white washes inside the always-dark Titanium band. Classes are unique to this file so the documentation's own
   stylesheets, loaded on docs pages, cannot collide with them. The Cenovel icon appears only as the brand (bar,
   footer, favicon); backgrounds are purpose-made line fields (fields/make-fields.py). */

/* ---------- Schibsted Grotesk, the site's text face (variable, 100–900), as it was before 2026-10-18: the owner kept it
   ("was already fine"). Public Sans belongs to the logo pack, whose lockups are outlined and need no font. ---------- */
@font-face{font-family:Schibsted;src:url('/assets/h/sans.4c8b93f431.woff2') format('woff2');font-weight:100 900;font-display:optional}

/* ---------- Base (site pages: body.cv) ---------- */
.cv,.cv *,.cv *::before,.cv *::after{box-sizing:border-box}
html{scrollbar-width:thin;scrollbar-color:var(--cv-line) transparent}
body.cv{margin:0;background:var(--cv-page);color:var(--cv-ink);font:400 var(--cv-fs-body)/1.6 var(--cv-font);-webkit-font-smoothing:antialiased}
:where(.cv) a{color:inherit;text-decoration:none}
:where(.cv) :is(button,input,textarea){font:inherit;color:inherit}
.cv :focus-visible{outline:2px solid var(--cv-blue);outline-offset:3px;border-radius:4px}
.cv h1,.cv h2,.cv h3,.cv h4{font-weight:500;margin:0;text-wrap:balance;color:var(--cv-ink)}
.cv h1{font-size:var(--cv-fs-display);line-height:1.07;letter-spacing:-.035em}
.cv h2{font-size:var(--cv-fs-section);line-height:1.15;letter-spacing:-.025em}
.cv h3{font-size:var(--cv-fs-card);line-height:1.35;letter-spacing:-.01em}
.cv h4{font-size:var(--cv-fs-small);line-height:1.4}
:where(.cv) p{margin:0}
:where(.cv) :is(strong,b){font-weight:500}
.cv code{font-family:var(--cv-mono);font-size:.875em;background:var(--cv-well);border:1px solid var(--cv-line-soft);border-radius:4px;padding:0 4px}
.cv-wrap{max-width:calc(var(--cv-container) + 2 * var(--cv-gutter));margin:0 auto;padding:0 var(--cv-gutter)}
.cv-skip{position:fixed;top:-100px;left:16px;z-index:30;background:var(--cv-card);color:var(--cv-ink);padding:10px 14px;border-radius:var(--cv-radius-sm);box-shadow:var(--cv-shadow-hover)}
.cv-skip:focus{top:12px}
.cv-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.cv-muted{color:var(--cv-muted)}
.cv-link{color:var(--cv-blue-text);font-size:var(--cv-fs-small);font-weight:400;display:inline-flex;gap:6px;align-items:center}
.cv-link:hover{text-decoration:underline;text-underline-offset:4px}
.cv-link span[aria-hidden]{transition:transform var(--cv-dur) var(--cv-ease)}
.cv-link:hover span[aria-hidden]{transform:translateX(2px)}
.cv-eyebrow{display:block;font-size:var(--cv-fs-meta);font-weight:500;color:var(--cv-blue-text);letter-spacing:.01em;margin-bottom:12px}

/* ---------- The scroll box and the header over it (owner, 2026-10-18). On desktop the page scrolls in .page-scroll
   (SITESCROLL, 2026-10-06), and the header lies over the top of it, so the page passes under the header (an opaque dark
   bar, below). In Chromium and Safari
   the scrollbar still starts below the header (a track margin); Firefox has no track margin, so there it runs the full
   height, under the header. The page's own anchors and the outline's links land clear of the header
   (scroll-padding-top). Phones scroll the document under the same fixed header. ---------- */
@media screen and (min-width:801px){
  body:is(.cv,.cv-docs){height:100vh;height:100dvh;display:block;overflow:hidden}
  body:is(.cv,.cv-docs)>.page-scroll{height:100%;overflow-y:auto;overflow-x:hidden;scrollbar-gutter:stable;outline:none;scrollbar-width:thin;scrollbar-color:var(--cv-line-strong) transparent;scroll-padding-top:calc(var(--cv-bar) + 16px)}
  html:has(body:is(.cv,.cv-docs)){scroll-padding-top:0}
  /* The footer always reaches the bottom of the window: a page shorter than the window grows its main, and a page that
     is only its head (the 404) grows the head, so no paper shows below the dark footer. */
  body:is(.cv,.cv-docs)>.page-scroll{display:flex;flex-direction:column}
  .page-scroll>main{flex:1 0 auto}
  .page-scroll>main:has(> :is(.cv-hero,.cv-subhero):last-child){display:flex;flex-direction:column}
  .page-scroll>main>:is(.cv-hero,.cv-subhero):last-child{flex:1 0 auto}
}
@supports selector(::-webkit-scrollbar){@media screen and (min-width:801px){
  body:is(.cv,.cv-docs)>:is(.page-scroll,.cv-bar){scrollbar-width:auto;scrollbar-color:auto}
  body:is(.cv,.cv-docs)>.page-scroll *{scrollbar-color:var(--cv-line-strong) transparent}
  body:is(.cv,.cv-docs)>:is(.page-scroll,.cv-bar)::-webkit-scrollbar{width:11px;background:transparent}
  body:is(.cv,.cv-docs)>.page-scroll::-webkit-scrollbar-track{background:transparent;margin-top:var(--cv-bar)}
  body:is(.cv,.cv-docs)>.page-scroll::-webkit-scrollbar-thumb{background:var(--cv-line-strong) padding-box;border:3px solid transparent;border-radius:6px;min-height:40px}
  body:is(.cv,.cv-docs)>.page-scroll::-webkit-scrollbar-thumb:hover{background-color:var(--cv-faint)}
}}
@media screen and (max-width:800px){html:has(body:is(.cv,.cv-docs)){scroll-padding-top:calc(var(--cv-bar) + 16px)}}
@media screen{.page-scroll>main{padding-top:var(--cv-bar)}.page-scroll>main>:is(.cv-hero,.cv-subhero):first-child{margin-top:calc(-1 * var(--cv-bar))}}
@media screen and (min-width:801px) and (prefers-reduced-motion:no-preference){body:is(.cv,.cv-docs)>.page-scroll{scroll-behavior:smooth}}
@media print{body:is(.cv,.cv-docs){height:auto;display:block;overflow:visible}body:is(.cv,.cv-docs)>.page-scroll{overflow:visible}.cv-bar{position:static}}

/* ---------- Buttons: website sized (44 px), the brand blue, a quiet outline for the second choice ---------- */
.cv-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:var(--cv-btn-h);padding:0 20px;border-radius:var(--cv-radius-sm);font-size:16px;font-weight:500;line-height:1.2;
  background:var(--cv-blue);color:var(--cv-on-blue);border:1px solid var(--cv-blue);cursor:pointer;white-space:nowrap;
  transition:transform 220ms var(--cv-ease-spring),background-color var(--cv-dur) var(--cv-ease),border-color var(--cv-dur) var(--cv-ease),color var(--cv-dur) var(--cv-ease)}
.cv-btn:hover{background:var(--cv-blue-hover);border-color:var(--cv-blue-hover)}
.cv-btn:active{transform:translateY(1px)}
.cv-btn:focus-visible{outline:2px solid var(--cv-blue);outline-offset:3px;border-radius:var(--cv-radius-sm)}
.cv-btn.ghost{background:transparent;color:var(--cv-ink);border-color:var(--cv-line-strong)}
.cv-btn.ghost:hover{background:var(--cv-glass-lift);border-color:var(--cv-ink)}
.cv-btn.sm{min-height:40px;padding:0 16px;font-size:15px}
.cv-btn[disabled],.cv-btn[aria-disabled="true"]{opacity:.6;cursor:default}
.cv-actions{display:flex;flex-wrap:wrap;gap:12px 16px;align-items:center}

/* ---------- The header: a simple site header (owner, 2026-10-18) on a dark titanium bar (2026-10-19). The lockup, the
   four links with the underline hover, a search button and Portal. At the top of a page the bar is solid, with a
   hairline at its foot: over a page head it reads as the top of that head, and over paper (a page without a head) it
   lifts on a soft shadow, so the step from the dark bar to the paper is drawn, not cut. Once the page scrolls
   (platinum.js sets .cv-scrolled on <html>, only when the state changes) it turns to dark glass with a backdrop blur
   and keeps the shadow, so the page shows softly through it (owner, 2026-10-18; restored 2026-10-19). The glass is
   opaque enough that its words hold AA over white paper, the worst case under it. The blur itself never transitions
   (it repainted on every scroll frame); only the color eases. Firefox, which redraws a backdrop blur on every scroll
   frame (42 ms frames in testing), keeps the solid bar, as do browsers without backdrop-filter and visitors who reduce
   transparency. It reserves the same scrollbar gutter as the page under it (scrollbar-gutter on an overflow-hidden
   box), so with classic scrollbars the brand still lines up with the page column. ---------- */
.cv-bar{position:fixed;top:0;left:0;right:0;z-index:20;overflow:hidden;scrollbar-gutter:stable;scrollbar-width:thin;color:var(--cv-ink);
  background:var(--cv-bar-bg);border-bottom:1px solid var(--cv-bar-edge);box-shadow:none;
  transition:background-color 180ms var(--cv-ease),box-shadow 180ms var(--cv-ease)}
.cv-scrolled .cv-bar,body:not(:has(.cv-hero,.cv-subhero)) .cv-bar{box-shadow:var(--cv-header-shadow)}
.cv-scrolled .cv-bar{background:var(--cv-bar-glass);-webkit-backdrop-filter:saturate(1.5) blur(16px);backdrop-filter:saturate(1.5) blur(16px)}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){.cv-scrolled .cv-bar{background:var(--cv-bar-bg)}}
@supports (-moz-appearance:none){.cv-scrolled .cv-bar{background:var(--cv-bar-bg);-webkit-backdrop-filter:none;backdrop-filter:none}}
@media (prefers-reduced-transparency:reduce){.cv-scrolled .cv-bar{background:var(--cv-bar-bg);-webkit-backdrop-filter:none;backdrop-filter:none}}
.cv-scrolled .cv-bar:has(.cv-nav.open){background:var(--cv-bar-bg);-webkit-backdrop-filter:none;backdrop-filter:none}
/* The header and the footer carry their own words: light ink, a lighter blue and hairlines for the dark bar. */
:is(.cv-bar,.cv-foot){color-scheme:dark;--cv-ink:var(--cv-bar-ink);--cv-muted:var(--cv-bar-muted);--cv-faint:var(--cv-bar-muted);
  --cv-blue:var(--cv-bar-blue);--cv-blue-text:var(--cv-bar-blue-text);--cv-line:var(--cv-bar-line);--cv-line-soft:var(--cv-bar-line-soft);
  --cv-line-strong:var(--cv-bar-line-strong);--cv-glass-lift:var(--cv-bar-lift)}
@media (prefers-reduced-motion:reduce){.cv-bar{transition:none}}
.cv-bar :focus-visible{outline-color:var(--cv-blue)}
/* One column for the whole site (2026-10-19): the header, the footer, the documentation layout and every .cv-wrap page
   share --cv-container inside the gutter, so the logo stands on the page's left edge and Portal on its right. */
.cv-bar>.cv-wrap,.cv-foot>.cv-wrap{max-width:none;width:min(var(--cv-container),calc(100% - 2 * var(--cv-gutter)));padding:0}
body.cv-docs .wrap{width:min(var(--cv-container),calc(100% - 2 * var(--cv-gutter)))}
/* The sidebar's search box and selected row start on the column edge; focus rings draw inside, where the scroll box
   can't clip them. */
body.cv-docs .docs-nav{padding-left:0}
body.cv-docs .docs-nav :focus-visible{outline-offset:-2px}
.cv-bar-inner{position:relative;z-index:1;display:flex;align-items:center;gap:40px;height:var(--cv-bar)}
.cv-brand{display:inline-flex;align-items:center;flex:none}
/* The 08 icon lockup in white, 180 px wide in the header and the footer so SYSTEMS meets the pack's minimum size. */
.cv-brand img{display:block;height:auto}
.cv-brand img{width:180px}
.cv-nav{display:flex;align-items:center;flex:1;gap:24px;min-width:0}
.cv-nav-main{display:flex;gap:4px;font-size:16px}
.cv-nav-main a{position:relative;padding:8px 12px;color:var(--cv-ink);font-weight:500}
/* Hover is the underline alone (owner, 2026-10-18: "The hover should only be the outline"), no filled box. */
.cv-nav-main a[aria-current]{font-weight:500}
.cv-nav-side{margin-left:auto;display:flex;align-items:center;gap:8px;font-size:16px}
/* The search dialog (search.js): the bar's Search opens it on every page, and / or Ctrl+K (⌘K) anywhere. A command
   palette under the bar: one field, up to eight pages, the arrow keys move and Enter opens. */
.search-dialog{width:min(680px,calc(100% - 32px));max-height:min(640px,calc(100dvh - 96px));margin:calc(var(--cv-bar) + 16px) auto auto;padding:0;border:1px solid var(--cv-card-edge);border-radius:var(--cv-radius-lg);
  background:var(--cv-surface);color:var(--cv-ink);box-shadow:var(--cv-shadow);font:400 var(--cv-fs-body)/1.5 var(--cv-font)}
.search-dialog::backdrop{background:var(--cv-scrim)}
.search-dialog form{display:flex;align-items:center;gap:12px;padding:10px 12px 10px 16px;border-bottom:1px solid var(--cv-line)}
.search-dialog form svg{flex:none;color:var(--cv-muted)}
.search-dialog input{flex:1;min-width:0;min-height:40px;border:0;background:transparent;font:inherit;font-size:18px;color:var(--cv-ink);outline:none}
/* The field is the dialog's one control: focus shows as the blue rule under it, not a ring around it. */
.search-dialog input:focus-visible{outline:none}
.search-dialog form:focus-within{border-bottom-color:var(--cv-blue)}
.search-dialog .sd-close{flex:none;min-height:28px;padding:0 8px;background:var(--cv-control);border:1px solid var(--cv-line);border-radius:var(--cv-radius-sm);font:500 12px/1 var(--cv-font);color:var(--cv-muted);cursor:pointer}
.search-dialog .sd-close:hover{color:var(--cv-ink);background:var(--cv-glass-lift)}
.search-dialog .sd-status{margin:0;padding:10px 16px 0;font-size:13px;color:var(--cv-muted)}
.search-dialog ul{list-style:none;margin:0;padding:8px;overflow:auto;max-height:calc(min(640px,100dvh - 96px) - 120px)}
.search-dialog li a{display:block;padding:10px 12px;border-radius:var(--cv-radius-sm);color:inherit;text-decoration:none}
.search-dialog li a:hover{text-decoration:none;background:var(--cv-glass-lift)}
.search-dialog li[aria-selected=true] a{background:var(--cv-selected)}
.search-dialog li strong{display:block;font-size:16px;font-weight:500}
.search-dialog li .sd-path{display:block;font-size:13px;color:var(--cv-blue-text);margin-top:2px}
.search-dialog li small{display:block;margin-top:4px;color:var(--cv-muted);font-size:14px;line-height:1.5}
.search-dialog mark{background:var(--cv-blue-soft);color:inherit;padding:0 1px;border-radius:2px}
.search-dialog .sd-foot{display:flex;gap:16px;padding:10px 16px;border-top:1px solid var(--cv-line);font-size:13px;color:var(--cv-muted)}
@media (prefers-reduced-motion:no-preference){
  .search-dialog[open]{animation:cv-dialog-in 200ms var(--cv-ease-enter) both}
  .search-dialog li{animation:cv-settle 260ms var(--cv-ease-enter) both;animation-delay:calc(var(--i,0) * 30ms)}
  @keyframes cv-dialog-in{from{opacity:0;transform:translateY(-4px)}}
  @keyframes cv-settle{from{opacity:0;transform:translateY(4px)}}
}
/* The header link underline, back from the earlier site (2026-10-03, c4f1921c9 and 3cbfd85e9): a 2px line drawn in
   from the left under the word on hover and keyboard focus (180 ms in, 120 ms out), held under the current page.
   It spans the word, not the padding, and sits under the text so the target is unchanged. Transform only; under
   reduced motion it appears and disappears without the draw. Phone menu: the same line, under the word. */
.cv-nav-main a::after{content:"";position:absolute;left:12px;right:12px;top:calc(50% + .8em);height:2px;border-radius:1px;
  background:var(--cv-blue);opacity:1;transform:scaleX(0);transform-origin:left center;pointer-events:none;transition:transform 120ms var(--cv-ease)}
@media (hover:hover){.cv-nav-main a:hover::after{transform:scaleX(1);transition-duration:180ms}}
.cv-nav-main a:focus-visible::after{transform:scaleX(1);transition-duration:180ms}
.cv-nav-main a[aria-current]::after{transform:scaleX(1);opacity:1}
@media (prefers-reduced-motion:reduce){.cv-nav-main a::after{transition:none}}
/* Search, on every page: a button that opens the documentation search (search.js); / and Ctrl+K (⌘K) open it too.
   Its hover turns it blue, with no fill. */
.cv-search{display:inline-grid;place-items:center;width:44px;height:44px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--cv-ink);cursor:pointer;
  transition:color var(--cv-dur) var(--cv-ease)}
.cv-search:hover{color:var(--cv-blue-text)}
.cv-search:focus-visible{outline:2px solid var(--cv-blue);outline-offset:2px;border-radius:50%}
.cv-search svg{width:20px;height:20px}
html:not(.js) .cv-search{visibility:hidden}
/* Portal: a quiet outline; on hover the outline darkens, with no fill. */
.cv-portal{display:inline-flex;align-items:center;gap:8px;min-height:40px;padding:0 16px;border-radius:var(--cv-radius-sm);border:1px solid var(--cv-line-strong);background:transparent;
  color:var(--cv-ink);font-size:15px;font-weight:500;transition:border-color var(--cv-dur) var(--cv-ease)}
.cv-portal:hover{border-color:var(--cv-ink)}
.cv-portal svg{flex:none;opacity:.75}
.cv-bar .cv-btn,.cv-band .cv-btn{background:var(--cv-chrome-action);border-color:var(--cv-chrome-action);color:var(--cv-on-chrome-action)}
.cv-bar .cv-btn:hover,.cv-band .cv-btn:hover{background:var(--cv-chrome-action-hover);border-color:var(--cv-chrome-action-hover)}
.cv-menu{display:none;margin-left:auto;min-height:40px;padding:0 16px;border-radius:var(--cv-radius-sm);border:1px solid var(--cv-line-strong);background:transparent;color:var(--cv-ink);font-size:15px;font-weight:500;cursor:pointer}
@media (max-width:1023px){
  .cv-bar-inner{flex-wrap:wrap;height:auto;gap:0 12px}
  .cv-brand{min-height:var(--cv-bar)}
  .cv-menu{display:inline-flex;align-items:center}
  .cv-nav{display:none;flex-basis:100%;flex-direction:column;align-items:stretch;gap:12px;padding:4px 0 20px}
  .cv-nav.open{display:flex}
  .cv-nav-main{flex-direction:column;align-items:flex-start}
  .cv-nav-side{margin-left:0;flex-wrap:wrap}
}

/* ---------- Hero: a dark titanium tone and a line field (fields/make-fields.py): trunks, closets as racks, ports as dots.
   The words stay clear of the field (owner, 2026-10-18): it shows only beside the text column (a page head), in the
   margins of a two-column head (home, trust), or at the sides of a centered head (Live demo). A signal runs along
   the trunks once when the page opens, then the field rests.
   Painted for smooth scrolling (owner, 2026-10-18: "when you scroll back up, it isn't smooth and the page loads in
   blocks"): everything here is static content of the scroll box, so it is rasterized once and moves with the page on
   the compositor. The dark head ends on the paper in one clean edge (owner, 2026-10-19). The line field is a pre-colored SVG painted as a background
   image (build.py writes it), with one gradient mask for the side fade: no SVG mask, no composited masks, no fixed or
   anchored layer. The signal is the one SVG-masked layer, and only for its
   3.6 s run; then it is hidden and never painted again. ---------- */
.cv-hero,.cv-subhero{position:relative;isolation:isolate;background:var(--cv-hero);color:var(--cv-hero-ink);
  --cv-fade:linear-gradient(90deg,transparent calc(50% + 240px),black calc(50% + 460px))}
.cv-hero:has(.cv-hero-center){--cv-fade:linear-gradient(90deg,black,transparent 28%,transparent 72%,black)}
:is(.cv-hero,.cv-subhero):has(.cv-hero-copy){--cv-fade:linear-gradient(90deg,black,transparent calc(50% - 560px),transparent calc(50% + 560px),black)}
:is(.cv-hero,.cv-subhero)::before,:is(.cv-hero,.cv-subhero)::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none}
:root{--cv-field-art:url('/assets/h/field-network-dark.57e248e317.svg')}
body:has(#nf-title){--cv-field-art:url('/assets/h/field-silent-dark.f5a8054a75.svg')}
/* The field is clipped to the head, so the head ends on the paper in one clean edge; the side fade is its one mask. */
:is(.cv-hero,.cv-subhero)::before{background:var(--cv-field-art) right -60px top calc(var(--cv-bar) + 8px)/1560px 585px no-repeat;
  -webkit-mask:var(--cv-fade);mask:var(--cv-fade)}
:is(.cv-hero,.cv-subhero)::after{inset:0;visibility:hidden}
@media (prefers-reduced-motion:no-preference){
  :is(.cv-hero,.cv-subhero)::after{visibility:visible;background:linear-gradient(90deg,transparent,var(--cv-hero-pulse),transparent) -420px 0/420px 100% no-repeat;
    -webkit-mask:url('/assets/h/field-pulse.3903608bba.svg') right -60px top calc(var(--cv-bar) + 8px)/1560px 585px no-repeat,var(--cv-fade);-webkit-mask-composite:source-in;
    mask:url('/assets/h/field-pulse.3903608bba.svg') right -60px top calc(var(--cv-bar) + 8px)/1560px 585px no-repeat,var(--cv-fade);mask-composite:intersect;
    animation:cv-signal 3.6s cubic-bezier(.45,0,.25,1) .6s 1 both}
  @keyframes cv-signal{from{background-position:-420px 0}99.9%{visibility:visible}to{background-position:calc(100% + 420px) 0;visibility:hidden}}
  :is(.cv-hero,.cv-subhero)::before{animation:cv-field-in 1.2s var(--cv-ease-enter) both}
  @keyframes cv-field-in{from{opacity:0}}
  .cv-hero .cv-btn:hover{transform:translateY(-1px)}
}
/* The head paints its own tone, as ordinary content of the scroll box. A classic scrollbar's track beside it is the
   page's own column, in the page color: a scroll box's background never paints under its scrollbar in Chromium, so the
   tone could not reach there anyway (owner call, 2026-10-19; overlay scrollbars, the macOS default, have no track). */
.cv-hero :is(h1,h2),.cv-subhero :is(h1,h2){color:var(--cv-hero-ink)}
.cv-hero .cv-lead,.cv-subhero .cv-lead,:is(.cv-hero,.cv-subhero) :is(.cv-updated,.cv-fine){color:var(--cv-hero-muted)}
:is(.cv-hero,.cv-subhero) :is(.cv-eyebrow,.cv-crumb,.cv-crumb a){color:var(--cv-hero-label)}
:is(.cv-hero,.cv-subhero) .cv-actions .cv-btn:not(.ghost){background:var(--cv-hero-btn);border-color:var(--cv-hero-btn);color:var(--cv-hero-btn-ink)}
:is(.cv-hero,.cv-subhero) .cv-btn.ghost{background:transparent;color:var(--cv-hero-ink);border-color:var(--cv-hero-ghost-line)}
:is(.cv-hero,.cv-subhero) .cv-btn.ghost:hover{background:var(--cv-hero-lift);border-color:var(--cv-hero-ink)}
:is(.cv-hero,.cv-subhero) :focus-visible{outline-color:var(--cv-blue)}
/* The 404: the same field, one closet that does not answer. */
body:has(#nf-title) .cv-subhero{padding:calc(88px + var(--cv-bar)) 0 96px}
.cv-hero{padding:calc(72px + var(--cv-bar)) 0 96px}
/* A page head's room below its words matches the room above them: the head ends in a clean edge, with no fade to fill. */
.cv-subhero{padding:calc(56px + var(--cv-bar)) 0 56px}
.cv-hero-grid{display:grid;grid-template-columns:1fr 1.08fr;gap:56px;align-items:center}
.cv-lead{font-size:var(--cv-fs-lead);line-height:1.55;color:var(--cv-muted);margin-top:22px;max-width:34em}
.cv-subhero h1{font-size:var(--cv-fs-title);line-height:1.15}
.cv-subhero .cv-lead{max-width:36em;margin-top:20px}
.cv-hero .cv-actions,.cv-subhero .cv-actions{margin-top:30px}
.cv-fine{font-size:var(--cv-fs-meta);color:var(--cv-faint);margin-top:18px}
.cv-crumb{display:flex;gap:8px;font-size:var(--cv-fs-meta);font-weight:500;letter-spacing:.01em;color:var(--cv-muted);margin-bottom:16px}
.cv-crumb a{color:var(--cv-blue-text)}
.cv-crumb a:hover{text-decoration:underline;text-underline-offset:3px}

/* A product screen in a silver frame. */
.cv-frame{margin:0;position:relative;background:var(--cv-card);border-radius:var(--cv-radius-lg);padding:6px;border:1px solid var(--cv-card-edge);box-shadow:var(--cv-shadow)}
.cv-frame img{display:block;width:100%;height:auto;border-radius:var(--cv-radius-sm)}
.cv-frame figcaption,.cv-tour-cap{display:flex;justify-content:space-between;align-items:center;gap:16px;font-size:var(--cv-fs-meta);color:var(--cv-muted);padding:10px 6px 2px}
.cv-frame figcaption a{color:var(--cv-blue-text);font-weight:500;white-space:nowrap}
.cv-frame figcaption a:hover{text-decoration:underline;text-underline-offset:3px}
.cv-shot-crop{aspect-ratio:16/10;overflow:hidden;border-radius:var(--cv-radius-sm)}
.cv-shot-crop img{width:100%;height:100%;object-fit:cover;object-position:top left;border-radius:0}

/* The hero tour: three real screens, crossfaded every 6 s (platinum.js). Without JavaScript or with reduced motion
   it shows the first screen, and the buttons still pick one. */
.cv-tour{position:relative;aspect-ratio:16/10;overflow:hidden;border-radius:var(--cv-radius-sm);background:var(--cv-chrome-2)}
.cv-tour img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:top left;border-radius:0;opacity:0;transition:opacity var(--cv-dur) var(--cv-ease)}
.cv-tour img.on{opacity:1}
.cv-tour-dots{display:flex;gap:2px;align-items:center}
.cv-tour-dots button{width:22px;height:22px;padding:0;border:0;background:transparent;cursor:pointer;display:grid;place-items:center;border-radius:50%}
.cv-tour-dots button::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--cv-line);transition:background-color var(--cv-dur) var(--cv-ease)}
.cv-tour-dots button[aria-pressed="true"]::before{background:var(--cv-blue)}
.cv-tour-cap a{color:var(--cv-blue-text);font-weight:500}

/* ---------- Sections and their heads ---------- */
.cv-s{padding:96px 0}
.cv-s.flush{padding-top:8px}
.cv-s+.cv-s{border-top:1px solid var(--cv-line-soft)}
.cv-s.tight{padding:72px 0}
.cv-s-head{display:grid;grid-template-columns:1fr 1fr;gap:56px;margin-bottom:40px;align-items:end}
.cv-s-head p{color:var(--cv-muted);font-size:var(--cv-fs-lead);line-height:1.55}
.cv-s-head.solo{grid-template-columns:1fr}
.cv-s-foot{margin-top:24px}
.cv-note{margin-top:20px;font-size:var(--cv-fs-small);color:var(--cv-muted)}
.cv-g2,.cv-g3,.cv-g4{display:grid;gap:20px}
.cv-g2{grid-template-columns:repeat(2,minmax(0,1fr))}
.cv-g3{grid-template-columns:repeat(3,minmax(0,1fr))}
.cv-g4{grid-template-columns:repeat(4,minmax(0,1fr))}
.cv-list{list-style:none;margin:0;padding:0}

/* ---------- Open sections, and cards only where a whole block is a link (owner, 2026-10-18 evening). Content sits on
   the page with whitespace and hairlines; a link block (a door, a pillar, a tile) is an opaque card with a hairline that
   lifts on hover. Drawings sit on a quiet toned panel, not a card. One rule each, so a block cannot drift; components
   below set only their layout. ---------- */
:is(a.cv-card,.cv-card.is-link,.cv-pillar,.cv-tile){background:var(--cv-card);border:1px solid var(--cv-card-edge);border-radius:var(--cv-radius);box-shadow:var(--cv-card-shadow)}
:is(a.cv-card,.cv-card.is-link,.cv-pillar){transition:transform 260ms var(--cv-ease-spring),box-shadow var(--cv-dur) var(--cv-ease),border-color var(--cv-dur) var(--cv-ease)}
:is(a.cv-card,.cv-card.is-link,.cv-pillar):hover{transform:translateY(-2px);box-shadow:var(--cv-card-shadow-hover)}
.cv-card:not(a,.is-link){border-top:1px solid var(--cv-line);border-radius:0;padding:20px 0 0}
:is(.cv-facts,.cv-faq,.cv-ftable,.cv-table-wrap){border-top:1px solid var(--cv-line);border-bottom:1px solid var(--cv-line)}
.cv-drawing:not(.bare){background:var(--cv-page-low);border-radius:var(--cv-radius-lg)}
/* In the hero, a drawing or a screen sits on a near-opaque card so it reads over the blue. */
:is(.cv-hero,.cv-subhero) :is(.cv-drawing,.cv-frame){background:var(--cv-hero-card);color:var(--cv-ink);box-shadow:var(--cv-shadow)}
.cv-hero .cv-frame figcaption{color:var(--cv-muted)}

/* ---------- Cards: one style site-wide. Head, body, and a link pinned to the bottom so a row lines up. ---------- */
.cv-card{padding:24px;display:flex;flex-direction:column;gap:10px;min-width:0}
.cv-card p{color:var(--cv-muted);font-size:var(--cv-fs-small)}
.cv-card .cv-link{margin-top:auto;padding-top:8px}
.cv-card .cv-k{font-size:var(--cv-fs-meta);color:var(--cv-muted)}
a.cv-card .cv-go{margin-top:auto;padding-top:8px;color:var(--cv-blue-text);font-size:var(--cv-fs-small);font-weight:400}
.cv-card ul{margin:4px 0 0;padding-left:18px;color:var(--cv-muted);font-size:var(--cv-fs-small)}
.cv-card ul li+li{margin-top:4px}
.cv-num{font-size:var(--cv-fs-meta);color:var(--cv-blue-text);font-weight:500;letter-spacing:.01em}
.cv-k{font-size:var(--cv-fs-meta);font-weight:400;color:var(--cv-muted);letter-spacing:.01em}

/* Audience doors under the hero. */
.cv-doors{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.cv-door{padding:28px 28px 24px;gap:10px}
.cv-chips{display:flex;flex-wrap:wrap;gap:6px;list-style:none;margin:2px 0 0;padding:0}
.cv-chips li{font-size:13px;border:1px solid var(--cv-line);border-radius:999px;padding:3px 10px;color:var(--cv-muted)}

/* ---------- The Titanium band (customer band, closing call) ---------- */
.cv-band{background:linear-gradient(160deg,var(--cv-chrome-1),var(--cv-chrome-2));color:var(--cv-on-chrome);border:1px solid var(--cv-chrome-line);border-radius:16px;padding:40px;display:grid;grid-template-columns:1.2fr 1fr;gap:40px;align-items:center;color-scheme:dark}
.cv-band h2{color:var(--cv-on-chrome)}
.cv-band p{color:var(--cv-on-chrome-muted);margin-top:12px}
.cv-band .cv-actions{margin-top:22px}
.cv-band .cv-actions.end{justify-content:flex-end;margin-top:0}
.cv-band :focus-visible{outline-color:var(--cv-chrome-focus)}
.cv-band .cv-btn.ghost{background:transparent;border-color:var(--cv-chrome-line-strong);color:var(--cv-on-chrome)}
.cv-band .cv-btn.ghost:hover{background:var(--cv-lift)}
.cv-band-list{display:grid;gap:10px;list-style:none;margin:0;padding:0}
.cv-band-list li{background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.08);border-radius:var(--cv-radius-sm);padding:12px 14px;font-size:14px;color:var(--cv-on-chrome)}

/* ---------- The two-option switch (Solutions) ---------- */
.cv-seg{display:inline-flex;background:var(--cv-card);border:1px solid var(--cv-line);border-radius:9px;padding:3px;gap:2px}
.cv-seg a{padding:7px 16px;border-radius:7px;font-size:14px;font-weight:500;color:var(--cv-muted);transition:background-color var(--cv-dur) var(--cv-ease),color var(--cv-dur) var(--cv-ease)}
.cv-seg a:hover{color:var(--cv-ink)}
.cv-seg a[aria-current]{background:var(--cv-blue-soft);color:var(--cv-blue-text)}
.cv-subhero .cv-hero-grid{margin-top:32px}

/* ---------- Fact rows and questions ---------- */
.cv-facts{margin:0}
.cv-facts>div{display:grid;grid-template-columns:200px 1fr;gap:24px;padding:16px 0;border-top:1px solid var(--cv-line-soft);font-size:var(--cv-fs-small)}
.cv-facts>div:first-child{border-top:0}
.cv-facts dt{font-weight:500}
.cv-facts dd{margin:0;color:var(--cv-muted)}
.cv-facts a{color:var(--cv-blue-text)}
.cv-facts a:hover{text-decoration:underline;text-underline-offset:3px}
.cv-faq details{border-top:1px solid var(--cv-line-soft);padding:18px 0}
.cv-faq details:first-child{border-top:0}
.cv-faq summary{cursor:pointer;font-weight:500;list-style:none;display:flex;justify-content:space-between;gap:16px}
.cv-faq summary::-webkit-details-marker{display:none}
.cv-faq summary::after{content:"+";color:var(--cv-muted);font-weight:400;flex:none;transition:transform var(--cv-dur) var(--cv-ease)}
.cv-faq details[open] summary::after{transform:rotate(45deg)}
.cv-faq details p{color:var(--cv-muted);margin-top:8px;max-width:52em}
.cv-faq a{color:var(--cv-blue-text)}
.cv-faq a:hover{text-decoration:underline;text-underline-offset:3px}

/* ---------- Placeholder slot: a visual that waits for the neutral demo world (Opal item 72) ---------- */
.cv-slot{display:grid;place-items:center;text-align:center;aspect-ratio:16/10;border:1px dashed var(--cv-line);border-radius:var(--cv-radius-sm);background:var(--cv-well);color:var(--cv-muted);font-size:14px;padding:24px}

/* ---------- Footer: the header's dark titanium (one footer on every page, the documentation included) ---------- */
.cv-foot{margin-top:72px;background:var(--cv-bar-bg);color:var(--cv-muted);font-size:var(--cv-fs-small)}
/* After a page that is only its head (the 404), the footer follows the dark head straight on, with a hairline between. */
main:has(> :is(.cv-hero,.cv-subhero):last-child) + .cv-foot{margin-top:0;border-top:1px solid var(--cv-bar-edge)}
.cv-foot :focus-visible{outline-color:var(--cv-blue)}
.cv-foot-grid{display:grid;grid-template-columns:1.4fr repeat(4,1fr);gap:32px;padding-top:44px;padding-bottom:28px}
.cv-foot h2{color:var(--cv-ink);font-weight:500;font-size:var(--cv-fs-meta);letter-spacing:0;margin:0 0 12px}
.cv-foot ul{list-style:none;margin:0;padding:0}
.cv-foot li a{display:inline-block;padding:3px 0;color:var(--cv-muted);transition:color var(--cv-dur) var(--cv-ease)}
.cv-foot li a:hover{color:var(--cv-ink)}
.cv-foot-about{margin-top:14px;max-width:24em}
.cv-foot-legal{border-top:1px solid var(--cv-line);display:flex;flex-wrap:wrap;justify-content:space-between;gap:12px;padding-top:20px;padding-bottom:28px}
.cv-foot-legal nav{display:flex;flex-wrap:wrap;gap:16px}
.cv-foot-legal a{color:var(--cv-muted)}
.cv-foot-legal a:hover{color:var(--cv-ink)}
/* The documentation's own styles must not reach into the shared bar and footer. */
body.cv-docs .cv-bar a:hover,body.cv-docs .cv-foot a:hover{text-decoration:none}
body.cv-docs .cv-foot p{margin-bottom:0}
body.cv-docs .cv-bar :focus-visible,body.cv-docs .cv-foot :focus-visible{outline-width:2px;outline-offset:3px}

/* ---------- Page transitions: one 150 ms crossfade; the bar never moves ---------- */
@media (prefers-reduced-motion:no-preference){
  @view-transition{navigation:auto}
  .cv-bar{view-transition-name:cv-bar}
  ::view-transition-group(cv-bar),::view-transition-old(cv-bar),::view-transition-new(cv-bar){animation:none}
  ::view-transition-old(cv-bar){opacity:0}
  ::view-transition-old(root){animation:cv-fade-out var(--cv-dur) var(--cv-ease) both}
  ::view-transition-new(root){animation:cv-fade-in var(--cv-dur) var(--cv-ease) both}
  @keyframes cv-fade-out{to{opacity:0}}
  @keyframes cv-fade-in{from{opacity:0}}
}
@media (prefers-reduced-motion:reduce){
  .cv *,.cv *::before,.cv *::after{transition:none!important;animation:none!important}
}

/* ---------- Narrow screens: the site stays readable on a phone ---------- */
@media (max-width:1023px){
  .cv-hero-grid,.cv-s-head,.cv-band{grid-template-columns:1fr;gap:32px}
  .cv-g4{grid-template-columns:repeat(2,minmax(0,1fr))}
  .cv-foot-grid{grid-template-columns:1fr 1fr}
}
@media (max-width:720px){
  :root{--cv-gutter:16px;--cv-fs-display:38px;--cv-fs-title:32px;--cv-fs-section:28px}
  .cv-hero{padding:calc(40px + var(--cv-bar)) 0 40px}
  .cv-doors,.cv-g2,.cv-g3,.cv-g4{grid-template-columns:1fr}
  .cv-facts>div{grid-template-columns:1fr;gap:4px}
  .cv-band{padding:28px}
  .cv-s{padding:48px 0}
  .cv-foot-grid{grid-template-columns:1fr}
}

/* ---------- Page pieces added with the solutions pages ---------- */
.cv-go{display:inline-flex;gap:6px}
.cv-links{display:flex;flex-wrap:wrap;gap:8px 24px}
.cv-split{align-items:start}
.cv-crop{overflow:hidden;border-radius:var(--cv-radius-sm);background:var(--cv-chrome-2)}
.cv-wide img{width:100%}

/* A drawing's caption actions: Pause and a link. */
.cv-net-acts{display:inline-flex;align-items:center;gap:20px}
.cv-motion-btn{font-size:var(--cv-fs-meta);font-weight:500;color:var(--cv-blue-text);background:none;border:0;padding:0;cursor:pointer;min-width:3.4em;text-align:left}
.cv-motion-btn:hover{text-decoration:underline;text-underline-offset:3px}
/* Scroll reveals on site pages (platinum.js): blocks that start below the first screen rise 24px into place as they
   arrive, list items a step apart. Translation only: copy is never faded, and nothing on the first screen moves. */
@media (prefers-reduced-motion:no-preference){
  .cv .cv-rise{transform:translateY(24px);transition:transform var(--cv-dur-enter) var(--cv-ease-enter);transition-delay:calc(var(--cv-i,0) * 70ms)}
  .cv .cv-rise.cv-in{transform:none}
}

/* ---------- Article pages (trust, requirements, legal, what's new): a head, an outline, sections on cards ---------- */
.cv-article{display:grid;grid-template-columns:220px minmax(0,1fr);gap:40px;align-items:start;padding-top:48px}
.cv-article.no-toc{grid-template-columns:minmax(0,1fr)}
.cv-article.no-toc .cv-prose{max-width:880px}
.cv-toc{position:sticky;top:calc(var(--cv-bar) + 24px);font-size:var(--cv-fs-small)}
.cv-toc h2,body.cv main .cv-toc h2{font-size:var(--cv-fs-meta);line-height:1.4;letter-spacing:.01em;font-weight:500;color:var(--cv-muted);letter-spacing:.01em;margin:0 0 10px}
.cv-toc ol{list-style:none;margin:0;padding:0;border-left:1px solid var(--cv-line)}
.cv-toc a{display:block;padding:5px 0 5px 14px;margin-left:-1px;border-left:2px solid transparent;color:var(--cv-muted);line-height:1.35;transition:color var(--cv-dur) var(--cv-ease),border-color var(--cv-dur) var(--cv-ease)}
.cv-toc a:hover{color:var(--cv-ink)}
.cv-toc a[aria-current]{color:var(--cv-blue-text);border-left-color:var(--cv-blue)}
.cv-prose{display:grid;gap:0;min-width:0}
.cv-prose>section{padding:40px 0;min-width:0;scroll-margin-top:24px;border-top:1px solid var(--cv-line-soft)}
.cv-prose>section:first-child{padding-top:0;border-top:0}
.cv-prose h2{font-size:var(--cv-fs-subhead);line-height:1.3;letter-spacing:-.015em;margin:0 0 14px}
.cv-prose h3{font-size:20px;line-height:1.35;margin:24px 0 8px;scroll-margin-top:24px}
.cv-prose h4{font-size:var(--cv-fs-small);margin:16px 0 6px}
.cv-prose p,.cv-prose ul,.cv-prose ol{margin:0 0 16px;color:var(--cv-ink);font-size:var(--cv-fs-body);line-height:1.6;max-width:var(--cv-measure)}
.cv-prose>section>:last-child,.cv-prose>section>:last-child>:last-child{margin-bottom:0}
.cv-prose ul,.cv-prose ol{padding-left:22px}
.cv-prose li+li{margin-top:6px}
.cv-prose a{color:var(--cv-blue-text);text-decoration:underline;text-decoration-color:color-mix(in srgb,var(--cv-blue-text) 35%,transparent);text-underline-offset:3px}
.cv-prose a:hover{text-decoration-color:currentColor}
.cv-prose a.cv-btn{color:var(--cv-on-blue);text-decoration:none}
.cv-prose a.cv-btn.ghost{color:var(--cv-ink)}
.cv-prose dl.facts{display:grid;grid-template-columns:200px minmax(0,1fr);margin:4px 0 12px;border-top:1px solid var(--cv-line-soft)}
.cv-prose dl.facts dt,.cv-prose dl.facts dd{padding:12px 0;border-bottom:1px solid var(--cv-line-soft);margin:0}
.cv-prose dl.facts dt{font-weight:500;padding-right:20px}
.cv-prose dl.facts dd{color:var(--cv-muted)}
.cv-prose .table-wrap{overflow-x:auto;margin:4px 0 14px;border:1px solid var(--cv-line);border-radius:var(--cv-radius-sm)}
.cv-prose table{width:100%;border-collapse:collapse;font-size:var(--cv-fs-small)}
.cv-prose th{text-align:left;font-weight:500;color:var(--cv-muted);background:var(--cv-well);white-space:nowrap}
.cv-prose th,.cv-prose td{padding:10px 14px;border-bottom:1px solid var(--cv-line-soft);vertical-align:top}
.cv-prose tr:last-child td{border-bottom:0}
.cv-prose .code-wrap{position:relative;margin:4px 0 14px}
.cv-prose pre{margin:0;overflow-x:auto;background:var(--cv-chrome-2);color:var(--cv-on-chrome);border-radius:var(--cv-radius-sm);padding:16px 18px;font:14.5px/1.65 var(--cv-mono)}
.cv-prose pre code{background:none;border:0;padding:0;color:inherit;font-size:inherit}
.cv-prose .copy{position:absolute;top:8px;right:8px;min-height:28px;padding:0 10px;border-radius:6px;border:1px solid var(--cv-chrome-line-strong);background:var(--cv-chrome-1);color:var(--cv-on-chrome);font-size:12px;cursor:pointer}
.cv-prose .see-also{font-size:var(--cv-fs-small);color:var(--cv-muted);border-top:1px solid var(--cv-line-soft);padding-top:12px;margin-top:16px}
.cv-prose .note,.cv-prose .empty-state{background:var(--cv-well);border:1px solid var(--cv-line-soft);border-radius:var(--cv-radius-sm);padding:12px 16px;font-size:var(--cv-fs-small)}
.cv-prose .pending-note{background:var(--cv-warn-soft);border-color:transparent}
.cv-prose .empty-state p{margin:0}
.cv-prose .link-list{list-style:none;padding:0;display:flex;flex-wrap:wrap;gap:8px 24px}
.cv-prose .advisory{border-top:1px solid var(--cv-line-soft);padding-top:12px}
.cv-prose .try-demo{display:flex;flex-wrap:wrap;gap:8px 20px;align-items:center;justify-content:space-between;background:var(--cv-blue-soft);border-radius:var(--cv-radius-sm);padding:14px 16px;margin:4px 0 12px}
.cv-prose .try-demo p{margin:0}
.cv-prose .text-link{font-weight:500;text-decoration:none}
.cv-prose .cv-actions{margin-top:8px}
.cv-updated{font-size:var(--cv-fs-meta);color:var(--cv-faint);margin-top:14px}

/* ---------- Product pages: a row per capability, the screen beside its facts ---------- */
.cv-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);gap:48px;align-items:center}
.cv-row.flip>:first-child{order:2}
.cv-row h3{font-size:var(--cv-fs-subhead);line-height:1.3;margin-bottom:10px}
.cv-row>div>p{color:var(--cv-muted);margin-bottom:14px}
.cv-ticks{list-style:none;margin:0 0 16px;padding:0;display:grid;gap:10px}
.cv-ticks li{position:relative;padding-left:22px;font-size:var(--cv-fs-small);color:var(--cv-ink)}
.cv-ticks li::before{content:"";position:absolute;left:2px;top:9px;width:8px;height:8px;border-radius:2px;background:var(--cv-blue);opacity:.8}
.cv-row .cv-links{margin-top:4px}
.cv-rows{display:grid;gap:64px}
.cv-table-wrap{overflow-x:auto}
.cv-table{width:100%;border-collapse:collapse;font-size:var(--cv-fs-small)}
.cv-table th{text-align:left;font-weight:500;color:var(--cv-muted);background:var(--cv-well);white-space:nowrap}
.cv-table th,.cv-table td{padding:12px 16px;border-bottom:1px solid var(--cv-line-soft);vertical-align:top}
.cv-table tr:last-child td{border-bottom:0}
.cv-stat{font-size:var(--cv-fs-section);font-weight:500;letter-spacing:-.02em;line-height:1.1}

/* A short recording of the demo: the poster first; it plays while on screen unless motion is reduced. */
.cv-capture video,.cv-capture img{display:block;width:100%;height:auto;border-radius:var(--cv-radius-sm)}
.cv-capture .cv-cap-stage{position:relative;aspect-ratio:8/5;overflow:hidden;border-radius:var(--cv-radius-sm);background:var(--cv-chrome-2)}
.cv-capture .cv-cap-stage>*{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.cv-capture video{opacity:0;transition:opacity var(--cv-dur) var(--cv-ease)}
.cv-capture.playing video{opacity:1}
.cv-capture button{font-size:var(--cv-fs-meta);font-weight:500;color:var(--cv-blue-text);background:none;border:0;padding:0;cursor:pointer}

/* ---------- The request form ---------- */
.cv-form-grid{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);gap:24px;align-items:start}
.cv-form{display:grid;gap:18px}
.cv-form fieldset{border:0;margin:0;padding:0;display:grid;gap:8px;min-width:0}
.cv-form legend,.cv-field>label{font-size:var(--cv-fs-small);font-weight:500;padding:0;margin-bottom:6px}
.cv-field{display:grid;gap:0}
.cv-field .hint{font-size:var(--cv-fs-meta);color:var(--cv-muted);margin-top:6px}
.cv-form input[type=text],.cv-form input[type=email],.cv-form input[type=number],.cv-form textarea{width:100%;min-height:42px;padding:9px 12px;border:1px solid var(--cv-line);border-radius:var(--cv-radius-sm);background:var(--cv-card);color:var(--cv-ink);font-size:var(--cv-fs-small);transition:border-color var(--cv-dur) var(--cv-ease)}
.cv-form textarea{min-height:110px;resize:vertical}
.cv-form input:hover,.cv-form textarea:hover{border-color:var(--cv-faint)}
.cv-form input:focus-visible,.cv-form textarea:focus-visible{outline:2px solid var(--cv-blue);outline-offset:1px;border-color:var(--cv-blue)}
.cv-form [aria-invalid="true"]{border-color:var(--cv-bad)}
.cv-two{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.cv-choice{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.cv-choice.two{grid-template-columns:repeat(2,minmax(0,1fr))}
.cv-choice label{position:relative;display:flex;flex-direction:column;gap:2px;border:1px solid var(--cv-line);border-radius:var(--cv-radius-sm);padding:10px 12px 10px 36px;cursor:pointer;background:var(--cv-card);font-size:14px;font-weight:500;transition:border-color var(--cv-dur) var(--cv-ease),background-color var(--cv-dur) var(--cv-ease)}
.cv-choice label span{font-size:var(--cv-fs-meta);font-weight:400;color:var(--cv-muted)}
.cv-choice input{position:absolute;left:12px;top:13px;margin:0;accent-color:var(--cv-blue)}
.cv-choice label:has(input:checked){border-color:var(--cv-blue);background:var(--cv-blue-soft)}
.cv-choice label:has(input:focus-visible){outline:2px solid var(--cv-blue);outline-offset:2px}
.cv-trap{position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden}
.cv-verify:empty{display:none}
.cv-verify-stub{font-size:var(--cv-fs-meta);color:var(--cv-ok);margin:0}
.cv-status{font-size:var(--cv-fs-small);margin:0;min-height:1.6em}
.cv-status[data-state=error]{color:var(--cv-bad)}
.cv-status[data-state=busy]{color:var(--cv-muted)}
.cv-error-list{background:var(--cv-bad-soft);border-radius:var(--cv-radius-sm);padding:12px 16px;font-size:var(--cv-fs-small)}
.cv-error-list ul{margin:6px 0 0;padding-left:20px}
.cv-done{display:grid;gap:12px}
.cv-done h2{font-size:var(--cv-fs-subhead)}
.cv-steps{counter-reset:step;list-style:none;margin:4px 0 0;padding:0;display:grid;gap:12px}
.cv-steps li{counter-increment:step;position:relative;padding-left:36px;font-size:var(--cv-fs-small);color:var(--cv-muted)}
.cv-steps li strong{color:var(--cv-ink);display:block}
.cv-steps li::before{content:counter(step);position:absolute;left:0;top:0;width:24px;height:24px;border-radius:50%;background:var(--cv-blue-soft);color:var(--cv-blue-text);font-size:15px;font-weight:500;display:grid;place-items:center}
.cv-form-grid .cv-card h3{font-size:var(--cv-fs-card)}
[hidden]{display:none!important}

@media (max-width:1023px){
  .cv-article{grid-template-columns:1fr}
  .cv-toc{position:static}
  .cv-row,.cv-form-grid{grid-template-columns:1fr;gap:28px}
  .cv-row.flip>:first-child{order:0}
}
@media (max-width:720px){
  .cv-prose>section{padding:28px 0}
  .cv-prose dl.facts{grid-template-columns:1fr}
  .cv-prose dl.facts dt{border-bottom:0;padding-bottom:0}
  .cv-two,.cv-choice,.cv-choice.two{grid-template-columns:1fr}
}

/* ---------- Documentation: the shared header and footer; the layout is the documentation's own (site.css, docs.css),
   its legacy colors mapped onto the tokens and its type on the website's scale. ---------- */
body.cv-docs{--paper:var(--cv-page);--ink:var(--cv-ink);--muted:var(--cv-muted);--line:var(--cv-line);--blue:var(--cv-blue);--blue-text:var(--cv-blue-text);
  --ice:var(--cv-blue-soft);--night:var(--cv-chrome-2);--header:var(--cv-bar);--cover:var(--cv-bar);background:var(--cv-page);color:var(--cv-ink);font-family:var(--cv-font)}
.docs-article h1,.docs-article h2,.docs-article h3{font-family:var(--cv-font);font-weight:500}
/* The article reads at 17 px on 1.6 with a 70-character measure. */
.docs-article{font-size:var(--cv-fs-body);line-height:1.6}
.docs-article :is(p,li){max-width:var(--cv-measure)}
.docs-article .intro{font-size:var(--cv-fs-lead);line-height:1.55}
.docs-article h1{font-size:var(--cv-fs-title);line-height:1.15;letter-spacing:-.025em;text-transform:none}
.landing-hero h1{font-size:var(--cv-fs-display);line-height:1.1}
.docs-article h2{font-size:28px;line-height:1.25;letter-spacing:-.015em}
.docs-article h3{font-size:21px;line-height:1.35}
.docs-article .kicker{font-family:var(--cv-font);font-size:var(--cv-fs-meta);font-weight:500;letter-spacing:0;text-transform:none;color:var(--cv-blue-text)}
.docs-article .intro{color:var(--cv-muted)}
.docs-nav>.eyebrow{font-family:var(--cv-font);font-size:var(--cv-fs-meta);font-weight:500;letter-spacing:.01em;text-transform:none}
.docs-nav a{border-radius:var(--cv-radius-sm);min-height:36px;color:var(--cv-ink)}
.docs-nav a:hover{background:var(--cv-glass-lift)}
/* The current page: the blue's darker step, which holds 4.5:1 on the selected tint in both themes. */
.docs-nav a[aria-current=page]{background:var(--cv-selected);color:var(--cv-blue-hover);font-weight:500}
.doc-group summary{font-size:var(--cv-fs-small)}
.doc-group-flat{border-bottom:0}
.page-outline a[aria-current=location]{border-left-color:var(--cv-blue)}
/* The sidebar's search opens the one search dialog (search.js), the same as the header's button, / and Ctrl+K. */
.docs-search-open{display:flex;align-items:center;gap:10px;width:100%;min-height:40px;padding:0 8px 0 12px;border:1px solid var(--cv-line-strong);border-radius:var(--cv-radius-sm);background:var(--cv-input);color:var(--cv-muted);font:400 15px/1 var(--cv-font);cursor:pointer;transition:border-color var(--cv-dur) var(--cv-ease),color var(--cv-dur) var(--cv-ease)}
.docs-search-open:hover{border-color:var(--cv-ink);color:var(--cv-ink)}
.docs-search-open span{flex:1;text-align:left;white-space:nowrap}
.docs-search-open kbd{font:500 12px/1 var(--cv-font);padding:3px 6px;border:1px solid var(--cv-line);border-radius:4px}
html:not(.js) .docs-search{display:none}
/* The sidebar scrolls on its own when it is taller than the window: a thin themed bar that shows only while the
   pointer or focus is in it, in a reserved gutter so it never sits on the links. */
body.cv-docs .docs-nav{scrollbar-width:thin;scrollbar-color:transparent transparent;scrollbar-gutter:stable}
body.cv-docs .docs-nav:is(:hover,:focus-within){scrollbar-color:var(--cv-line-strong) transparent}
.landing-search{background:var(--cv-card);border-color:var(--cv-line)}
/* Legacy documentation colors that were drawn for light only: table heads, sticky table cells (opaque, so rows do not
   show through them) and the old button. */
:is(.rm-table,.pv-table) thead th{background:var(--cv-surface-strong)}
.rm-table tbody th{background:var(--cv-surface)}
body.cv-docs .button{min-height:var(--cv-btn-h);padding:0 20px;background:var(--cv-blue);color:var(--cv-on-blue);border-color:transparent;border-radius:var(--cv-radius-sm);font-size:16px;font-weight:500}
body.cv-docs .button:hover{background:var(--cv-blue-hover)}
body.cv-docs .button.secondary{background:transparent;color:var(--cv-ink);border-color:var(--cv-line-strong)}
body.cv-docs .button.secondary:hover{background:var(--cv-glass-lift);border-color:var(--cv-ink)}
body.cv-docs .button:focus-visible{outline:2px solid var(--cv-blue);outline-offset:3px}
/* The documentation as a reading surface (owner, 2026-10-18 evening): the sidebar, the article and On this page, with
   more air between them; navigation and the outline at 15 and 14 px; code in the page's own quiet tone with a hairline,
   not a dark console block; tables for reading (no filled head, hairlines between rows, room in each cell). The
   hardware reference registers keep their opaque sticky heads. The article pages on the site (trust, legal) share
   the same code and table style. */
@media (min-width:1280px){body.cv-docs .docs-shell{grid-template-columns:232px minmax(0,1fr) 200px;gap:56px}}
.docs-nav a{font-size:15px;padding:8px 12px}
.page-outline{font-size:14px}
.page-outline a{color:var(--cv-muted)}
.page-outline a:hover{color:var(--cv-ink);text-decoration:none}
.docs-article>:is(h2){margin-top:56px}
.code-wrap pre,.cv-prose pre{background:var(--cv-code);color:var(--cv-code-ink);border:1px solid var(--cv-code-edge);border-radius:var(--cv-radius-sm);padding:20px 96px 20px 22px;font:14.5px/1.7 var(--cv-mono)}
.code-wrap pre code,.cv-prose pre code{color:inherit}
.code-wrap .copy,.cv-prose .copy{top:12px;right:12px;min-height:32px;min-width:0;padding:0 12px;border-radius:var(--cv-radius-sm);border:1px solid var(--cv-line-strong);background:var(--cv-page);color:var(--cv-ink);font:500 13px/1 var(--cv-font);cursor:pointer;transition:border-color var(--cv-dur) var(--cv-ease)}
.code-wrap .copy:hover,.cv-prose .copy:hover{border-color:var(--cv-ink)}
.code-wrap .copy:focus-visible,.cv-prose .copy:focus-visible{outline:2px solid var(--cv-blue);outline-offset:2px}
.docs-article code:not(pre code),.cv-prose code:not(pre code){background:var(--cv-well);border:1px solid var(--cv-line-soft);border-radius:4px;padding:1px 5px;font-size:.88em}
body.cv-docs .table-wrap,.cv-prose .table-wrap{border:0;border-radius:0;margin:20px 0 24px}
body.cv-docs table:not(.rm-table,.pv-table,.hw-table),.cv-prose table{font-size:15px;line-height:1.5}
body.cv-docs table:not(.rm-table,.pv-table,.hw-table) th,.cv-prose th{background:none;color:var(--cv-muted);font-size:14px;font-weight:500;white-space:nowrap;border-bottom:1px solid var(--cv-line-strong);padding:10px 20px 10px 0}
body.cv-docs table:not(.rm-table,.pv-table,.hw-table) :is(td,th[scope=row]),.cv-prose :is(td,th[scope=row]){padding:14px 20px 14px 0;border-bottom:1px solid var(--cv-line-soft);vertical-align:top}
body.cv-docs table:not(.rm-table,.pv-table,.hw-table) th[scope=row],.cv-prose th[scope=row]{color:var(--cv-ink);font-size:15px;font-weight:500}
body.cv-docs table:not(.rm-table,.pv-table,.hw-table) tr:last-child :is(td,th[scope=row]),.cv-prose tr:last-child :is(td,th[scope=row]){border-bottom:1px solid var(--cv-line-soft)}
/* The documentation landing's five paths: each column's parts sit on shared rows, so the link lists start on one line
   however long a description runs; descriptions and links read at the website's small size, not the console's 14 px. */
body.cv-docs .paths{grid-template-rows:auto auto auto 1fr}
body.cv-docs .path{display:grid;grid-row:span 4;grid-template-rows:subgrid;row-gap:0;align-content:start}
body.cv-docs .path p{font-size:var(--cv-fs-small);line-height:1.5}
body.cv-docs .path li a{font-size:var(--cv-fs-small)}
/* Fields in the documentation's worked examples and explorers (supported hardware and devices, replacement, access,
   Mist, E-Rate, Explore): the website's 44 px field with a hairline, its own chevron in place of the browser's, and the
   one focus ring. */
body.cv-docs .docs-article :is(select,input:not([type=checkbox],[type=radio],[type=range])){min-height:var(--cv-btn-h);border:1px solid var(--cv-line-strong);border-radius:var(--cv-radius-sm);background-color:var(--cv-input);color:var(--cv-ink);font:400 15px/1.3 var(--cv-font);padding:0 12px;transition:border-color var(--cv-dur) var(--cv-ease)}
body.cv-docs .docs-article select:not([multiple],[size]){appearance:none;-webkit-appearance:none;padding-right:36px;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 20px) 50%,calc(100% - 15px) 50%;background-size:5px 5px;background-repeat:no-repeat}
/* The Mist worked example keeps its row's compact scale: its picker matches the 36 px buttons beside it. */
body.cv-docs .docs-article .mm-actions select:not([multiple],[size]){min-height:36px;font-size:13px;padding:0 32px 0 10px;background-position:calc(100% - 17px) 50%,calc(100% - 12px) 50%}
body.cv-docs .docs-article :is(select,input):hover:not(:disabled){border-color:var(--cv-ink)}
body.cv-docs .docs-article :is(select,input):focus-visible{outline:2px solid var(--cv-blue);outline-offset:2px}
body.cv-docs .docs-article :is(select,input):disabled{opacity:.6;cursor:not-allowed}
body.cv-docs .docs-article :is(.hw-filters,.rm-filters,.hw-findbox) label{font-size:var(--cv-fs-meta);font-weight:500;color:var(--cv-ink)}
/* The supported-hardware register: a hairline above and below in place of a rounded box (a rounded box that scrolls
   squares its corners off), an opaque sticky head so rows never show through it, and room in the first column. Each
   model name is a link-styled button that draws the model. */
body.cv-docs .hw-scroll{border:0;border-block:1px solid var(--cv-line);border-radius:0}
body.cv-docs .hw-table :is(td,th){padding:12px 14px;border-bottom:1px solid var(--cv-line-soft);vertical-align:top}
body.cv-docs .hw-table thead th{background:var(--cv-page);color:var(--cv-muted);font-size:14px;font-weight:500;white-space:nowrap;border-bottom:1px solid var(--cv-line-strong);box-shadow:0 1px 0 var(--cv-line-strong)}
body.cv-docs .hw-table tbody th{font-size:15px}
body.cv-docs .hw-table th button{all:unset;cursor:pointer;color:var(--cv-blue-text);font-weight:500;white-space:nowrap}
body.cv-docs .hw-table th button:hover{text-decoration:underline;text-underline-offset:3px}
body.cv-docs .hw-table th button:focus-visible{outline:2px solid var(--cv-blue);outline-offset:2px;border-radius:2px}
body.cv-docs .hw-table tbody tr:hover{background:var(--cv-glass-lift)}
body.cv-docs .hw-table tbody tr[aria-selected=true]{background:var(--cv-selected)}
/* Disclosures (sidebar groups, On this page, source notes, release details) open on a quiet chevron that turns, not
   the browser's triangle; the FAQ keeps its plus. */
:is(body.cv-docs,.cv-prose) details:not(.cv-faq details)>summary{list-style:none;display:flex;align-items:center;gap:10px}
:is(body.cv-docs,.cv-prose) details>summary::-webkit-details-marker{display:none}
:is(body.cv-docs,.cv-prose) details:not(.cv-faq details)>summary::before{content:"";flex:none;width:7px;height:7px;margin:0 3px 0 1px;border:solid var(--cv-muted);border-width:0 1.5px 1.5px 0;transform:rotate(-45deg);transition:transform var(--cv-dur) var(--cv-ease)}
:is(body.cv-docs,.cv-prose) details[open]:not(.cv-faq details)>summary::before{transform:rotate(45deg) translate(-1px,-1px)}
@media (prefers-reduced-motion:reduce){:is(body.cv-docs,.cv-prose) details>summary::before{transition:none}}
/* The trust summary: the facts and "Who secures what" keep their own heights. */
.cv-trust-glance{align-items:start}

/* =====================================================================================================
   Page shapes and drawings (owner 2026-10-12, D1–D5). Each page has its own layout built from these shapes: the drawn
   hero, the wide row, the bento, the strip, the timeline, the numbered path, the pinned stage, the pillar hub, the
   annotated screen and the facts table. Drawings are inline SVG in tokens only.
   ===================================================================================================== */

/* ---------- Drawn heroes ---------- */
.cv-hero-copy{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:56px;align-items:end}
.cv-hero-copy .cv-lead{margin-top:0}
.cv-hero-draw .cv-drawing.hero{margin-top:44px}
.cv-subhero .cv-drawing.hero{margin-top:36px}

/* ---------- Drawings ---------- */
.cv-drawing{margin:0;padding:28px 32px 16px;min-width:0}
.cv-drawing.bare{background:none;border:0;padding:0}
.cv-drawing>svg{display:block;width:100%;height:auto;overflow:visible}
.cv-drawing figcaption{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap;font-size:var(--cv-fs-meta);color:var(--cv-muted);border-top:1px solid var(--cv-line-soft);margin-top:14px;padding-top:10px}
.cv-drawing figcaption a{color:var(--cv-blue-text);font-weight:500}
.cv-drawing figcaption a:hover{text-decoration:underline;text-underline-offset:3px}
.dw{font-family:var(--cv-font)}
.dw text{fill:var(--cv-ink);font-size:13px}
.dw .t{font-weight:500;font-size:14px}
.dw .sm{font-size:12px}
.dw .t.sm{font-size:12.5px}
.dw .m{fill:var(--cv-muted)}
.dw .bt{fill:var(--cv-blue-text);font-weight:500}
.dw .wt{fill:var(--cv-warn)}
.dw .q{font-size:15px}
.dw .mono{font-family:var(--cv-mono);font-size:11.5px}
.dw .ln{fill:none;stroke:var(--cv-faint);stroke-width:1.4}
.dw .ln.b{stroke:var(--cv-ink);stroke-width:1.6;stroke-linejoin:round}
.dw .ln.dash{stroke:var(--cv-line);stroke-dasharray:4 4}
.dw .ln.dist{stroke:var(--cv-silver-4);stroke-width:1.6;stroke-dasharray:none;fill:var(--cv-well)}
.dw .bx{fill:var(--cv-card);stroke:var(--cv-line);stroke-width:1.2}
.dw .core{fill:var(--cv-blue-soft);stroke:var(--cv-blue);stroke-width:1.6}
.dw .well{fill:var(--cv-well);stroke:var(--cv-line)}
.dw .soft{fill:var(--cv-blue-soft)}
.dw .hl{fill:none;stroke:var(--cv-blue);stroke-width:2}
.dw .wn{stroke:var(--cv-warn);stroke-width:1.6}
.dw .pt{fill:var(--cv-well);stroke:var(--cv-faint);stroke-width:1}
.dw .pt.up{fill:var(--cv-line)}
.dw .unit{fill:var(--cv-well);stroke:var(--cv-faint)}
.dw .pulse{fill:none;stroke:var(--cv-blue);stroke-width:7;stroke-linecap:round;visibility:hidden}
/* Reports */
.dw .rp-cover{fill:var(--cv-card);transform-box:fill-box;transform-origin:right center;transform:scaleX(0)}
.dw .rp-caret{fill:var(--cv-blue);opacity:0}
.dw .bar{fill:var(--cv-blue)}
/* Monitoring */
.dw .mo-rip{fill:none;stroke:var(--cv-warn);stroke-width:1.4;opacity:.3}
.dw .dep{fill:none;stroke:var(--cv-warn);stroke-width:1.6}
/* Inventory */
.dw .grid{stroke:var(--cv-line-soft);stroke-width:1;fill:none}
.dw path.bar{fill:none;stroke:var(--cv-blue);stroke-width:8;stroke-linecap:round}
.dw .wd{fill:var(--cv-card);stroke:var(--cv-blue);stroke-width:2}
.dw .eos{fill:none;stroke:var(--cv-warn);stroke-width:2.4;stroke-linecap:round}
.dw .today{fill:none;stroke:var(--cv-blue);stroke-width:1.6}
/* Network record */
.dw .stop{fill:none;stroke:var(--cv-blue);stroke-width:2}
.dw .dot{fill:var(--cv-blue)}
/* K-12 */
.dw .pin{fill:var(--cv-blue);stroke:var(--cv-card);stroke-width:2}
.dw .chip{fill:var(--cv-card);stroke:var(--cv-line)}
.dw .arc{fill:none;stroke:var(--cv-blue);stroke-width:10;stroke-linecap:round}
.dw .num{fill:var(--cv-card);stroke:var(--cv-blue);stroke-width:1.6}
.dw .nt{font-weight:500;font-size:13px;fill:var(--cv-blue-text)}
.dw-ring{max-width:320px}
/* Enterprise, Trust */
.dw .ok{fill:none;stroke:var(--cv-ok);stroke-width:1.8;opacity:0}
.dw .okc{fill:var(--cv-ok-soft);stroke:var(--cv-ok);stroke-width:1.6}
.dw .tick{fill:none;stroke:var(--cv-ok);stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round}
/* Annotated screens: numbered pins over a real screen, the notes beside it. */
.cv-annotated{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:40px;align-items:center}
.cv-annot-stage{position:relative}
.cv-pins{position:absolute;inset:0;width:100%;height:100%;font-family:var(--cv-font);pointer-events:none}
.cv-pins circle{fill:var(--cv-blue);stroke:var(--cv-card);stroke-width:4}
.cv-pins text{fill:var(--cv-on-blue);font-size:22px;font-weight:500}
.cv-callouts{counter-reset:co;list-style:none;margin:0;padding:0;display:grid;gap:18px}
.cv-callouts li{counter-increment:co;position:relative;padding-left:40px;font-size:var(--cv-fs-small);color:var(--cv-ink)}
.cv-callouts li::before{content:counter(co);position:absolute;left:0;top:-1px;width:26px;height:26px;border-radius:50%;background:var(--cv-blue);color:var(--cv-on-blue);font-size:15px;font-weight:500;display:grid;place-items:center}

/* =====================================================================================================
   Diagrams (redrawn 2026-10-18, site.py dg_*): one grammar, from the tokens. 1.5 px strokes, 8 px
   nodes and 12 px zones, 12 px labels or more. Still and complete by default; the motion runs only inside a playing
   [data-anim] (platinum.js) and never under reduced motion. Blue goes out (a read or request), green comes back (an
   answer); a dashed amber frame is a member not answering Cenovel.
   ===================================================================================================== */
.dg{--dg-stroke:color-mix(in srgb,var(--cv-ink) 34%,transparent);--dg-zone:color-mix(in srgb,var(--cv-ink) 3%,transparent)}
.dg text{font-family:var(--cv-font)}
.dg .t{font-size:14px;font-weight:500;fill:var(--cv-ink)}
.dg .t.m{font-weight:400;fill:var(--cv-muted)}
.dg .s{font-size:12.5px;fill:var(--cv-muted)}
.dg .lbl{font-size:12px;fill:var(--cv-muted)}
.dg .node{fill:var(--cv-well);stroke:var(--dg-stroke);stroke-width:1.5}
.dg .node.core{fill:var(--cv-blue-soft);stroke:var(--cv-blue)}
.dg .node.none{fill:none;stroke-dasharray:4 5}
.dg .zone{fill:var(--dg-zone);stroke:var(--cv-line);stroke-width:1.5}
.dg .zone.out{fill:none;stroke:var(--dg-stroke);stroke-dasharray:6 6}
.dg .inner{fill:var(--cv-card)}
.dg .wire{fill:none;stroke:var(--dg-stroke);stroke-width:1.5;stroke-linejoin:round}
.dg .wire.opt{stroke-dasharray:4 5}
.dg .wire.warn{stroke:var(--cv-warn)}
.dg .wire.link{stroke:var(--cv-blue);stroke-dasharray:3 4}
.dg .dg-head{fill:var(--dg-stroke)}
.dg .flow{fill:none;stroke-width:7;stroke-linecap:round;stroke-dasharray:.02 2;stroke-dashoffset:.1;visibility:hidden}
.dg .flow.read{stroke:var(--cv-blue)}
.dg .flow.answer{stroke:var(--cv-ok)}
.dg .port{fill:none;stroke:var(--dg-stroke);stroke-width:1.2}
.dg .port.up{fill:color-mix(in srgb,var(--cv-ok) 32%,transparent)}
.dg .port.lit{fill:var(--cv-blue);stroke:var(--cv-blue)}
.dg .state.good{fill:var(--cv-ok)}
.dg .state.silent{fill:var(--cv-page);stroke:var(--cv-warn);stroke-width:2;opacity:0}
.dg .state.silent.still{opacity:1}
.dg .silent-frame{fill:color-mix(in srgb,var(--cv-warn) 9%,transparent);stroke:var(--cv-warn);stroke-width:1.5;stroke-dasharray:5 4;opacity:0}
.dg .record-ring{fill:none;stroke:var(--cv-blue);stroke-width:2}
.dg .record-ring.check{opacity:0}
.dg .key{stroke-width:4;stroke-linecap:round}
.dg .key.read{stroke:var(--cv-blue)}
.dg .key.answer{stroke:var(--cv-ok)}
.dg .wall{stroke:var(--cv-ink);stroke-width:2.5;stroke-linecap:round}
.dg circle.no{fill:var(--cv-page);stroke:var(--cv-bad);stroke-width:2}
.dg path.no{stroke:var(--cv-bad);stroke-width:2;stroke-linecap:round}
.dg .stamp{fill:var(--cv-blue)}
.dg .tick-c{fill:var(--cv-ok-soft);stroke:var(--cv-ok);stroke-width:1.5}
.dg .tick-p{fill:none;stroke:var(--cv-ok);stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.dg :is(.stamp,.tick-c,.tick-p){transform-box:fill-box;transform-origin:center}
@media (prefers-reduced-motion:no-preference){
  .js [data-anim] .dg .flow{visibility:visible}
  /* Home: reads go out to the three members twice in 8 s; members 1 and 2 answer both times, member 3 only the second. */
  .js [data-anim] .dg-reads .read{animation:dg-out2 8s linear infinite both}
  .js [data-anim] .dg-reads .r2{animation-delay:.15s}.js [data-anim] .dg-reads .r3{animation-delay:.3s}
  .js [data-anim] .dg-reads :is(.a1,.a2){animation:dg-back2 8s linear infinite both}
  .js [data-anim] .dg-reads .a2{animation-delay:.15s}
  .js [data-anim] .dg-reads .a3{animation:dg-back1 8s linear .3s infinite both}
  .js [data-anim] .dg-reads :is(.silent-frame,.state.silent:not(.still)){animation:dg-silent 8s steps(1,end) .3s infinite both}
  .js [data-anim] .dg-reads .port.lit{animation:dg-lit 8s steps(1,end) infinite both}
  .js [data-anim] .dg-reads .record-ring{animation:dg-ring 8s steps(1,end) infinite both}
  @keyframes dg-out2{0%{stroke-dashoffset:.1}14%{stroke-dashoffset:-1.1}14.1%,50%{stroke-dashoffset:.1}64%,100%{stroke-dashoffset:-1.1}}
  @keyframes dg-back2{0%,16%{stroke-dashoffset:.1}30%{stroke-dashoffset:-1.1}30.1%,66%{stroke-dashoffset:.1}80%,100%{stroke-dashoffset:-1.1}}
  @keyframes dg-back1{0%,66%{stroke-dashoffset:.1}80%,100%{stroke-dashoffset:-1.1}}
  @keyframes dg-silent{0%{opacity:0}31%{opacity:1}80%{opacity:0}}
  @keyframes dg-lit{0%{fill:none;stroke:var(--dg-stroke)}30%{fill:var(--cv-blue);stroke:var(--cv-blue)}49%{fill:none;stroke:var(--dg-stroke)}80%{fill:var(--cv-blue);stroke:var(--cv-blue)}98%{fill:none;stroke:var(--dg-stroke)}}
  @keyframes dg-ring{0%{opacity:0}30%{opacity:1}49%{opacity:0}80%{opacity:1}98%{opacity:0}}
  /* Security: a request comes in from a browser; reads go out to switches and servers and their answers come back. */
  .js [data-anim] .dg-boundary .flow{animation:dg-out1 6s linear infinite both}
  .js [data-anim] .dg-boundary .b2{animation-delay:1.5s}.js [data-anim] .dg-boundary .b3{animation-delay:2.9s}
  .js [data-anim] .dg-boundary .b4{animation-delay:1.8s}.js [data-anim] .dg-boundary .b5{animation-delay:3.2s}
  @keyframes dg-out1{0%{stroke-dashoffset:.1}22%,100%{stroke-dashoffset:-1.1}}
  /* Docs: the read arrives and is stamped, the link reaches the equipment, then work and evidence attach. */
  .js [data-anim] .dg-keeps .flow{animation:dg-out1 7s linear infinite both}
  .js [data-anim] .dg-keeps .k2{animation-delay:1.7s}.js [data-anim] .dg-keeps .k3{animation-delay:3.2s}.js [data-anim] .dg-keeps .k4{animation-delay:3.4s}
  .js [data-anim] .dg-keeps .stamp{animation:dg-pop 7s var(--cv-ease-enter) infinite both}
  .js [data-anim] .dg-keeps .record-ring{animation:dg-hold 7s steps(1,end) infinite both}
  @keyframes dg-pop{0%,19%{transform:scale(0)}23%,92%{transform:scale(1)}100%{transform:scale(0)}}
  @keyframes dg-hold{0%{opacity:0}40%{opacity:1}76%{opacity:0}}
  /* Trust: the bundle and its signature reach the appliance, the check runs, the tick closes it, the updater installs. */
  .js [data-anim] .dg-check .flow{animation:dg-out1 6s linear infinite both}
  .js [data-anim] .dg-check .c2{animation-delay:1.2s}.js [data-anim] .dg-check .c3{animation-delay:3.4s}
  .js [data-anim] .dg-check .record-ring.check{animation:dg-scan 6s ease-in-out infinite both}
  .js [data-anim] .dg-check :is(.tick-c,.tick-p){animation:dg-tick 6s var(--cv-ease-enter) infinite both}
  @keyframes dg-scan{0%,36%{opacity:0}40%{opacity:1}46%{opacity:.35}50%{opacity:1}54%,100%{opacity:0}}
  @keyframes dg-tick{0%,52%{transform:scale(0)}56%,94%{transform:scale(1)}100%{transform:scale(0)}}
}

/* ---------- The motion: CSS only; platinum.js adds .cv-run while a drawing may move. ---------- */
@media (prefers-reduced-motion:no-preference){
  .js [data-anim]:not(.cv-run)::before,.js [data-anim]:not(.cv-run) *,.js [data-anim]:not(.cv-run) *::before,.js [data-anim]:not(.cv-run) *::after{animation-play-state:paused!important}
  .js [data-anim] .a-draw{stroke-dasharray:1 1;animation:cv-draw var(--cv-dur-draw) var(--cv-ease-enter) both}
  .js [data-anim] .a-pop{transform-box:fill-box;transform-origin:center;animation:cv-pop 420ms var(--cv-ease-enter) both}
  .js [data-anim] .pulse{visibility:visible;stroke-dasharray:.02 2}
  .js [data-anim] .d1{animation-delay:180ms}.js [data-anim] .d2{animation-delay:360ms}.js [data-anim] .d3{animation-delay:540ms}
  .js [data-anim] .d4{animation-delay:720ms}.js [data-anim] .d5{animation-delay:900ms}.js [data-anim] .d6{animation-delay:1080ms}
  .js [data-anim] .d7{animation-delay:1260ms}.js [data-anim] .d8{animation-delay:1440ms}.js [data-anim] .d9{animation-delay:1620ms}
  .js [data-anim] .d10{animation-delay:1800ms}
  @keyframes cv-draw{from{stroke-dashoffset:1}to{stroke-dashoffset:0}}
  @keyframes cv-pop{from{transform:scale(0)}}
  @keyframes cv-travel{0%{stroke-dashoffset:.1}50%,100%{stroke-dashoffset:-1.1}}
  /* Reports: the question types itself (2 s), the bars answer, it holds, then asks again; every 9 s. */
  .js [data-anim] .rp-cover{animation:cv-rp-cover 9s infinite both}
  .js [data-anim] .rp-caret{animation:cv-rp-caret 9s infinite both}
  .js [data-anim] .rp-bar{transform-box:fill-box;transform-origin:left center;animation:cv-rp-bar 9s var(--cv-ease-enter) infinite both}
  @keyframes cv-rp-cover{0%{transform:scaleX(1);animation-timing-function:steps(20,end)}24%{transform:scaleX(.76)}25%,100%{transform:scaleX(0)}}
  @keyframes cv-rp-caret{0%{transform:translateX(0);opacity:1;animation-timing-function:steps(20,end)}24%{transform:translateX(161px);opacity:1}25%,100%{transform:translateX(161px);opacity:0}}
  @keyframes cv-rp-bar{0%,26%{transform:scaleX(0)}36%,100%{transform:scaleX(1)}}
  .js [data-anim].once *{animation-iteration-count:1!important}
  /* Monitoring: reads travel out; the closet switch ripples; its dependents are marked in turn. */
  .js [data-anim] .mo-pulse{animation:cv-travel 4s linear 1.6s infinite both}
  .js [data-anim] .mo-rip{transform-box:fill-box;transform-origin:center;animation:cv-mo-rip 3s var(--cv-ease-enter) 1.6s infinite both}
  .js [data-anim] .mo-dep{animation:cv-mo-dep 6s 1.6s infinite both}
  @keyframes cv-mo-rip{from{transform:scale(.7);opacity:.55}to{transform:scale(2.4);opacity:0}}
  @keyframes cv-mo-dep{0%,8%{opacity:0}16%,80%{opacity:1}92%,100%{opacity:0}}
  /* Closets: the free ports glow, left to right. */
  .js [data-anim] .cl-free{animation:cv-cl-free 4s 1.6s infinite both}
  @keyframes cv-cl-free{0%,10%{fill:var(--cv-well);stroke:var(--cv-faint)}20%,55%{fill:var(--cv-blue);stroke:var(--cv-blue)}70%,100%{fill:var(--cv-well);stroke:var(--cv-faint)}}
  /* Network record: a token runs the record's life; each stop lights as it passes. */
  .js [data-anim] .nr-pulse{animation:cv-travel 8s linear 1s infinite both}
  .js [data-anim] .nr-stop{animation:cv-nr-stop 8s 1s infinite both}
  @keyframes cv-nr-stop{0%,4%{opacity:0}8%,40%{opacity:1}50%,100%{opacity:0}}
  /* K-12: the 2025 tags, then the 2026 tags; a marker travels the funding ring. */
  .js [data-anim] .km-2025{animation:cv-km-a 6s 2s infinite both}
  .js [data-anim] .km-2026{animation:cv-km-a 6s 5s infinite both}
  @keyframes cv-km-a{0%,4%{fill:var(--cv-card);stroke:var(--cv-line)}10%,44%{fill:var(--cv-blue-soft);stroke:var(--cv-blue)}52%,100%{fill:var(--cv-card);stroke:var(--cv-line)}}
  .js [data-anim] .kr-pulse{animation:cv-travel 10s linear 2s infinite both}
  /* Enterprise: a check runs the audit chain and each block verifies in turn. */
  .js [data-anim] .ac-pulse{animation:cv-travel 6s linear 1.2s infinite both}
  .js [data-anim] .ac-ok{animation:cv-ac-ok 6s 1.2s infinite both}
  @keyframes cv-ac-ok{0%{opacity:0}6%,50%{opacity:1}60%,100%{opacity:0}}
  /* Stagger for loops, after the loops so it wins. */
  .js [data-anim] .k1{animation-delay:1.6s}.js [data-anim] .k2{animation-delay:1.9s}.js [data-anim] .k3{animation-delay:2.2s}
  .js [data-anim] .k4{animation-delay:2.5s}.js [data-anim] .k5{animation-delay:2.8s}.js [data-anim] .k6{animation-delay:3.1s}
  .js [data-anim] .mo-rip.k3{animation-delay:3.1s}
  .js [data-anim] .nr-stop.k1{animation-delay:1s}.js [data-anim] .nr-stop.k2{animation-delay:2.33s}.js [data-anim] .nr-stop.k3{animation-delay:3.67s}
  .js [data-anim] .nr-stop.k4{animation-delay:5s}.js [data-anim] .nr-stop.k5{animation-delay:6.33s}.js [data-anim] .nr-stop.k6{animation-delay:7.67s}
  .js [data-anim] .ac-ok.k1{animation-delay:1.3s}.js [data-anim] .ac-ok.k2{animation-delay:2.7s}.js [data-anim] .ac-ok.k3{animation-delay:4.1s}.js [data-anim] .ac-ok.k4{animation-delay:5.5s}
}

/* ---------- The wide row: a narrow column of text beside a wide visual ---------- */
.cv-wide-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.9fr);gap:56px;align-items:center}
.cv-wide-row.flip>:first-child{order:2}
.cv-wide-text{display:grid;gap:14px;align-content:start}
.cv-wide-text>p{color:var(--cv-muted);font-size:var(--cv-fs-lead);line-height:1.55}
.cv-wide-text .cv-ticks{margin:4px 0 6px}

/* ---------- The bento: uneven tiles, each one headline and one visual ---------- */
.cv-bento{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:20px}
.cv-tile{grid-column:span 2;display:flex;flex-direction:column;overflow:hidden;min-width:0}
.cv-tile-text{padding:22px 22px 18px;display:flex;flex-direction:column;gap:8px}
.cv-tile-text p{color:var(--cv-muted);font-size:var(--cv-fs-small)}
.cv-tile-text .cv-link{margin-top:auto;padding-top:6px}
.cv-tile-shot{margin:0 0 0 22px;flex:1;min-height:170px;max-height:200px;overflow:hidden;border-top-left-radius:var(--cv-radius-sm);border:1px solid var(--cv-line-soft);border-right:0;border-bottom:0;background:var(--cv-chrome-2)}
.cv-tile-shot img{display:block;width:150%;max-width:none;height:auto}
.cv-tile.wide{grid-column:span 4;flex-direction:row}
.cv-tile.wide .cv-tile-text{flex:0 0 38%;padding:28px 0 28px 28px}
.cv-tile.wide .cv-tile-text h3,.cv-tile.full .cv-tile-text h3{font-size:var(--cv-fs-subhead);line-height:1.3}
.cv-tile.wide .cv-tile-shot{margin:28px 0 0 28px;max-height:none;min-height:0}
.cv-tile.wide .cv-tile-shot img{width:120%}
.cv-tile.full{grid-column:span 6;flex-direction:row;align-items:center;gap:32px;padding:8px 28px 8px 0}
.cv-tile.full .cv-tile-text{flex:0 0 32%;padding:28px 0 28px 28px}
.cv-tile.full .cv-drawing{flex:1}

/* ---------- The strip: facts on one line, hairlines between, no cards ---------- */
.cv-strip{list-style:none;margin:0;padding:0;display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);border-top:1px solid var(--cv-line)}
.cv-strip li{position:relative;padding:20px 24px 4px 0;display:grid;gap:8px;align-content:start}
.cv-strip li+li{padding-left:24px;border-left:1px solid var(--cv-line)}
.cv-strip li::before{content:"";position:absolute;top:-1px;left:0;width:40px;height:2px;background:var(--cv-blue)}
.cv-strip li+li::before{left:24px}
.cv-strip p{color:var(--cv-muted);font-size:var(--cv-fs-small)}

/* ---------- The timeline: stops on a line; it draws once, or fills as it scrolls past (scrub) ---------- */
.cv-tl{list-style:none;margin:0;padding:0;display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);gap:28px}
.cv-tl>li{position:relative;padding-top:40px;display:grid;gap:8px;align-content:start}
.cv-tl>li::before{content:"";position:absolute;z-index:1;left:0;top:6px;width:16px;height:16px;border-radius:50%;background:var(--cv-card);border:2px solid var(--cv-blue);box-sizing:border-box}
.cv-tl>li::after{content:"";position:absolute;left:24px;right:-20px;top:13px;height:2px;background:var(--cv-blue);border-radius:1px;transform-origin:left center}
.cv-tl>li:last-child::after{right:0;background:var(--cv-line)}
.cv-tl p{color:var(--cv-muted);font-size:var(--cv-fs-small)}
.cv-tl.scrub>li::after{background:var(--cv-blue)}
@media (prefers-reduced-motion:no-preference){
  .js .cv-tl[data-anim]>li::after{animation:cv-grow 600ms var(--cv-ease-enter) both}
  .js .cv-tl[data-anim]>li:nth-child(2)::after{animation-delay:500ms}.js .cv-tl[data-anim]>li:nth-child(3)::after{animation-delay:1000ms}
  .js .cv-tl[data-anim]>li:nth-child(4)::after{animation-delay:1500ms}.js .cv-tl[data-anim]>li:nth-child(5)::after{animation-delay:2000ms}
  @keyframes cv-grow{from{transform:scaleX(0)}}
  @supports (animation-timeline:view()){
    .cv-tl.scrub{view-timeline-name:--cv-tl}
    .cv-tl.scrub>li::after{animation:cv-grow linear both;animation-timeline:--cv-tl}
    .cv-tl.scrub>li:nth-child(1)::after{animation-range:cover 15% cover 30%}
    .cv-tl.scrub>li:nth-child(2)::after{animation-range:cover 30% cover 45%}
    .cv-tl.scrub>li:nth-child(3)::after{animation-range:cover 45% cover 60%}
    .cv-tl.scrub>li:nth-child(4)::after{animation-range:cover 60% cover 70%}
  }
}

/* ---------- The numbered path (Live demo): numbers down a line ---------- */
.cv-path{counter-reset:pa;list-style:none;margin:0;padding:0;display:grid;gap:0;max-width:880px}
.cv-path>li{counter-increment:pa;position:relative;padding:0 0 30px 64px;min-height:72px}
.cv-path>li::before{content:counter(pa);position:absolute;z-index:1;left:4px;top:0;width:32px;height:32px;border-radius:50%;background:var(--cv-blue);color:var(--cv-on-blue);font-size:15px;font-weight:500;display:grid;place-items:center}
.cv-path>li::after{content:"";position:absolute;left:19px;top:32px;bottom:0;width:2px;background:var(--cv-blue);opacity:.35;transform-origin:center top}
.cv-path>li:last-child::after{display:none}
.cv-path h3{padding-top:4px}
.cv-path .cv-links{margin-top:10px}
@media (prefers-reduced-motion:no-preference){
  .js .cv-path[data-anim]>li::after{animation:cv-grow-y 500ms var(--cv-ease-enter) both}
  .js .cv-path[data-anim]>li:nth-child(2)::after{animation-delay:300ms}.js .cv-path[data-anim]>li:nth-child(3)::after{animation-delay:600ms}
  .js .cv-path[data-anim]>li:nth-child(4)::after{animation-delay:900ms}.js .cv-path[data-anim]>li:nth-child(5)::after{animation-delay:1200ms}
  @keyframes cv-grow-y{from{transform:scaleY(0)}}
}

/* ---------- The pinned stage (product overview): the screen holds while the steps scroll past ---------- */
.cv-stage{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.55fr);gap:56px;align-items:start}
.cv-stage-steps{list-style:none;margin:0;padding:0}
.cv-stage-step{min-height:clamp(320px,52vh,480px);display:flex;flex-direction:column;justify-content:center;gap:10px;padding:24px 0 24px 26px;border-left:2px solid var(--cv-line);transition:border-color var(--cv-dur) var(--cv-ease)}
.cv-stage-step.on{border-left-color:var(--cv-blue)}
.cv-stage-step h3{font-size:var(--cv-fs-subhead);line-height:1.3}
.cv-stage-step p{color:var(--cv-muted)}
.cv-stage-step .cv-k{font-size:var(--cv-fs-meta);color:var(--cv-blue-text);font-weight:500}
.cv-stage-view{position:sticky;top:calc(var(--cv-bar) + 32px)}
.cv-stage-view .cv-tour img.on,.cv-stage-view .cv-tour img[data-shot].on{opacity:1}
.cv-stage-map{display:block;width:100%;height:auto;margin-bottom:16px}
.cv-stage-map .node{fill:var(--cv-card);stroke:var(--cv-faint);stroke-width:1.6;transition:fill var(--cv-dur) var(--cv-ease),stroke var(--cv-dur) var(--cv-ease)}
.cv-stage-map .node.on{fill:var(--cv-blue);stroke:var(--cv-blue)}

/* ---------- The pillar hub (Trust): six pillars around the appliance, spokes drawn in ---------- */
.cv-hub{position:relative;display:grid;grid-template-columns:minmax(0,1fr) 260px minmax(0,1fr);gap:0;align-items:stretch}
.cv-hub::before{content:"";position:absolute;left:50%;top:calc((100% - 32px) / 6);bottom:calc((100% - 32px) / 6);width:2px;margin-left:-1px;background:var(--cv-blue);opacity:.5;transform-origin:center}
.cv-hub-side{list-style:none;margin:0;padding:0;display:grid;gap:16px;grid-auto-rows:1fr}
.cv-hub-side>li{display:grid}
.cv-pillar{position:relative;padding:20px 22px;display:grid;gap:6px}
.cv-pillar h3 a::after{content:"";position:absolute;inset:0}
.cv-pillar p{color:var(--cv-muted);font-size:var(--cv-fs-small)}
.cv-pillar::before{content:"";position:absolute;top:50%;width:131px;height:2px;background:var(--cv-blue);opacity:.5}
.cv-hub-side.left .cv-pillar::before{left:100%;transform-origin:left center}
.cv-hub-side.right .cv-pillar::before{right:100%;transform-origin:right center}
.cv-hub-core{position:relative;z-index:1;align-self:center;justify-self:center;width:180px;height:180px;border-radius:50%;display:grid;place-content:center;text-align:center;gap:6px;padding:24px;background:var(--cv-card);border:1px solid var(--cv-blue);box-shadow:0 0 0 8px var(--cv-page),0 0 0 9px var(--cv-line),0 0 36px -4px var(--cv-blue-soft)}
.cv-hub-core strong{font-size:var(--cv-fs-card);font-weight:500;line-height:1.3}
.cv-hub-core span{font-size:var(--cv-fs-meta);color:var(--cv-muted)}
@media (prefers-reduced-motion:no-preference){
  .js .cv-hub[data-anim] .cv-pillar::before{animation:cv-grow 500ms var(--cv-ease-enter) both}
  .js .cv-hub[data-anim]::before{animation:cv-grow-y 600ms var(--cv-ease-enter) 500ms both}
  .js .cv-hub[data-anim] li:nth-child(2) .cv-pillar::before{animation-delay:200ms}.js .cv-hub[data-anim] li:nth-child(3) .cv-pillar::before{animation-delay:400ms}
}

/* ---------- The facts table that closes a capability page ---------- */
.cv-frow{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.7fr);gap:40px;padding:28px 0}
.cv-frow+.cv-frow{border-top:1px solid var(--cv-line-soft)}
.cv-fhead{display:grid;gap:6px;align-content:start}
.cv-fhead p{color:var(--cv-muted);font-size:var(--cv-fs-small)}
.cv-frow .cv-ticks{margin-bottom:10px}
.cv-guides{display:flex;flex-wrap:wrap;gap:10px 28px;margin-top:22px}

/* ---------- Routes as the hero (How to buy) and the ring row (K-12) ---------- */
.cv-routes{list-style:none;margin:40px 0 0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));border-top:2px solid var(--cv-ink)}
.cv-routes>li{padding:22px 28px 6px 0;display:grid;gap:10px;align-content:start;scroll-margin-top:24px}
.cv-routes>li+li{padding-left:28px;border-left:1px solid var(--cv-line)}
.cv-routes h2{font-size:var(--cv-fs-subhead);line-height:1.3}
.cv-routes .cv-k{font-size:var(--cv-fs-meta);color:var(--cv-blue-text);font-weight:500}
.cv-routes ul{margin:0;padding-left:18px;color:var(--cv-muted);font-size:var(--cv-fs-small);display:grid;gap:6px}
.cv-ring-row{display:grid;grid-template-columns:320px minmax(0,1fr);gap:56px;align-items:center}
.cv-ring-row .cv-drawing{padding:20px}
.cv-phases{counter-reset:ph;list-style:none;margin:0;padding:0;display:grid;gap:16px}
.cv-phases li{counter-increment:ph;position:relative;padding-left:44px;display:grid;gap:2px}
.cv-phases li::before{content:counter(ph);position:absolute;left:0;top:0;width:28px;height:28px;border-radius:50%;border:1.6px solid var(--cv-blue);color:var(--cv-blue-text);font-size:15px;font-weight:500;display:grid;place-items:center;box-sizing:border-box}
.cv-phases p{color:var(--cv-muted);font-size:var(--cv-fs-small)}
/* Live demo: the demo is the hero. */
.cv-demo-stage{position:relative;margin-top:36px}
.cv-demo-stage .cv-frame img{max-height:none}
/* Centered with translate, not transform, so the hero buttons' hover lift (a transform) never undoes the centering
   and slides the button sideways (owner, 2026-10-18). */
.cv-demo-go{position:absolute;left:50%;bottom:32px;translate:-50% 0;box-shadow:var(--cv-shadow);min-height:48px;padding:0 24px;font-size:17px}
.cv-hero-center{text-align:center;display:grid;justify-items:center}
.cv-hero-center .cv-lead{margin-inline:auto}
.cv-quiet-list{display:flex;flex-wrap:wrap;gap:8px 28px;margin-top:20px;font-size:var(--cv-fs-small);color:var(--cv-muted)}

@media (max-width:1023px){
  .cv-hero-copy,.cv-wide-row,.cv-annotated,.cv-stage,.cv-frow,.cv-ring-row{grid-template-columns:1fr;gap:28px}
  .cv-wide-row.flip>:first-child{order:0}
  .cv-stage-view{position:static;order:-1}
  .cv-stage-step{min-height:0}
  .cv-bento{grid-template-columns:repeat(2,minmax(0,1fr))}
  .cv-tile,.cv-tile.wide,.cv-tile.full{grid-column:span 2;flex-direction:column;padding:0}
  .cv-tile.wide .cv-tile-text,.cv-tile.full .cv-tile-text{flex:none;padding:22px}
  .cv-tile.full .cv-drawing{padding:0 22px 22px}
  .cv-hub{grid-template-columns:1fr;gap:16px}
  .cv-hub-side{grid-auto-rows:auto}
  .cv-hub-core{order:-1}
  .cv-pillar::before,.cv-hub::before{display:none}
  .cv-strip,.cv-tl{grid-auto-flow:row}
  .cv-strip li+li{padding-left:0;border-left:0;border-top:1px solid var(--cv-line)}
  .cv-tl>li::after{display:none}
  .cv-routes{grid-template-columns:1fr}
  .cv-routes>li+li{padding-left:0;border-left:0;border-top:1px solid var(--cv-line)}
}
@media (max-width:720px){
  .cv-bento{grid-template-columns:1fr}
  .cv-tile,.cv-tile.wide,.cv-tile.full{grid-column:auto}
  .cv-demo-go{position:static;translate:none;margin-top:16px}
}
.cv-strip .cv-link{display:flex;width:max-content;margin-top:10px}
.cv-trust-net{margin-top:36px;scroll-margin-top:24px}
.cv-pair{margin-top:28px;align-items:start}
.cv-narrow{max-width:900px}
.cv-narrow .cv-annotated{grid-template-columns:1fr}
.cv-demo-shot{display:block}
.cv-demo-shot .cv-frame{transition:box-shadow var(--cv-dur) var(--cv-ease)}
.cv-demo-stage .cv-btn.cv-demo-go{bottom:72px}
.cv-hero-center.cv-fine{display:flex;justify-content:center;align-items:center;gap:8px}
/* A section background: a rack elevation (patch panels, a switch stack and its ports, a UPS) in the empty right side of
   Live demo's Things to try, quiet behind nothing but the field. Its box is the content column, so the drawing ends on
   the content's right edge (a percentage in mask-position would count from the space left over, not the page). */
section[aria-labelledby="demo-try"]{position:relative;isolation:isolate}
section[aria-labelledby="demo-try"]::before{content:"";position:absolute;inset:0 max(var(--cv-gutter),calc(50% - var(--cv-container) / 2));z-index:-1;pointer-events:none;
  background:url('/assets/h/field-rack-light.4fafc997f8.svg') right center/306px 522px no-repeat}
/* A Pause button keeps its place before it shows, so revealing it never moves the caption. */
.cv-motion-btn[hidden]{display:inline-block!important;visibility:hidden}

