/* =============================================================================
   Wiskl — optical whiskers for machines
   -----------------------------------------------------------------------------
   Structure follows Ekkovia's site system (pill nav, numbered sections, hexnet
   fields, wordmark footer). The palette does not: it is sampled from the Wiskl
   mark and the Lumiskur wordmark, where seven whiskers of light run from cyan
   through blue to violet across a black ground.

   Sampled from the source art:
       cyan    #00FFFF → used at #22E9F7 (pure cyan vibrates on black)
       blue    #6DA0FF
       violet  #B063FF
       white   #EAEAEA

   The accent is VIOLET, not cyan. Cyan is the field colour — it is what the
   whiskers are made of, so it is everywhere and cannot also be the thing that
   draws the eye. Violet is the far end of the spectrum, it is rarer in the
   mark, and it is what a whisker becomes when it reaches something. So violet
   marks arrival: focus states, the active packet in a hexnet, the CTA.
   ========================================================================== */

/* ---- Tokens ------------------------------------------------------------- */
:root {
  /* Ground: near-black with a violet cast, so the cyan reads cool against it.
     Not #000 — a pure-black ground gives the glows nothing to bloom into and
     makes every panel edge a hard step. */
  --bg:        #06070E;
  --bg-2:      #080A14;
  --surface:   #0B0D1A;
  --surface-2: #0E1122;
  --panel:     #10142A;
  --line:      rgba(255,255,255,.075);
  --line-2:    rgba(255,255,255,.14);
  --line-cy:   rgba(34,233,247,.26);
  --line-vi:   rgba(176,99,255,.30);

  /* Spectrum */
  --cyan:      #22E9F7;
  --cyan-deep: #0FB6C6;
  --blue:      #6DA0FF;
  --blue-deep: #3E6FE0;
  --violet:    #B063FF;
  --violet-sf: #C68CFF;
  --green:     #3FE0A8;
  --amber:     #FFC46B;
  --red:       #FF7A85;

  /* The whisker gradient. One definition, used by every gradient on the page. */
  --spectrum: linear-gradient(100deg, var(--cyan) 0%, var(--blue) 52%, var(--violet) 100%);

  /* Text */
  --text:  #E8EBF4;
  --muted: #96A0BC;
  --faint: #5D6684;

  /* HexNet cell palette (consumed by hexnet.js state map) */
  --hx-idle:   #2E3F6B;
  --hx-cyan:   #22E9F7;
  --hx-violet: #B063FF;
  --hx-white:  #DCE8FF;
  --hx-green:  #3FE0A8;
  --hx-red:    #FF7A85;

  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Inter",
          "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --display: var(--sans);
  /* The wordmark is a thin, wide-tracked geometric sans. No webfont is shipped,
     so technical labels approximate it with a system geometric face plus the
     wide tracking that actually carries the identity. */
  --tech: "Avenir Next", "Futura", "Century Gothic", var(--sans);
  --mono: "SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;

  --maxw: 1200px;
  --gutter: clamp(20px, 5vw, 48px);
  --radius: 16px;
  --radius-sm: 10px;
  --radius-lg: 22px;
  --ease: cubic-bezier(.22,.61,.36,1);
  --shadow: 0 30px 70px -34px rgba(0,0,0,.9);
}

/* ---- Light theme --------------------------------------------------------
   A glow-on-black brand has no natural light mode, so this does not attempt
   one. It inverts to cool paper and *deepens* the spectrum until it is legible
   on white — bright cyan on paper is invisible. The mark itself keeps its own
   colours and is simply given a dark surround where it needs one. */
:root[data-theme="light"] {
  --bg:        #F2F4FA;
  --bg-2:      #E9ECF6;
  --surface:   #FFFFFF;
  --surface-2: #F7F9FD;
  --panel:     #FFFFFF;
  --line:      rgba(12,22,48,.13);
  --line-2:    rgba(12,22,48,.22);
  --line-cy:   rgba(13,140,155,.34);
  --line-vi:   rgba(120,50,190,.32);

  --cyan:      #0C8C9B;
  --cyan-deep: #076974;
  --blue:      #3A63C8;
  --violet:    #7A32BE;
  --violet-sf: #9450D8;
  --green:     #0E9F6E;

  --text:  #0C1630;
  --muted: #465578;
  --faint: #6C789A;

  --hx-idle:   #9AA7C4;
  --hx-cyan:   #0C8C9B;
  --hx-violet: #7A32BE;
  --hx-white:  #16203C;
  --shadow: 0 22px 56px -30px rgba(12,22,48,.34);
}

/* ---- Reset -------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
/* Technical grid + a spectrum wash at the top of the page. Both are fixed and
   behind everything, so scrolling reveals the page against a steady field
   rather than dragging the background with it. */
