/* =======================================================================
     NexusSec vLabs — book a private lab, learn in the browser

     The dot field from the homepage reference, retargeted: same sampling
     technique, but it resolves into the FIVE-bar NXSVL mark rather than the
     three-bar NexusSec Labs one, because this domain is the lab product.

     One file on purpose. A holding page that depends on a stylesheet, a
     script bundle and a font is three things that can fail before anyone
     sees the word "soon". Everything here except the webfont is inline, and
     the webfont has a real fallback stack.
     ======================================================================= */

  /* ---- DEFAULT: LIGHT. On bare :root so a visitor with JavaScript blocked
       still gets the default rather than the opt-in. ---- */
  :root {
    color-scheme: light;

    --fg-rgb:    16,26,42;
    --line-rgb:  30,52,92;
    --steel-rgb: 47,95,196;
    --surf-rgb:  255,255,255;
    --ink-rgb:   246,248,252;  /* page ground, for scrims */

    --ink:    #f6f8fc;
    --hi:     #0a1020;
    --cream:  #24303f;
    --steel:  #2f5fc4;
    --steel-hover: #24499b;
    --on-steel:    #fff;
    --electric:#2f5fc4;
    --signal: #17794a;
    --dim:    #2f5fc4;
    --muted:  rgba(var(--fg-rgb), .70);

    --logo-filter: brightness(0);

    --dot-lit:  rgb(74,122,224);
    --dot-pale: rgb(150,168,196);
    --dot-dim:  rgb(110,142,198);

    --gut:    clamp(24px, 8vw, 132px);
    --head-h: 72px;
    --sans: "Manrope", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  }

  /* ---- Dark, opt-in. theme.js stamps data-theme="dark". ---- */
  :root[data-theme="dark"] {
    color-scheme: dark;

    /* Colours are stored as rgb TRIPLETS wherever an alpha is applied, so
       every existing rgba() keeps its own opacity and only the base colour
       flips. That is why dark is pixel-identical to before the theme. */
    --fg-rgb:    255,255,255;   /* text        */
    --line-rgb:  174,198,248;   /* hairlines   */
    --steel-rgb: 126,163,243;   /* accent      */
    --surf-rgb:  10,16,22;      /* panel/scrim */
    --ink-rgb:   11,17,21;

    --hi:          #fff;
    --steel-hover: #9dbaf7;
    --on-steel:    #08111f;

    /* Vendor SVGs carry their own brand colours and several are near-black,
       so they are crushed flat and inverted to read on dark. On light they
       are crushed WITHOUT the invert, or they vanish. */
    --logo-filter: brightness(0) invert(1);

    /* The hero field is drawn in JS; it reads these instead of hardcoding. */
    --dot-lit:  rgb(126,163,243);
    --dot-pale: rgb(230,236,245);
    --dot-dim:  rgb(174,198,248);

    --ink:    #0b1115;
    --cream:  #e6ecf5;
    --steel:  #7ea3f3;
    --electric:#89aaff;
    --signal: #79e4b3;
    --dim:    #aec6f8;
    --muted:  rgba(var(--fg-rgb), .62);
    /* ONE gutter for the whole page. The header used to override this with its
       own clamp and sat 43px left of everything below it, all the way down. */
  }

  /* Only while the toggle is pressed — never on load, never for anyone who
     asked for reduced motion. */
  :root.theme-anim, :root.theme-anim * {
    transition: background-color .2s ease, color .2s ease,
                border-color .2s ease, fill .2s ease !important;
  }
  @media (prefers-reduced-motion: reduce) {
    :root.theme-anim, :root.theme-anim * { transition: none !important; }
  }

  * { box-sizing: border-box; }
  html, body { margin: 0; padding: 0; background: var(--ink); }

  body {
    min-height: 100vh;
    color: var(--cream);
    font-family: var(--sans);
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
  }

  a { color: var(--dim); text-decoration: none; transition: color .18s; }
  a:hover { color: var(--hi); }

  /* ---- The field ---- */

  #stage {
    position: relative;
    min-height: 100vh;
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    /* NO overflow here. An ancestor with overflow makes position:sticky bind to
       that box instead of the viewport, which is why the header scrolled away
       while reporting position:sticky. The field it used to clip is
       position:fixed with its own overflow:hidden, so nothing needs it. */
  }

  #field { position: fixed; inset: 0; overflow: hidden; }
  #halo  { position: absolute; inset: 0; }
  #mark  {
    position: absolute; left: 58%; top: 42%;
    height: 74%; aspect-ratio: 1;
    transform: translate(-50%, -50%);
  }
  .dot { position: absolute; border-radius: 1px; }

  #ring {
    position: absolute; left: 58%; top: 42%;
    width: 62%; aspect-ratio: 1; border-radius: 50%;
    background: radial-gradient(circle, rgba(var(--fg-rgb), .15) 0%, rgba(var(--fg-rgb), 0) 62%);
    transform: translate(-50%, -50%) scale(.55);
  }
  #sweep {
    position: absolute; top: -20%; bottom: -20%; left: 0; width: 26%;
    background: linear-gradient(90deg, rgba(var(--fg-rgb), 0), rgba(var(--fg-rgb), .06), rgba(var(--fg-rgb), 0));
    pointer-events: none;
  }
  #vignette {
    position: fixed; inset: 0; pointer-events: none;
    background:
      radial-gradient(120% 90% at 50% 40%, rgba(var(--fg-rgb), .05) 0%, rgba(0,0,0,0) 58%),
      linear-gradient(180deg, rgba(var(--surf-rgb), .34) 0%, rgba(0,0,0,0) 30%, rgba(var(--surf-rgb), .58) 100%);
  }

  /* ---- Motion. Every animation is opt-in under prefers-reduced-motion, and
          none of them holds an element at opacity 0 as its resting state: if
          the timeline never advances, the page still reads. ---- */
  @media (prefers-reduced-motion: no-preference) {
    #mark  { animation: drift 18s ease-in-out infinite; }
    #ring  { animation: pulse 9s cubic-bezier(.25,.6,.3,1) infinite; }
    #sweep { animation: sweep 11s linear infinite; }
    .dot   { animation: breathe var(--bd, 0s) ease-in-out var(--bg, 0s) infinite; }

    @keyframes drift {
      0%,100% { transform: translate(-50%,-50%) scale(1)     rotate(0deg); }
      50%     { transform: translate(-50%,-50%) scale(1.045) rotate(1.2deg); }
    }
    @keyframes pulse {
      0%   { transform: translate(-50%,-50%) scale(.55); opacity: 0; }
      22%  { opacity: .34; }
      100% { transform: translate(-50%,-50%) scale(1.65); opacity: 0; }
    }
    @keyframes sweep {
      from { transform: translateX(-60%) skewX(-18deg); }
      to   { transform: translateX(220%) skewX(-18deg); }
    }
    @keyframes breathe { 0%,100% { opacity: var(--a0); } 50% { opacity: var(--a1); } }
  }

  /* ---- Content ---- */

  .shell {
    position: relative; z-index: 2;
    width: 100%; max-width: none; margin: 0 auto;
    /* padding-INLINE only. As a shorthand this also set padding-block:0, which
       silently flattened the footer — it kept its own vertical padding rule and
       lost to this one on specificity. */
    padding-inline: var(--gut);
  }

  /* header.shell, not header: .shell already sets position:relative and would
     otherwise win on specificity, leaving this stuck-looking but not sticky. */
  header.shell {
    position: sticky; top: 0; z-index: 20;
    min-height: var(--head-h);
    display: flex; align-items: center; justify-content: space-between; gap: 24px;
    /* Transparent until you scroll past the hero. The field behind it is the
       point of this page; a bar sitting on it from the first pixel would cover
       the one thing the visitor came to look at. */
    border-bottom: 1px solid transparent;
    transition: background .28s ease, border-color .28s ease;
  }
  header.shell.is-stuck {
    background: rgba(var(--surf-rgb), .82);
    backdrop-filter: blur(14px) saturate(140%);
    border-bottom-color: rgba(var(--line-rgb), .16);
  }
  @media (prefers-reduced-motion: reduce) { header { transition: none; } }
  .brand { display: inline-flex; align-items: center; gap: 12px; }
  .brand img { width: 34px; height: 34px; display: block; }
  .brand-txt { display: flex; flex-direction: column; line-height: 1; }
  .brand-txt b { font-size: 20px; font-weight: 800; letter-spacing: -.03em; color: var(--hi); }
  .brand-txt b i { font-style: normal; color: var(--steel); }
  .brand-txt span {
    margin-top: 5px; font: 500 8.5px/1 var(--mono);
    letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
  }

  .header-actions { display: flex; align-items: center; gap: 19px; }
  .header-actions a:first-child { color: rgba(var(--fg-rgb), .61); font: 600 11px/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; }
  .header-actions a:first-child:hover { color: var(--hi); }
  .header-actions .header-cta {
    min-height: 38px; padding: 0 15px; display: inline-flex; align-items: center;
    border: 1px solid rgba(var(--line-rgb), .34); border-radius: 5px;
    color: var(--cream); font-size: 12px; font-weight: 700;
  }
  .header-actions .header-cta:hover { border-color: var(--steel); background: rgba(var(--steel-rgb), .1); }

  main { min-height: calc(100svh - 88px); display: flex; align-items: center; padding: clamp(38px, 6vh, 78px) 0; }
  .hero-layout { width: 100%; }
  .hero-copy { position: relative; max-width: 640px; }

  .badge {
    display: inline-flex; align-items: center; gap: 9px;
    padding: 6px 13px; border-radius: 999px; margin-bottom: 22px;
    border: 1px solid rgba(var(--steel-rgb), .34);
    background: rgba(var(--steel-rgb), .10);
    font: 500 10.5px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase;
    color: var(--dim);
  }
  .badge s { width: 6px; height: 6px; border-radius: 50%; background: var(--steel); }
  @media (prefers-reduced-motion: no-preference) {
    .badge s { animation: blip 2.4s ease-in-out infinite; }
    @keyframes blip { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
  }

  h1 {
    margin: 0 0 18px;
    font-size: clamp(32px, 4.6vw, 50px);
    font-weight: 800; line-height: 1.05; letter-spacing: -.035em;
    color: var(--hi); max-width: 13ch; text-wrap: balance;
  }
  h1 em { font-style: normal; color: var(--steel); }

  .lede {
    margin: 0 0 30px; max-width: 56ch;
    font-size: clamp(15px, 1.6vw, 17.5px); line-height: 1.62; color: rgba(var(--fg-rgb), .76);
  }

  .capabilities { display: flex; flex-wrap: wrap; gap: 8px; margin: -4px 0 29px; }
  .capabilities span { padding: 7px 10px; border: 1px solid rgba(var(--line-rgb), .2); background: rgba(var(--surf-rgb), .4); border-radius: 3px; color: rgba(var(--fg-rgb), .67); font: 500 10px/1.2 var(--mono); letter-spacing: .08em; text-transform: uppercase; }

  .actions { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-bottom: 26px; }
  .btn {
    display: inline-flex; align-items: center; gap: 9px;
    min-height: 46px; padding: 0 22px; border-radius: 6px;
    font-size: 14.5px; font-weight: 700; border: 1px solid transparent;
    transition: background .18s, border-color .18s, color .18s;
  }
  .btn-solid  { background: var(--steel); color: var(--on-steel); }
  .btn-solid:hover { background: var(--steel-hover); color: var(--on-steel); }
  .btn-ghost  { border-color: rgba(var(--line-rgb), .34); color: var(--cream); }
  .btn-ghost:hover { border-color: var(--steel); color: var(--hi); background: rgba(var(--steel-rgb), .08); }

  .stats { display: flex; flex-wrap: wrap; gap: clamp(22px, 4vw, 40px); }
  .stats div b {
    display: block; font-size: clamp(19px, 2.4vw, 23px); font-weight: 800;
    letter-spacing: -.03em; color: var(--hi); font-variant-numeric: tabular-nums;
  }
  .stats div span {
    display: block; margin-top: 5px;
    font: 400 10.5px/1.3 var(--mono); letter-spacing: .14em;
    text-transform: uppercase; color: rgba(var(--fg-rgb), .58);
  }

  /* A slow platform ticker makes the breadth of the labs visible while the
     NXSVL product mark remains the hero. */
  .platform-rail { width: min(100%, 960px); margin-top: clamp(37px, 5vw, 60px); overflow: hidden; border-top: 1px solid rgba(var(--line-rgb), .17); border-bottom: 1px solid rgba(var(--line-rgb), .17); mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); }
  .platform-track { display: flex; width: max-content; align-items: center; }
  @media (prefers-reduced-motion: no-preference) {
    .platform-track { animation: platform-scroll 32s linear infinite; }
  }
  @media (prefers-reduced-motion: reduce) {
    /* No marquee. One static row, centred, and the duplicate set hidden so the
       logos are not announced twice. */
    .platform-track { width: 100%; justify-content: center; flex-wrap: wrap; }
    .platform-set[aria-hidden="true"] { display: none; }
    .platform-set { flex-wrap: wrap; justify-content: center; padding-right: 0; }
  }
  .platform-set { display: flex; align-items: center; gap: clamp(27px, 4vw, 55px); padding: 18px clamp(14px, 2vw, 28px) 18px 0; }
  .platform-set img {
    display: block; width: auto; height: clamp(20px, 2vw, 27px);
    max-width: 132px; object-fit: contain; object-position: center;
    /* Rendered as flat white silhouettes. Every one of these SVGs carries its
       own brand colour, and several are near-black — Fortinet is #231f20 and
       Sophos #495390, both of which vanish on a #0b1115 ground. brightness(0)
       crushes each mark to black, invert(1) flips it to white, so the strip is
       legible AND visually consistent instead of a row of clashing palettes. */
    filter: var(--logo-filter);
    opacity: .58;
    transition: opacity .22s ease;
  }
  .platform-rail:hover .platform-set img,
  .platform-rail:focus-within .platform-set img { opacity: .95; }
  /* Pause on hover so a logo can actually be read. */
  .platform-rail:hover .platform-track,
  .platform-rail:focus-within .platform-track { animation-play-state: paused; }
  .platform-set img.logo-paloalto { height: clamp(18px, 1.8vw, 24px); max-width: 145px; }
  .platform-set img.logo-radware { max-width: 112px; }
  .platform-set img.logo-watchguard { max-width: 125px; }
  @media (prefers-reduced-motion: no-preference) { @keyframes platform-scroll { to { transform: translateX(-50%); } } }


  /* ---- The product story ---- */
  .story { position: relative; z-index: 2; border-top: 1px solid rgba(var(--line-rgb), .14); }
  .story-shell { width: 100%; max-width: none; margin: 0 auto; padding: clamp(74px, 11vw, 142px) clamp(24px, 8vw, 132px); }
  .section-kicker { margin: 0 0 18px; color: var(--dim); font: 500 10px/1 var(--mono); letter-spacing: .15em; text-transform: uppercase; }
  .section-kicker span { color: var(--steel); }
  .statement { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(220px, .54fr); gap: clamp(30px, 9vw, 120px); align-items: end; }
  .statement h2 { margin: 0; max-width: 13ch; color: var(--hi); font-size: clamp(28px, 3.6vw, 42px); font-weight: 800; line-height: 1.07; letter-spacing: -.05em; text-wrap: balance; }
  .statement h2 em { color: var(--steel); font-style: normal; }
  .statement > p { margin: 0; color: rgba(var(--fg-rgb), .68); font-size: 15px; line-height: 1.72; }
  .rule { margin: clamp(40px,6vw,70px) 0 0; height: 1px; background: rgba(var(--line-rgb), .16); }
  .principles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; margin-top: 1px; background: rgba(var(--line-rgb), .16); }
  .principle { min-height: 265px; padding: clamp(21px,3vw,34px); background: rgba(var(--surf-rgb), .82); }
  .principle > span { display: block; color: var(--steel); font: 500 10px/1 var(--mono); letter-spacing: .12em; }
  .principle h3 { margin: 52px 0 10px; color: var(--hi); font-size: clamp(19px,2vw,25px); letter-spacing: -.035em; }
  .principle p { margin: 0; color: rgba(var(--fg-rgb), .61); font-size: 13px; line-height: 1.65; }
  .dark-story { background: rgba(var(--surf-rgb), .76); border-top: 1px solid rgba(var(--line-rgb), .14); border-bottom: 1px solid rgba(var(--line-rgb), .14); }
  .tracks { display: grid; grid-template-columns: minmax(220px,.52fr) minmax(0,1fr); gap: clamp(42px,9vw,130px); align-items:start; }
  .tracks h2 { margin: 0; max-width: 10ch; color: var(--hi); font-size: clamp(28px,3.4vw,40px); line-height:1.06; letter-spacing:-.05em; }
  .tracks h2 em { color:var(--steel); font-style:normal; }
  .track-list { margin: 0; padding: 0; list-style: none; border-top: 1px solid rgba(var(--line-rgb), .18); }
  .track-list li { display:grid; grid-template-columns: 34px minmax(0,1fr) auto; gap: 15px; padding: 20px 0; border-bottom: 1px solid rgba(var(--line-rgb), .18); align-items: center; }
  .track-list b { color: var(--steel); font:500 10px/1 var(--mono); }
  .track-list strong { display:block; color:var(--hi); font-size:15px; letter-spacing:-.02em; }
  .track-list span { display:block; margin-top:4px; color:rgba(var(--fg-rgb), .52); font-size:12px; }
  .track-list i { color:rgba(var(--fg-rgb), .5); font-size:18px; font-style:normal; }
  .origin { display: grid; grid-template-columns: minmax(0,1fr) minmax(250px,.75fr); gap: clamp(40px,10vw,140px); align-items:center; }
  .origin-copy h2 { margin:0 0 20px; color:var(--hi); font-size:clamp(28px,3.4vw,40px); line-height:1.08; letter-spacing:-.05em; }
  .origin-copy h2 em { color:var(--steel); font-style:normal; }
  .origin-copy p { max-width:52ch; margin:0; color:rgba(var(--fg-rgb), .66); font-size:15px; line-height:1.72; }
  .origin-copy a { display:inline-flex; margin-top:25px; color:var(--dim); font-size:13px; font-weight:700; }
  .origin-card { padding:28px; border: 1px solid rgba(var(--line-rgb), .21); background:linear-gradient(135deg, rgba(var(--steel-rgb), .11), rgba(var(--fg-rgb), .025)); }
  .origin-card p { margin:0 0 25px; color:rgba(var(--fg-rgb), .58); font:500 10px/1.5 var(--mono); letter-spacing:.13em; text-transform:uppercase; }
  .origin-card b { display:block; color:var(--hi); font-size:19px; line-height:1.35; letter-spacing:-.025em; }
  .origin-card span { display:block; margin-top:16px; color:var(--steel); font:500 10px/1 var(--mono); letter-spacing:.12em; }
  .arrival { position:relative; z-index:2; overflow:hidden; padding: clamp(84px,13vw,172px) 0 clamp(54px,7vw,88px); text-align:center; }
  .arrival::before { content:""; position:absolute; left:50%; top:45%; width:min(900px,110vw); aspect-ratio:1; border-radius:50%; background:radial-gradient(circle,rgba(var(--steel-rgb), .22),rgba(var(--steel-rgb), 0) 66%); transform:translate(-50%,-50%); pointer-events:none; }
  .arrival .section-kicker, .arrival h2, .arrival p, .arrival .actions { position:relative; }
  .arrival h2 { margin:0; color:var(--hi); font-size:clamp(44px,8vw,104px); font-weight:800; line-height:.8; letter-spacing:-.09em; text-transform:uppercase; }
  .arrival h2 em { display:block; color:var(--steel); font-style:normal; }
  .arrival p { max-width:49ch; margin:33px auto 25px; color:rgba(var(--fg-rgb), .7); font-size:15px; line-height:1.7; }
  .arrival .actions { justify-content:center; margin-bottom:0; }

  footer {
    position: relative; z-index: 2;
    border-top: 1px solid rgba(var(--line-rgb), .14);
    padding-block: clamp(34px, 4vw, 54px) clamp(22px, 2.4vw, 30px);
    font-size: 12.5px; color: rgba(var(--fg-rgb), .5);
  }

  /* Brand block plus THREE link columns. This was `repeat(2, …)` while the
     markup carried three, so the last column wrapped onto a second row and sat
     orphaned under the brand. Auto-fitting is deliberately not used here: the
     brand column is a different width to the link columns, so the track list
     has to be explicit. */
  .foot-top {
    display: grid; grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr));
    gap: clamp(22px, 3vw, 44px);
    padding-bottom: clamp(26px, 3vw, 38px);
  }
  .foot-brand { display: flex; flex-direction: column; gap: 13px; align-items: flex-start; }
  .foot-brand p { margin: 0; max-width: 34ch; font-size: 13px; line-height: 1.6; color: rgba(var(--fg-rgb), .58); }
  .foot-col h2 {
    margin: 0 0 13px; font: 600 10px/1 var(--mono);
    letter-spacing: .16em; text-transform: uppercase; color: rgba(var(--fg-rgb), .5);
  }
  .foot-col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
  .foot-col a { font-size: 13.5px; color: rgba(var(--fg-rgb), .74); }
  .foot-col a:hover { color: var(--hi); }
  /* Two steps down, because there are now three link columns rather than two.
     The brand block takes the full width first — it carries a 34ch paragraph
     and is the first thing to get uncomfortably narrow. */
  @media (max-width: 980px) {
    .foot-top { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .foot-brand { grid-column: 1 / -1; }
  }
  @media (max-width: 620px) {
    .foot-top { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  }
  .foot-in {
    display: flex; flex-wrap: wrap; gap: 14px;
    justify-content: space-between; align-items: center;
    padding-top: clamp(18px, 2vw, 24px);
    border-top: 1px solid rgba(var(--line-rgb), .10);
  }
  .foot-in nav { display: flex; flex-wrap: wrap; gap: 18px; }
  .foot-product { color: rgba(var(--fg-rgb), .72); font-weight: 700; }

  :where(a, .btn):focus-visible { outline: 2px solid var(--steel); outline-offset: 3px; border-radius: 4px; }

  @media (max-width: 760px) {
    header { min-height: 62px; }
    .header-meta span { display: none; }
    .header-actions a:first-child { display:none; }
    .statement, .tracks, .origin { grid-template-columns: 1fr; }
    .principles { grid-template-columns: 1fr; }
    .principle { min-height: auto; }
    .principle h3 { margin-top: 35px; }
    .story-shell { padding-top:72px; padding-bottom:72px; }
    .arrival h2 { font-size:clamp(38px,11vw,68px); }
    #mark { left: 50%; top: 34%; width: 88%; height: auto; }
    #ring { left: 50%; top: 34%; width: 104%; }
  }
  /* ---------------------------------------------------------------------
     Theme toggle
     --------------------------------------------------------------------- */

  /* The mark ships in two files because it is a two-colour SVG: a filter that
     fixed the near-white half would wreck the accent half. CSS picks one, so
     there is no JS and nothing for the CSP to block. */
  /* .brand img already sets display:block at (0,1,1), so these have to
     out-specify it or the hidden mark renders anyway — which showed up as a
     stray blue sliver next to the logo, the only part of the near-black
     light mark visible on a dark ground. */
  .brand img.brand-mark--dark { display: none; }
  :root[data-theme="dark"] .brand img.brand-mark--light { display: none; }
  :root[data-theme="dark"] .brand img.brand-mark--dark  { display: block; }

  .theme-btn {
    display: inline-grid; place-items: center;
    width: 34px; height: 34px; padding: 0;
    background: transparent;
    border: 1px solid rgba(var(--line-rgb), .22);
    border-radius: 4px;
    color: var(--muted);
    cursor: pointer;
    transition: color .18s ease, border-color .18s ease, background-color .18s ease;
  }
  .theme-btn:hover {
    color: var(--hi);
    border-color: rgba(var(--steel-rgb), .55);
    background: rgba(var(--steel-rgb), .10);
  }
  .theme-btn:focus-visible {
    outline: 2px solid var(--steel);
    outline-offset: 2px;
  }
  .theme-btn svg {
    width: 17px; height: 17px;
    fill: none; stroke: currentColor; stroke-width: 1.7;
    stroke-linecap: round; stroke-linejoin: round;
  }
  /* Show the icon for what pressing it GIVES you, which is the convention:
     a sun while dark, a moon while light. */
  .theme-btn .t-sun { display: none; }
  :root[data-theme="dark"] .theme-btn .t-moon { display: none; }
  :root[data-theme="dark"] .theme-btn .t-sun  { display: block; }

  @media (max-width: 760px) {
    /* The nav text links already hide here; keep the toggle, it is small. */
    .theme-btn { width: 32px; height: 32px; }
  }

  /* ---------------------------------------------------------------------
     Cookie / storage notice
     Bottom-anchored rather than a centre-screen modal: nothing here is
     urgent enough to block the page, and a modal on first paint is the
     pattern everyone has learned to dismiss without reading.
     --------------------------------------------------------------------- */
  /* Bottom RIGHT, not left. A full-width bar covered "Request a free demo"
     outright; moving it to the bottom-left still covered it, because the whole
     hero — heading, chips and buttons — is left-aligned. The right half of the
     hero holds nothing but the dot field, so that is where this belongs. */
  .ck {
    position: fixed; right: clamp(14px, 3vw, 26px); bottom: clamp(14px, 3vw, 26px);
    left: auto; z-index: 60; width: min(400px, calc(100vw - 28px));
    background: var(--ink);
    border: 1px solid rgba(var(--line-rgb), .28);
    border-radius: 4px;
    box-shadow: 0 10px 34px rgba(0,0,0,.42);
    padding: 15px 16px;
  }
  .ck[hidden] { display: none; }
  .ck-in { display: block; }
  .ck-copy { margin: 0 0 13px; font-size: 12.5px; line-height: 1.6; color: var(--muted); }
  .ck-copy b { color: var(--hi); font-weight: 600; }
  .ck-copy a { color: var(--steel); text-decoration: underline; }
  .ck-actions { display: flex; gap: 8px; }
  .ck-actions .ck-btn { flex: 1 1 auto; }

  .ck-btn {
    font: 600 13px var(--sans); padding: 9px 18px; border-radius: 3px;
    border: 1px solid rgba(var(--line-rgb), .34);
    background: transparent; color: var(--cream); cursor: pointer;
    transition: background-color .18s ease, border-color .18s ease, color .18s ease;
  }
  .ck-btn:hover { border-color: var(--steel); color: var(--hi);
    background: rgba(var(--steel-rgb), .10); }
  .ck-btn:focus-visible { outline: 2px solid var(--steel); outline-offset: 2px; }
  .ck-btn-primary { background: var(--steel); border-color: var(--steel); color: var(--on-steel); }
  .ck-btn-primary:hover { background: var(--steel-hover); border-color: var(--steel-hover);
    color: var(--on-steel); }

  @media (max-width: 620px) {
    .ck { padding: 14px 20px; }
    .ck-in { gap: 14px; }
    .ck-actions { width: 100%; }
    .ck-btn { flex: 1 1 auto; }
  }

  /* ---------------------------------------------------------------------
     Bypass blocks (WCAG 2.4.1)
     The legal pages and the portal both had a skip link; the landing page —
     the one with the most traffic and the longest header — did not, so a
     keyboard user tabbed the whole nav on every visit. Off-screen until
     focused, which is the only time it is useful.
     --------------------------------------------------------------------- */
  .skip {
    position: absolute; left: -9999px; top: 0; z-index: 80;
    background: var(--steel); color: var(--on-steel);
    padding: 12px 18px; font: 600 13px var(--sans);
    border-radius: 0 0 3px 0;
  }
  .skip:focus { left: 0; }

  /* ---------------------------------------------------------------------
     Touch targets (WCAG 2.5.5)
     34px is comfortable with a mouse and small with a thumb. Rather than
     inflate the desktop UI, this only applies where the pointer is actually
     coarse — phones and tablets — so nothing changes on a laptop.
     --------------------------------------------------------------------- */
  @media (pointer: coarse) {
    .theme-btn { width: 44px; height: 44px; }
    .header-actions .header-cta { min-height: 44px; }
    .header-actions a { min-height: 44px; display: inline-flex; align-items: center; }
    .ck-btn { min-height: 44px; }
    .btn-solid, .btn-ghost { min-height: 44px; display: inline-flex;
      align-items: center; justify-content: center; }
  }

  /* On a phone there is no spare column, so the card spans the width — but it
     still must not be the thing under the reader's thumb when they reach for
     the demo button, so it sits above the safe-area inset. */
  @media (max-width: 620px) {
    .ck { left: 12px; right: 12px; width: auto;
          bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
  }

  /* ---------------------------------------------------------------------
     Field scrim behind body copy
     The dot field is fixed behind everything. Contrast still passes where
     text crosses it (measured: 5.79:1 worst case), but in the denser
     patches it reads as noise rather than texture. This fades the ground
     back IN behind paragraphs — a soft radial rather than a box, so there
     is no visible edge and the field still shows around the text.
     --------------------------------------------------------------------- */
  .statement p,
  .origin-copy p {
    position: relative;
    padding: 12px 18px;
    margin-left: -18px;
    margin-right: -18px;
    background: radial-gradient(ellipse 118% 150% at 32% 50%,
                rgba(var(--ink-rgb), .93) 42%,
                rgba(var(--ink-rgb), 0) 80%);
  }
  /* The kicker and headings sit on sparser areas and read fine unaided. */

  @media (max-width: 620px) {
    /* Narrow columns leave nowhere for the fade to go, so keep it tighter. */
    .statement p, .origin-copy p { margin-left: -10px; margin-right: -10px; padding: 10px 12px; }
  }

  /* ---------------------------------------------------------------------
     Mobile header — most demo signups happen on a phone, so the header must
     stay on one clean row with the demo CTA prominent. Below 760px the
     "What is NXSVL?" link is already hidden; this stops "Sign in" wrapping,
     drops the brand tagline to reclaim width, and tightens the gaps so the
     CTA is never squeezed onto a second line.
     --------------------------------------------------------------------- */
  @media (max-width: 620px) {
    header.shell { gap: 10px; }
    .header-actions { gap: 12px; }
    .header-actions a { white-space: nowrap; }
    .brand-txt span { display: none; }      /* tagline: the wordmark alone carries it here */
    .brand-txt b { font-size: 17px; }
    .brand .brand-mark { width: 28px; height: 28px; }
  }
  @media (max-width: 400px) {
    .header-actions { gap: 9px; }
    .header-actions .header-cta { padding-left: 13px; padding-right: 13px; }
    .header-actions > a:not(.header-cta) { font-size: 10px; }
    header.shell { padding-left: 13px; padding-right: 13px; }
  }