body::before, body::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0;
}
body::before {
  background:
    linear-gradient(rgba(255,255,255,.030) 1px, transparent 1px) 0 0 / 100% 46px,
    linear-gradient(90deg, rgba(255,255,255,.030) 1px, transparent 1px) 0 0 / 46px 100%;
  -webkit-mask-image: radial-gradient(120% 80% at 50% 0%, #000 20%, transparent 78%);
          mask-image: radial-gradient(120% 80% at 50% 0%, #000 20%, transparent 78%);
}
body::after {
  background:
    radial-gradient(70% 45% at 18% -8%, rgba(34,233,247,.10), transparent 62%),
    radial-gradient(70% 50% at 84% -6%, rgba(176,99,255,.12), transparent 64%);
}
:root[data-theme="light"] body::before { background-image:
  linear-gradient(rgba(12,22,48,.055) 1px, transparent 1px),
  linear-gradient(90deg, rgba(12,22,48,.055) 1px, transparent 1px); }
:root[data-theme="light"] body::after { background:
  radial-gradient(70% 45% at 18% -8%, rgba(12,140,155,.10), transparent 62%),
  radial-gradient(70% 50% at 84% -6%, rgba(122,50,190,.10), transparent 64%); }

main, .nav, .footer { position: relative; z-index: 1; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3 { font-family: var(--display); font-weight: 800; letter-spacing: -.028em; margin: 0; }
p { margin: 0; }
em { font-style: normal; background: var(--spectrum); -webkit-background-clip: text;
     background-clip: text; color: transparent; }
:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; border-radius: 6px; }
.skip-link { position: absolute; left: -9999px; }
.skip-link:focus { left: 16px; top: 16px; z-index: 99; background: var(--panel);
  padding: 10px 16px; border-radius: 8px; border: 1px solid var(--line-2); }

/* =============================================================================
   HexNet  (structure from Ekkovia; palette variables remapped)
   ========================================================================== */
.hexnet { position: relative; width: 100%; height: 100%; line-height: 0; }
.hx-svg { width: 100%; height: 100%; overflow: visible; }
/* Every field is masked from its own CENTRE. An off-centre mask origin makes
   the animation look like it is sliding out of its box, which is exactly the
   impression a "computational field" must not give. */
.stage-net .hx-svg, .organ-net .hx-svg, .cta-net .hx-svg, .fl-node .hx-svg {
  -webkit-mask-image: radial-gradient(70% 70% at 50% 50%, #000 34%, transparent 96%);
          mask-image: radial-gradient(70% 70% at 50% 50%, #000 34%, transparent 96%);
}
/* Centred on the right-hand column but sized to the whole hero, and faded
   out before it reaches the headline so the copy keeps its contrast. */
/* Fade on BOTH axes, as two linear gradients intersected.
   A single radial could not do this job. Its falloff is radial, so the only
   way to reach zero at the left edge is to shrink it until it also starves
   the middle -- and at 46% of the hero the element boundary is right beside
   the body copy, where any residual opacity shows up as a hard vertical cut
   through the hexagons. Two axis-aligned ramps composited together fade the
   left and right edges exactly the way the top and bottom already fade, so
   the field dissolves into the page on every side instead of ending on a
   line. */
/* The left edge faces the headline, so it gets the longest fade: the field
   should be gone well before it reaches a letter, not merely dimmer. The
   right edge is pulled in too so the field stops short of the viewport rather
   than running off it. */
.hero-net .hx-svg {
  -webkit-mask-image:
    linear-gradient(to right, transparent 0%, #000 14%, #000 74%, transparent 100%),
    linear-gradient(to bottom, transparent 0%, #000 12%, #000 82%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent 0%, #000 14%, #000 74%, transparent 100%),
    linear-gradient(to bottom, transparent 0%, #000 12%, #000 82%, transparent 100%);
  mask-composite: intersect;
}
.hx {
  --a: 0; --f: 0; --e: 1;
  fill: var(--hx-base, var(--hx-cyan));
  stroke: var(--hx-base, var(--hx-cyan));
  stroke-width: 1;
  fill-opacity: calc(var(--a) * 0.92 * var(--e));
  stroke-opacity: calc(var(--a) * 0.5 * var(--e));
  transform-box: fill-box; transform-origin: center;
  transform: scale(calc(0.92 + var(--a) * 0.12));
  transition: fill-opacity .12s linear, stroke-opacity .12s linear;
}
@supports (color: color-mix(in srgb, red, blue)) {
  .hx {
    fill: color-mix(in srgb, var(--hx-base) calc((1 - var(--f)) * 100%), var(--hx-focus) calc(var(--f) * 100%));
    stroke: color-mix(in srgb, var(--hx-base) calc((1 - var(--f)) * 100%), var(--hx-focus) calc(var(--f) * 100%));
  }
}
.hx-svg { filter: drop-shadow(0 0 calc(2px + var(--hx-glow, .5) * 7px) rgba(34,233,247,.42)); }
/* The hero constellation is the page's signature motion. Give it a brighter
   bloom than the inline indicators, which only need to register as "alive". */
.stage-net .hx-svg { filter: drop-shadow(0 0 14px rgba(34,233,247,.55))
                             drop-shadow(0 0 34px rgba(109,160,255,.30)); }
.stage-net .hx-link { stroke-width: 1.2; }
.organ-net .hx-svg { filter: drop-shadow(0 0 12px rgba(34,233,247,.45)); }
.hx-link { stroke: var(--hx-base, var(--hx-cyan)); stroke-width: 1; fill: none;
  transition: stroke-opacity .12s linear; }
.hx-packet { fill: var(--hx-focus, var(--hx-violet)); transition: opacity .1s linear; }
.hx-inline { display: inline-block; width: 44px; height: 30px; vertical-align: middle; }

/* =============================================================================
   Layout primitives
   ========================================================================== */
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.sec { padding: clamp(72px, 10vw, 128px) 0; position: relative; }
.sec-head { display: flex; align-items: center; gap: 14px; margin-bottom: 30px; flex-wrap: wrap; }
.sec-head.center { justify-content: center; }
.sec-meta { font-family: var(--tech); font-size: 12.5px; letter-spacing: .26em;
  text-transform: uppercase; color: var(--muted); margin: 0; }
.sec-meta b { color: var(--violet); font-weight: 700; margin-right: 10px; }
.exp-pill { font-family: var(--tech); font-size: 11px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--cyan); border: 1px solid var(--line-cy);
  border-radius: 999px; padding: 5px 12px; background: rgba(34,233,247,.06); }
.center-h { font-size: clamp(30px, 4.6vw, 52px); line-height: 1.1; text-align: center;
  margin-bottom: 52px; }
.lead { color: var(--muted); font-size: clamp(16px, 1.5vw, 18.5px); max-width: 56ch; }

.btn { display: inline-flex; align-items: center; gap: 10px; border-radius: 999px;
  font-weight: 650; font-size: 15px; padding: 12px 22px; border: 1px solid transparent;
  cursor: pointer; transition: transform .18s var(--ease), box-shadow .18s var(--ease),
  background .18s var(--ease); font-family: var(--sans); white-space: nowrap; }
.btn.lg { padding: 15px 28px; font-size: 16px; }
.btn-primary { background: var(--spectrum); color: #05060C; font-weight: 750;
  box-shadow: 0 10px 34px -12px rgba(109,160,255,.75); }
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 16px 44px -12px rgba(176,99,255,.85); }
.btn-ghost { background: rgba(255,255,255,.035); border-color: var(--line-2); color: var(--text); }
.btn-ghost:hover { background: rgba(255,255,255,.07); transform: translateY(-2px); }
:root[data-theme="light"] .btn-ghost { background: rgba(12,22,48,.035); }
:root[data-theme="light"] .btn-primary { color: #fff; }

.link-arrow { display: inline-flex; align-items: center; gap: 8px; color: var(--cyan);
  font-weight: 620; font-size: 15px; margin-top: 8px; }
.link-arrow span { transition: transform .2s var(--ease); }
.link-arrow:hover span { transform: translateX(5px); }

/* =============================================================================
   Nav
   ========================================================================== */
.nav { position: sticky; top: 0; z-index: 50; padding: 14px 0; }
.nav-inner { display: flex; align-items: center; justify-content: space-between; gap: 20px;
  background: rgba(10,12,24,.55); border: 1px solid var(--line); border-radius: 999px;
  padding: 9px 9px 9px 20px; backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 16px 48px -22px rgba(0,0,0,.9), inset 0 1px 0 rgba(255,255,255,.05);
  transition: background .25s var(--ease); }
.nav.scrolled .nav-inner { background: rgba(10,12,24,.82); }
:root[data-theme="light"] .nav-inner { background: rgba(255,255,255,.66);
  box-shadow: 0 14px 40px -20px rgba(12,22,48,.3), inset 0 1px 0 #fff; }
:root[data-theme="light"] .nav.scrolled .nav-inner { background: rgba(255,255,255,.88); }

.brand { display: inline-flex; align-items: center; gap: 11px; }
.brand-mark { width: 32px; height: 32px; display: grid; place-items: center; }
/* The mark is seven hairline whiskers. At nav size those strokes are sub-pixel
   and it reads as a smudge, so it gets its own bloom to hold together small. */
.brand-mark img { width: 32px; height: auto;
  filter: drop-shadow(0 0 5px rgba(34,233,247,.45)); }
.brand-word { height: 15px; width: auto; opacity: .96; }
/* On paper the neon mark disappears: bright cyan on white is near-zero
   contrast, and a cyan bloom only makes it worse. Light mode swaps in an
   ink variant of the same artwork (same geometry, deepened spectrum) rather
   than filtering the bright one, because a hue-rotate on a gradient mark
   destroys the cyan-to-violet relationship that is the brand. */
.brand-mark .mk-light, .bench-brand .mk-light { display: none; }
:root[data-theme="light"] .brand-mark .mk-dark { display: none; }
:root[data-theme="light"] .brand-mark .mk-light { display: block; }
:root[data-theme="light"] .brand-mark img {
  filter: drop-shadow(0 0 2px rgba(12,22,48,.20)); }
.cta-short { display: none; }
:root[data-theme="light"] .brand-word { filter: invert(1) brightness(.22); }

.nav-links { display: flex; gap: 26px; font-size: 14.5px; color: var(--muted); }
.nav-links a { transition: color .18s var(--ease); }
.nav-links a:hover { color: var(--text); }
.nav-cta { display: flex; align-items: center; gap: 10px; }
.theme-toggle { width: 38px; height: 38px; border-radius: 999px; display: grid;
  place-items: center; background: rgba(255,255,255,.04); border: 1px solid var(--line);
  color: var(--muted); cursor: pointer; }
.theme-toggle:hover { color: var(--text); }
.theme-toggle svg { width: 17px; height: 17px; }
.icon-sun { display: none; }
:root[data-theme="light"] .icon-sun { display: block; }
:root[data-theme="light"] .icon-moon { display: none; }
@media (max-width: 900px) { .nav-links { display: none; } }
@media (max-width: 560px) {
  .nav-inner { padding: 8px 8px 8px 14px; gap: 10px; }
  .nav-cta { gap: 8px; }
  .nav-cta .btn-primary { font-size: 13.5px; padding: 10px 15px; }
  .theme-toggle { width: 34px; height: 34px; }
  .brand-word { height: 13px; }
  .brand-mark, .brand-mark img { width: 26px; }
  .cta-long { display: none; }
  .cta-short { display: inline; }
}

/* =============================================================================
   Hero
   ========================================================================== */
.hero { padding: clamp(40px, 7vw, 88px) 0 clamp(48px, 7vw, 92px); position: relative; }
/* Starts at 46% — the field lives behind the instrument panel only. It was
   previously spanning the full section, which put animated cells directly
   under the headline and body copy and made both hard to read. A background
   that competes with the words is not atmosphere, it is noise. */
/* height/width auto is load-bearing. `.hexnet` sets height:100%, and an
   absolutely-positioned box with top + bottom + height:100% is
   over-constrained: CSS keeps the height and DROPS the bottom inset, so the
   field silently grows past its container. Every one of these fields is
   positioned by insets, so each must release the inherited size. */
/* Centred on the instrument panel, with equal room either side. The right
   inset was negative, so the field ran past the viewport edge and its fade
   happened off-screen -- one side dissolved, the other was guillotined by
   the window. 44% / 3% puts the field's centre at ~70.5% of the hero, which
   is where the panel's centre already is. */
/* Measured against the layout rather than eyeballed: the copy column ends at
   49 % of the hero and the instrument panel spans 53–89 %. A field that sits
   inside 51–91 % is therefore almost entirely behind opaque glass and simply
   disappears, which is what happened on the first pass at making it smaller.
   47–95 % keeps a halo visible above, below and just past the panel while the
   mask below kills the left edge inside the 49–53 % gap, so it never reaches
   a letter and never runs to the viewport edge. */
.hero-net { position: absolute; inset: -8% 10% -12% 47%; height: auto; width: auto;
  z-index: 0; pointer-events: none; opacity: .82;
  /* Its own compositor layer. The field repaints every frame; without this
     the browser repaints the hero behind it too, which is a large area of
     gradient and text for no reason. Most visible as smoothness on a phone. */
  transform: translateZ(0); }
/* The constellation is deliberately a low-activity field, which reads as
   "alive" at inline sizes but disappears at hero scale on near-black. The
   brightness lift is applied to the whole SVG rather than to the palette so
   the cyan-to-violet relationship is untouched. */
/* Dimmed from the original 1.34 / .52 / .28, but only modestly. Most of the
   "less overwhelming" comes from the smaller box and tighter mask above; an
   earlier pass cut the brightness as well and the three reductions compounded
   until the field was invisible on a downscaled screen. */
.hero-net .hx-svg { filter: brightness(1.26) saturate(1.06)
                            drop-shadow(0 0 13px rgba(34,233,247,.42))
                            drop-shadow(0 0 32px rgba(109,160,255,.18)); }
.hero-net .hx-link { stroke-width: 1.15; }
.hero-grid { position: relative; z-index: 1; }
.hero-grid { display: grid; grid-template-columns: 1.02fr .98fr; gap: clamp(28px, 4vw, 60px);
  align-items: center; }
@media (max-width: 1000px) { .hero-grid { grid-template-columns: 1fr; } }

.eyebrow { font-family: var(--tech); font-size: 12px; letter-spacing: .3em; text-transform: uppercase;
  color: var(--cyan); display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.eyebrow .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--cyan);
  box-shadow: 0 0 12px var(--cyan); animation: pulse 2.4s var(--ease) infinite; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .32; } }
.eyebrow .ell { color: var(--faint); letter-spacing: .1em; }
@media (prefers-reduced-motion: reduce) { .eyebrow .dot { animation: none; } }

.hero h1 { font-size: clamp(38px, 6.2vw, 76px); line-height: 1.03; margin-bottom: 22px; }
.hero-actions { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 30px; }
.hero-actions.center { justify-content: center; }
.play { font-size: 11px; color: var(--cyan); }

.sysline { display: flex; align-items: center; gap: 12px; margin-top: 34px;
  padding-top: 22px; border-top: 1px solid var(--line); flex-wrap: wrap; }
.sys-label { font-family: var(--tech); font-size: 11px; letter-spacing: .24em;
  text-transform: uppercase; color: var(--faint); }
.sys-body { font-size: 14px; color: var(--muted); }

/* ---- Hero stage: the bench instrument mockup ---------------------------- */
.hero-stage { position: relative; min-height: 470px; display: grid; place-items: center; }
/* The instrument panel is translucent so the field reads THROUGH it as well
   as around it. Backdrop-blur keeps the readouts legible over moving cells. */
.bench { backdrop-filter: blur(9px); -webkit-backdrop-filter: blur(9px); }
.bench { position: relative; z-index: 1; width: 100%; background: color-mix(in srgb, var(--surface) 84%, transparent);
  border: 1px solid var(--line-2); border-radius: var(--radius); overflow: hidden;
  box-shadow: var(--shadow); font-size: 11px; }
.bench-bar { display: flex; align-items: center; justify-content: space-between;
  padding: 9px 13px; border-bottom: 1px solid var(--line); background: var(--surface-2); }
.bench-brand { display: inline-flex; align-items: center; gap: 7px; font-family: var(--tech);
  font-size: 10px; letter-spacing: .22em; color: var(--muted); }
.bench-brand img { width: 15px; }
.bench-state { font-family: var(--mono); font-size: 10px; color: var(--green); display: flex;
  align-items: center; gap: 6px; }
.bench-state i { width: 6px; height: 6px; border-radius: 50%; background: var(--green);
  box-shadow: 0 0 8px var(--green); }
.bench-body { display: grid; grid-template-columns: 1.15fr 1fr; }
.bench-cell { padding: 12px 14px; border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line); }
.bench-cell:nth-child(even) { border-right: none; }
.col-label { font-family: var(--tech); font-size: 9px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--faint); margin: 0 0 9px; }

/* beam profile viewport */
.profile { position: relative; aspect-ratio: 16/10; border-radius: 8px; overflow: hidden;
  background: radial-gradient(circle at 58% 44%, rgba(34,233,247,.10), transparent 62%), #04050B;
  border: 1px solid var(--line); }
.profile .cross { position: absolute; inset: 0; }
.profile .cross i { position: absolute; background: rgba(255,255,255,.10); }
.profile .cross i:first-child { left: 0; right: 0; top: 50%; height: 1px; }
.profile .cross i:last-child { top: 0; bottom: 0; left: 50%; width: 1px; }
.spot { position: absolute; width: 30%; aspect-ratio: 1; border-radius: 50%; left: 58%; top: 44%;
  transform: translate(-50%,-50%);
  background: radial-gradient(circle, #fff 0%, var(--cyan) 26%, rgba(109,160,255,.55) 52%, transparent 74%);
  filter: blur(.4px); animation: jitter 5.5s var(--ease) infinite; }
@keyframes jitter { 0%,100% { left: 58%; top: 44%; } 33% { left: 57.4%; top: 44.6%; }
  66% { left: 58.5%; top: 43.6%; } }
@media (prefers-reduced-motion: reduce) { .spot { animation: none; } }
.spot-box { position: absolute; left: 58%; top: 44%; width: 40%; aspect-ratio: 1;
  transform: translate(-50%,-50%); border: 1px dashed var(--line-vi); border-radius: 4px; }
.readout { display: grid; grid-template-columns: 1fr 1fr; gap: 3px 12px; margin-top: 10px;
  font-family: var(--mono); font-size: 10px; color: var(--muted); }
.readout b { color: var(--text); font-weight: 600; }

/* pointing panel */
.rows { display: grid; gap: 7px; font-family: var(--mono); font-size: 10.5px; }
.row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.row span { color: var(--faint); }
.row b { color: var(--text); font-weight: 600; }
.row b.ok { color: var(--green); }
.row b.vi { color: var(--violet); }
.err-bar { height: 4px; border-radius: 999px; background: rgba(255,255,255,.07);
  overflow: hidden; margin-top: 3px; }
.err-bar i { display: block; height: 100%; width: 16%; background: var(--spectrum);
  border-radius: 999px; }

/* risley dials */
.dials { display: flex; gap: 16px; justify-content: center; padding: 4px 0 2px; }
.dials svg { width: 66px; height: 66px; }
.dials circle.track { fill: none; stroke: rgba(255,255,255,.10); stroke-width: 3; }
.dials circle.arc { fill: none; stroke: url(#dg); stroke-width: 3; stroke-linecap: round; }
.dials line { stroke: var(--violet); stroke-width: 2; stroke-linecap: round; }

/* steering field */
.field { position: relative; aspect-ratio: 1/.82; }
.field svg { width: 100%; height: 100%; }
.bench-foot { display: flex; justify-content: space-between; gap: 10px; padding: 8px 14px;
  font-family: var(--mono); font-size: 9.5px; color: var(--faint); background: var(--surface-2); }

/* =============================================================================
   Brand band
   ========================================================================== */
.brand-band { display: flex; align-items: center; gap: 20px; padding: 6px 0 2px; }
.bb-rail { flex: 1; height: 1px; background: linear-gradient(90deg, transparent, var(--line-2)); }
.bb-rail-r { background: linear-gradient(90deg, var(--line-2), transparent); }
.bb-phrases { display: flex; align-items: center; gap: 16px; font-family: var(--tech);
  font-size: 12px; letter-spacing: .26em; text-transform: uppercase; color: var(--muted); }
.bb-phrases i { color: var(--violet); font-style: normal; font-size: 8px; }

/* flow link between sections */
.flow-link { display: flex; align-items: center; gap: 0; justify-content: center; }
.fl-rail { flex: 1; max-width: 40%; height: 1px;
  background: linear-gradient(90deg, transparent, var(--line-cy)); }
.fl-rail.b { background: linear-gradient(90deg, var(--line-cy), transparent); }
.fl-node { width: 84px; height: 56px; }

/* =============================================================================
   01 — Whiskers
   ========================================================================== */
.two-grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 4vw, 62px);
  align-items: center; }
@media (max-width: 960px) { .two-grid { grid-template-columns: 1fr; } }
.two-grid h2 { font-size: clamp(28px, 3.9vw, 46px); line-height: 1.1; margin-bottom: 18px; }
.two-grid p { color: var(--muted); margin-bottom: 14px; }

.probe-viz { position: relative; min-height: 330px; }
.probe { position: absolute; background: var(--surface); border: 1px solid var(--line-2);
  border-radius: 12px; padding: 11px 13px; box-shadow: var(--shadow); width: 150px; }
.probe-1 { left: 0; top: 6px; }
.probe-2 { left: 50%; top: 0; transform: translateX(-50%); }
.probe-3 { right: 0; top: 12px; }
.probe h4 { font-size: 13px; margin: 0 0 3px; font-weight: 700; }
.probe p { font-size: 11px; color: var(--faint); margin: 0; line-height: 1.45; }
.probe .glyph { font-size: 15px; color: var(--cyan); margin-bottom: 5px; }
.probe-node { position: absolute; left: 50%; bottom: 4px; transform: translateX(-50%);
  width: 132px; height: 92px; }
.probe-paths { position: absolute; inset: 0; width: 100%; height: 100%; }
.probe-paths .sig { fill: none; stroke: var(--cyan); stroke-width: 1.1; opacity: .5;
  stroke-dasharray: 4 7; animation: flow 3.4s linear infinite; }
@keyframes flow { to { stroke-dashoffset: -22; } }
@media (prefers-reduced-motion: reduce) { .probe-paths .sig { animation: none; } }

/* =============================================================================
   02 — Attention
   ========================================================================== */
.pipeline { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; list-style: none;
  padding: 0; margin: 22px 0 6px; }
.pipeline li { font-family: var(--tech); font-size: 11px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted); display: inline-flex; align-items: center;
  gap: 7px; background: rgba(255,255,255,.035); border: 1px solid var(--line);
  border-radius: 999px; padding: 6px 12px; }
.pipeline li.pl-arrow { background: none; border: none; padding: 0; color: var(--violet); }
.pl-ic { color: var(--cyan); font-size: 11px; }

.code { background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--radius);
  overflow: hidden; box-shadow: var(--shadow); }
.code-bar { display: flex; align-items: center; justify-content: space-between;
  padding: 9px 14px; border-bottom: 1px solid var(--line); background: var(--surface-2);
  font-family: var(--tech); font-size: 10px; letter-spacing: .2em; color: var(--faint); }
.code pre { margin: 0; padding: 16px 18px; font-family: var(--mono); font-size: 12.5px;
  line-height: 1.8; color: var(--muted); overflow-x: auto; }
.code .k { color: var(--violet); }
.code .n { color: var(--cyan); }
.code .s { color: var(--blue); }
.code .c { color: var(--faint); font-style: italic; }

.states { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 20px; }
@media (max-width: 620px) { .states { grid-template-columns: repeat(2, 1fr); } }
.state { border: 1px solid var(--line); border-radius: 12px; padding: 12px;
  background: rgba(255,255,255,.02); }
.state b { display: block; font-family: var(--tech); font-size: 10.5px; letter-spacing: .18em;
  margin-bottom: 5px; }
.state span { font-size: 11.5px; color: var(--faint); line-height: 1.45; display: block; }
.state.free b { color: var(--green); }
.state.occ b { color: var(--cyan); }
.state.hid b { color: var(--violet); }
.state.unk b { color: var(--amber); }

/* =============================================================================
   03 — Loop
   ========================================================================== */
.pipe3 { display: grid; grid-template-columns: 1fr auto 1fr; gap: clamp(16px, 3vw, 40px);
  align-items: center; }
@media (max-width: 900px) { .pipe3 { grid-template-columns: 1fr; } }
.pipe-card { margin: 0; background: var(--surface); border: 1px solid var(--line-2);
  border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); }
.pc-window { position: relative; aspect-ratio: 16/9;
  background: radial-gradient(circle at 50% 50%, rgba(255,255,255,.03), transparent 70%), #04050B; }
.scatter { position: absolute; inset: 0; }
.scatter i { position: absolute; width: 5px; height: 5px; border-radius: 50%;
  background: var(--cyan); box-shadow: 0 0 7px var(--cyan); opacity: .8; }
.scatter .bull { width: 13px; height: 13px; border-radius: 50%; background: none;
  border: 1px dashed var(--line-vi); box-shadow: none; opacity: 1; }
.pipe-card figcaption { padding: 13px 16px; border-top: 1px solid var(--line); }
.pipe-card figcaption b { display: block; font-size: 14.5px; margin-bottom: 3px; }
.pipe-card figcaption span { font-size: 12px; color: var(--faint); font-family: var(--mono); }
.pipe-mid { display: grid; place-items: center; gap: 8px; }
.pipe-mid .hexnet { width: 150px; height: 104px; }
.pipe-label { font-family: var(--tech); font-size: 11px; letter-spacing: .3em; color: var(--violet); }
@media (max-width: 900px) { .pipe-mid .hexnet { width: 100px; height: 68px; } }

.metrics { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-top: 52px; }
@media (max-width: 760px) { .metrics { grid-template-columns: repeat(2, 1fr); } }
.metric { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 16px 18px;
  background: rgba(255,255,255,.02); }
.metric .mv { font-family: var(--mono); font-size: clamp(20px, 2.5vw, 27px); font-weight: 600;
  background: var(--spectrum); -webkit-background-clip: text; background-clip: text;
  color: transparent; line-height: 1.15; }
.metric .ml { font-family: var(--tech); font-size: 9.5px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--faint); margin-top: 7px; }
.caveat { margin-top: 18px; font-size: 12.5px; color: var(--faint); font-family: var(--mono);
  display: flex; gap: 9px; align-items: flex-start; }
.caveat b { color: var(--amber); font-weight: 600; }

/* =============================================================================
   04 — Lumiskur
   ========================================================================== */
/* Three stacked layers, deliberately separated:
     1. the wordmark, ON TOP of the field so it is never competing with it
     2. the hexnet, confined to the middle band
     3. the tagline, BELOW the field so it never sits on top of moving cells
   The field previously spanned the whole box, so the tagline was printed
   over live hexagons and both became harder to read. */
.organ-viz { position: relative; display: flex; flex-direction: column;
  align-items: center; justify-content: flex-start; min-height: 500px; gap: 0; }
/* The field stops well above the tagline. Overlapping them made the caption
   sit on top of moving cells, which cost both of them legibility. */
.organ-net { position: absolute; left: 0; right: 0; top: 6%; bottom: 34%;
  height: auto; width: auto; z-index: 0; }
.organ-word { position: relative; z-index: 2; width: min(360px, 78%);
  margin-top: 10px; opacity: 1;
  filter: drop-shadow(0 0 22px rgba(6,7,14,.95)) drop-shadow(0 0 6px rgba(6,7,14,.9)); }
.organ-spacer { flex: 1 1 auto; min-height: 150px; }
.organ-tag { position: relative; z-index: 2; margin-top: auto; padding-top: 26px;
  text-align: center; font-family: var(--tech); font-size: 11px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--muted); line-height: 2.1; }
.organ-list { list-style: none; padding: 0; margin: 22px 0 0; display: grid; gap: 9px; }
.organ-list li { display: flex; align-items: baseline; gap: 12px; font-size: 14.5px;
  color: var(--muted); padding-bottom: 9px; border-bottom: 1px solid var(--line); }
.organ-list li b { font-family: var(--mono); font-size: 11px; color: var(--cyan);
  min-width: 24px; font-weight: 600; }
.mem-thesis { font-size: clamp(21px, 2.6vw, 30px); line-height: 1.22; margin: 26px 0 14px; }

/* =============================================================================
   05 — Roadmap
   ========================================================================== */
.stage-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
@media (max-width: 900px) { .stage-grid { grid-template-columns: 1fr; } }
.stage-card { background: var(--surface); border: 1px solid var(--line-2);
  border-radius: var(--radius-lg); padding: 28px; position: relative; overflow: hidden; }
.stage-card.featured { border-color: var(--line-cy); }
.stage-card.featured::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--spectrum); }
.sc-head { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 14px; }
.sc-name { font-family: var(--tech); font-size: 15px; letter-spacing: .16em; text-transform: uppercase; }
.sc-badge { font-family: var(--tech); font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
  border-radius: 999px; padding: 4px 11px; border: 1px solid var(--line-cy); color: var(--cyan);
  background: rgba(34,233,247,.07); }
.sc-badge.soon { border-color: var(--line-vi); color: var(--violet-sf); background: rgba(176,99,255,.07); }
.sc-sub { font-family: var(--mono); font-size: 12px; color: var(--faint); margin-bottom: 14px; }
.sc-desc { color: var(--muted); font-size: 14.5px; margin-bottom: 18px; }
.sc-feats { list-style: none; padding: 0; margin: 0 0 22px; display: grid; gap: 9px; }
.sc-feats li { font-size: 14px; color: var(--muted); display: flex; gap: 10px; align-items: baseline; }
.sc-feats li::before { content: "◆"; color: var(--cyan); font-size: 8px; }
.stage-card.soon .sc-feats li::before { color: var(--violet); }

.ladder { display: flex; gap: 0; margin-top: 46px; overflow-x: auto; padding-bottom: 8px; }
.rung { flex: 1 0 auto; min-width: 108px; text-align: center; position: relative;
  padding: 26px 8px 0; }
.rung::before { content: ""; position: absolute; top: 9px; left: 0; right: 0; height: 1px;
  background: var(--line-2); }
.rung::after { content: ""; position: absolute; top: 5px; left: 50%; transform: translateX(-50%);
  width: 9px; height: 9px; border-radius: 50%; background: var(--bg);
  border: 1px solid var(--line-2); }
.rung.done::after, .rung.now::after { border-color: var(--cyan); background: var(--cyan);
  box-shadow: 0 0 11px var(--cyan); }
.rung.now::after { background: var(--violet); border-color: var(--violet);
  box-shadow: 0 0 13px var(--violet); }
.rung b { display: block; font-family: var(--tech); font-size: 10px; letter-spacing: .13em;
  color: var(--faint); text-transform: uppercase; }
.rung.done b, .rung.now b { color: var(--text); }
.rung span { display: block; font-size: 10.5px; color: var(--faint); margin-top: 3px; line-height: 1.4; }

/* =============================================================================
   CTA
   ========================================================================== */
.cta-inner { position: relative; text-align: center; padding: clamp(46px, 7vw, 86px) var(--gutter);
  border: 1px solid var(--line-2); border-radius: var(--radius-lg); overflow: hidden;
  background: var(--surface); }
/* The CTA field is a halo, not a wash. A full-bleed hexnet behind centred body
   copy is the one place this motion system fights the page: the cells are large
   at `lg`, they sit exactly where the text is, and no amount of opacity fixes
   a texture that is competing with the words. So the mask is a donut — clear
   through the middle, bright around the outside. */
/* inset 0: the box is exactly the panel, so "centred" in the mask and
   "centred" on the card are the same point. The old negative inset shifted
   the field's centre away from the card's and the ring read as off-origin. */
/* Oversized on purpose, and still centred. HexNet fades its own outer 34 %
   of cells (EDGE_MARGIN) so a field never ends on a hard rectangle. Sized to
   the panel exactly, that built-in fade lands INSIDE the card and the result
   is a bright blob in the middle with empty corners -- the opposite of what
   the mask asks for. Blowing the field up well past the card pushes its own
   soft border out of sight, and `.cta-inner` (overflow:hidden, rounded)
   does the clipping. Symmetric insets keep the centre on the card's centre. */
.cta-net { position: absolute; inset: -55%; height: auto; width: auto; z-index: 0;
  opacity: .75; }
/* Same lift the hero field gets: the constellation and radial variants are
   deliberately low-activity, which reads at inline sizes and disappears at
   panel scale on near-black. */
.cta-net .hx-svg { filter: brightness(1.35) saturate(1.06)
                           drop-shadow(0 0 12px rgba(34,233,247,.45))
                           drop-shadow(0 0 32px rgba(176,99,255,.24)); }
/* `closest-side circle` sized the ring to the SHORT axis, so on a wide panel
   it stopped half a panel short of the left and right edges. `farthest-corner
   ellipse` reaches every corner, so the field carries all the way out and the
   rounded panel does the clipping. The centre is dimmed rather than cut to
   nothing, which keeps the headline readable without leaving a hole. */
/* Only a gentle centre dim now, to keep the headline readable. The field
   itself carries to the card edges. */
.cta-net .hx-svg {
  -webkit-mask-image: radial-gradient(farthest-side ellipse at 50% 50%,
    rgba(0,0,0,.30) 0%, rgba(0,0,0,.52) 22%, rgba(0,0,0,.9) 44%, #000 60%, #000 100%);
          mask-image: radial-gradient(farthest-side ellipse at 50% 50%,
    rgba(0,0,0,.30) 0%, rgba(0,0,0,.52) 22%, rgba(0,0,0,.9) 44%, #000 60%, #000 100%);
}
.cta-inner > *:not(.cta-net) { position: relative; z-index: 1; }
.cta-h { font-size: clamp(30px, 4.6vw, 54px); line-height: 1.08; margin: 12px 0 16px; }
.cta-sub { color: var(--text); font-size: clamp(16px, 1.7vw, 19px); margin-bottom: 10px; }
.cta-fine { color: var(--muted); max-width: 60ch; margin: 0 auto; font-size: 15px; }
.cta-soon { margin-top: 26px; justify-content: center; }

/* =============================================================================
   Footer
   ========================================================================== */
.footer { position: relative; padding-top: clamp(46px, 6vw, 76px); overflow: hidden;
  border-top: 1px solid var(--line); margin-top: 40px; }
.footer-top { display: grid; grid-template-columns: 1.2fr 2fr; gap: 40px; padding-bottom: 46px; }
@media (max-width: 860px) { .footer-top { grid-template-columns: 1fr; } }
.foot-tag { color: var(--muted); font-size: 14px; margin: 14px 0 12px; max-width: 34ch; }
.foot-status { display: flex; align-items: center; gap: 9px; font-family: var(--tech);
  font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--green); }
.foot-cols { display: grid; grid-template-columns: repeat(4, 1fr); gap: 26px; }
@media (max-width: 640px) { .foot-cols { grid-template-columns: repeat(2, 1fr); } }
.foot-cols h3 { font-family: var(--tech); font-size: 10px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 14px; font-weight: 500; }
.foot-cols a { display: block; font-size: 14px; color: var(--muted); padding: 4px 0; }
.foot-cols a:hover { color: var(--cyan); }
.footer-bottom { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  padding: 20px 0 26px; border-top: 1px solid var(--line); font-size: 13px; color: var(--faint); }
/* Full-bleed: the watermark should run the entire viewport width and sit
   flush on the bottom edge, not inside the content column. */
.foot-wordmark { display: block; width: 100vw; max-width: none;
  margin-left: calc(50% - 50vw); margin-bottom: 0; opacity: .055;
  pointer-events: none; }
:root[data-theme="light"] .foot-wordmark { filter: invert(1); opacity: .07; }

/* =============================================================================
   Small screens
   -----------------------------------------------------------------------------
   Handsets are the case this layout is most likely to break, for three
   specific reasons, each addressed below:

     1. Fixed-width technical content. The AttentionTarget code block and the
        instrument panel are monospaced and cannot reflow. They must scroll
        inside their own box rather than widening the page — a body that
        scrolls sideways on a phone reads as broken, and it hides content off
        the right edge where nobody looks.

     2. Long unbreakable strings. Readouts like "−10.994 mm" and the
        `--hx-…` tokens overflow narrow columns. They get explicit wrapping.

     3. iOS Safari's dynamic toolbar. `100vh` is wrong there — it is the tall
        viewport, so anything sized to it is clipped when the toolbar shows.
        Nothing here uses 100vh, and the footer watermark uses 100vw rather
        than 100vmax so it cannot induce horizontal overflow.
   ========================================================================== */

/* Belt and braces against sideways scroll on any handset. */
html { overflow-x: hidden; }
.code pre, .ladder { -webkit-overflow-scrolling: touch; }

@media (max-width: 820px) {
  body { font-size: 16px; }
  .sec { padding: clamp(52px, 9vw, 88px) 0; }
  .hero { padding: 26px 0 40px; }
  .hero-grid { gap: 34px; }
  .hero-stage { min-height: 0; }
  /* On a phone the field sat behind the whole hero, including the body copy,
     which made the paragraph genuinely hard to read. Confine it to the band
     behind the headline and let it fade out before the lead paragraph starts.
     The inset is also no longer negative on the sides: at -6% the element was
     420 px wide in a 375 px viewport and pushed the page 23 px past its own
     edge. */
  /* Measured, not guessed: on a 375 px viewport the headline ends at 9 % of
     the hero and the lead paragraph at 20 %. 26 % puts the field behind the
     eyebrow and headline and lets it fade out across the lead, instead of
     sitting under the whole column the way it did. */
  .hero-net { inset: -2% 0 auto 0; height: 26%; opacity: .42; }
  .hero-net .hx-svg { -webkit-mask-image: radial-gradient(96% 86% at 50% 22%, #000 12%, rgba(0,0,0,.34) 56%, transparent 84%);
                              mask-image: radial-gradient(96% 86% at 50% 22%, #000 12%, rgba(0,0,0,.34) 56%, transparent 84%); }

  /* Two stacked drop-shadows over a field of several hundred elements whose
     opacity changes every frame is the single most expensive thing on this
     page: the whole filter region is re-rasterised each time. It is what made
     the animation stutter on a phone. Keep the brightness lift, which is
     cheap, and drop the shadows, which are not. */
  .hero-net .hx-svg { filter: brightness(1.24) saturate(1.06); }

  /* Every cell carries a CSS transition so its opacity eases between frames.
     That is a nicety at desktop frame rates and a liability on a phone: the
     JS already writes a new value every frame, so the transition adds a
     second interpolation over hundreds of elements for no visible gain. */
  .hx, .hx-link, .hx-node { transition: none !important; }
  .center-h { margin-bottom: 36px; }

  /* The instrument panel is a fixed-layout technical figure: let it scroll
     horizontally inside its own frame instead of squeezing the readouts into
     unreadable slivers. */
  .bench { font-size: 10.5px; }
  .bench-body { grid-template-columns: 1fr; }
  .bench-cell { border-right: none; }
  .bench-foot { flex-wrap: wrap; gap: 4px 12px; }

  .probe-viz { min-height: 300px; }
  .probe { width: 46%; }
  .probe-2 { top: 88px; }
  .probe-3 { top: 176px; }
  .probe-1 { top: 0; }
  .probe-paths { display: none; }
  .probe-node { display: none; }

  .organ-viz { min-height: 340px; }
  .organ-spacer { min-height: 90px; }
  .organ-net { top: 8%; bottom: 40%; }

  .metrics { grid-template-columns: repeat(2, 1fr); }
  .pipe-mid { padding: 10px 0; }
  .pipe3 { gap: 18px; }
}

@media (max-width: 560px) {
  :root { --gutter: 18px; }
  .hero h1 { font-size: clamp(30px, 9vw, 42px); }
  .hero-actions .btn { width: 100%; justify-content: center; }
  .center-h, .two-grid h2, .cta-h { font-size: clamp(24px, 7.4vw, 34px); }
  .mem-thesis { font-size: clamp(18px, 5.6vw, 24px); }
  .lead { font-size: 15.5px; }

  /* Long numeric readouts must wrap rather than push the layout wide. */
  .readout, .rows { font-size: 9.5px; }
  .readout span, .row { overflow-wrap: anywhere; }

  .code pre { font-size: 11px; padding: 12px; }
  .states { grid-template-columns: 1fr 1fr; }
  .metrics { grid-template-columns: 1fr 1fr; gap: 10px; }
  .metric { padding: 12px 13px; }
  .stage-card { padding: 20px 18px; }
  .bb-phrases { font-size: 10px; gap: 10px; letter-spacing: .16em; }
  .footer-bottom { flex-direction: column; gap: 6px; }
  .foot-cols { gap: 18px; }

  /* Stack the probe cards; absolute positioning has no room to work with. */
  .probe-viz { min-height: 0; display: grid; gap: 10px; }
  .probe { position: static; width: auto; }
  .probe-1, .probe-2, .probe-3 { transform: none; }

  /* The roadmap ladder scrolls; it must not silently clip its last rung. */
  .ladder { margin-top: 34px; padding-bottom: 14px; }
  .rung { min-width: 96px; }
}

@media (max-width: 400px) {
  .nav-cta .btn-primary { padding: 9px 12px; font-size: 12.5px; }
  .brand-word { height: 11px; }
  .states { grid-template-columns: 1fr; }
  .bench { font-size: 9.5px; }
}

/* Coarse pointers: give every control a 44 px touch target, which is the iOS
   and Android minimum and is not satisfied by the desktop paddings above. */
@media (pointer: coarse) {
  .btn { min-height: 44px; }
  .nav-links a, .foot-cols a { padding-block: 9px; }
  .theme-toggle { width: 42px; height: 42px; }
  .link-arrow { padding-block: 8px; }
}
