/* ============================================================================
   NOVA DYNAMICS — STYLES
   ----------------------------------------------------------------------------
   Layout reference: full-height splash screens that snap as you scroll, with a
   fixed transparent top bar.

   Most visual tweaks (colour, bar height, type scale) can be made by changing
   the custom properties in the :root block below — you shouldn't need to hunt
   through the rest of the file.
   ========================================================================== */

/* ---- Design tokens ------------------------------------------------------ */
:root {
  /* Brand — sampled from the Nova Dynamics mark */
  --accent:          #21c6ea;
  --accent-deep:     #0a6f96;

  /* Surfaces & ink */
  --bg:              #070a10;
  --ink:             #ffffff;
  --ink-dim:         rgba(255, 255, 255, 0.72);
  --ink-faint:       rgba(255, 255, 255, 0.45);
  --rule:            rgba(255, 255, 255, 0.18);

  /* Top bar.
     Two sizes: a large one at the top of the page, and a compact one that it
     shrinks to once you start scrolling, so the bar doesn't permanently eat a
     fifth of every splash screen.
     To keep it large the whole way down, delete the `.topbar.is-scrolled`
     height / logo rules further down this file. */
  --bar-h:           clamp(88px, 14vw, 200px);
  --bar-h-compact:   clamp(66px, 8vw, 112px);
  --logo-h:          clamp(52px, 9vw, 128px);
  --logo-h-compact:  clamp(40px, 5vw, 72px);
  --bar-bg:          rgba(7, 10, 16, 0.82);

  /* Rhythm */
  --gutter:          clamp(20px, 4vw, 56px);
  --maxw:            1100px;

  /* Type */
  --font: "Segoe UI", -apple-system, BlinkMacSystemFont, "Helvetica Neue",
          Arial, sans-serif;
  --track-wide:      0.28em;   /* eyebrows, nav, buttons */
  --track-tight:     0.01em;   /* display headings */

  --ease:            cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ---- Reset -------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  /* Snapping is OFF. Even on `proximity` it fought the scroll wheel: a screen
     is a whole viewport tall, one wheel notch moves a fraction of that, so the
     snap kept pulling you back to the screen you were trying to leave — which
     reads as the page being stuck.
     `y proximity` brings back the gentle version, `y mandatory` the firm
     one-screen-at-a-time version. Both need a scroll wheel to be tested with,
     not a trackpad — trackpads scroll far enough per gesture to escape. */
  scroll-snap-type: none;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { display: block; max-width: 100%; }
a   { color: inherit; text-decoration: none; }
ul  { list-style: none; margin: 0; padding: 0; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  padding: 12px 20px;
  background: var(--accent);
  color: #001018;
  font-weight: 700;
}
.skip-link:focus { left: 8px; top: 8px; }

/* ============================================================================
   TOP BAR
   ========================================================================== */
.topbar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  height: var(--bar-h);
  padding: 0 var(--gutter);
  display: flex;
  align-items: center;
  gap: 24px;

  /* Transparent over the first splash, then fades in a backdrop on scroll. */
  background: transparent;
  transition: background-color 0.35s var(--ease),
              backdrop-filter   0.35s var(--ease),
              height            0.35s var(--ease);
}

.topbar.is-scrolled {
  height: var(--bar-h-compact);
  background: var(--bar-bg);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}

/* Keeps the bar legible over bright imagery while it is still transparent. */
.topbar::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.55), transparent);
  opacity: 1;
  transition: opacity 0.35s var(--ease);
  pointer-events: none;
}
.topbar.is-scrolled::before { opacity: 0; }

/* -- Logo ----------------------------------------------------------------- */
.brand {
  display: flex;
  align-items: center;
  margin-right: auto;
  flex: 0 0 auto;
}

.brand__img {
  height: var(--logo-h);
  width: auto;
  transition: opacity 0.25s var(--ease), height 0.35s var(--ease);
}
.topbar.is-scrolled .brand__img { height: var(--logo-h-compact); }
.brand:hover .brand__img { opacity: 0.78; }

/* -- Nav links ------------------------------------------------------------ */
.nav {
  display: flex;
  align-items: center;
  gap: clamp(18px, 2.6vw, 40px);
}

.nav__link {
  position: relative;
  padding: 6px 0;
  font-size: clamp(12px, 1vw, 15px);
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
}

.nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.3s var(--ease);
}
.nav__link:hover::after,
.nav__link:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* -- Hamburger ------------------------------------------------------------ */
.menu-toggle {
  position: relative;
  z-index: 2;
  width: 40px;
  height: 40px;
  display: grid;
  align-content: center;
  gap: 7px;
  flex: 0 0 auto;
}

.menu-toggle__bar {
  display: block;
  height: 1.5px;
  width: 100%;
  background: var(--ink);
  transition: transform 0.3s var(--ease), opacity 0.2s var(--ease);
}

.menu-toggle[aria-expanded="true"] .menu-toggle__bar:nth-child(1) {
  transform: translateY(8.5px) rotate(45deg);
}
.menu-toggle[aria-expanded="true"] .menu-toggle__bar:nth-child(2) { opacity: 0; }
.menu-toggle[aria-expanded="true"] .menu-toggle__bar:nth-child(3) {
  transform: translateY(-8.5px) rotate(-45deg);
}

/* ============================================================================
   DROPDOWN MENU
   ----------------------------------------------------------------------------
   Hangs off the bottom of the top bar, right-aligned under the hamburger. It
   used to be a full-screen overlay; it holds the same links, but as a panel.

   It sits outside `.topbar` in the markup, so it can't inherit the bar's
   height — `js/chrome.js` puts `is-scrolled` on <body> as well as on the bar,
   and the rule below moves the panel up when the bar shrinks.
   ========================================================================== */
.menu {
  position: fixed;
  z-index: 55;
  top: var(--bar-h);
  right: var(--gutter);
  width: min(320px, calc(100vw - var(--gutter) * 2));
  padding: 22px 24px 24px;
  background: rgba(7, 10, 16, 0.96);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  opacity: 0;
  transform: translateY(-8px);
  transform-origin: top right;
  transition: opacity 0.22s var(--ease), transform 0.22s var(--ease),
              top 0.35s var(--ease);
}
.menu[hidden] { display: none; }
.menu.is-open { opacity: 1; transform: none; }

body.is-scrolled .menu { top: var(--bar-h-compact); }

.menu__label {
  margin: 0 0 10px;
  font-size: 10px;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--accent);
}

.menu__list {
  margin: 0 0 22px;
  display: grid;
  gap: 1px;
}
.menu__list:last-child { margin-bottom: 0; }

.menu__link {
  display: block;
  padding: 8px 10px;
  margin-inline: -10px;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--ink-dim);
  transition: color 0.2s var(--ease), background-color 0.2s var(--ease);
}
.menu__link:hover,
.menu__link:focus-visible {
  color: var(--ink);
  background: rgba(255, 255, 255, 0.06);
}

.menu__list--small .menu__link {
  font-size: 11px;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

/* ============================================================================
   SPLASH SCREENS
   ========================================================================== */
.splash {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  /* No `scroll-snap-stop: always` — a long scroll or flick is allowed to run
     through several screens rather than being caught by every one of them. */
  scroll-snap-align: start;
  display: grid;
  align-items: center;
  /* Sized off the compact bar, not the tall one — the bar has already shrunk
     by the time you're looking at any screen other than the first. */
  padding: calc(var(--bar-h-compact) + 56px) var(--gutter) 96px;
  overflow: hidden;
  isolation: isolate;
}

/* Background image lives on its own layer so it can be dimmed independently. */
.splash__bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.splash__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(120% 90% at 50% 55%, transparent 25%, rgba(0, 0, 0, 0.55) 100%),
    linear-gradient(to top, rgba(0, 0, 0, 0.72) 0%, transparent 45%);
}

/* Extra dimming for a photo that is too busy or too bright to read small text
   over — set `darken: true` on the screen in content/site.js. The scrim above
   only shades the edges; this knocks the whole picture back. Earthworm needs
   it: mid-tone soil, right across the frame, with nowhere quiet for the
   eyebrow and tagline to sit. Tune the amount here, in one place. */
.splash--darken .splash__bg { filter: brightness(0.45); }

/* `darken: "heavy"` for a picture that is light overall rather than merely
   busy — a white blueprint under white type needs far more than a photograph
   does, and desaturating a little stops the red and blue linework buzzing. */
.splash--darken-heavy .splash__bg { filter: grayscale(0.3) brightness(0.3); }

/* A whole screen can be a link — see `href` in content/site.js. The anchor
   covers the section, under the copy so buttons still work. The headline and
   tagline then have to stop swallowing clicks, or the biggest thing on the
   screen would be a dead spot in the middle of a clickable screen; the buttons
   are handed their clicks back. The cost is that copy on a linked screen can't
   be selected, which is the usual bargain for a clickable hero. */
.splash__link {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.splash--linked .splash__content { pointer-events: none; }
.splash--linked .splash__actions { pointer-events: auto; }

.splash__content {
  position: relative;   /* keeps the copy above .splash__link */
  z-index: 1;
  width: min(var(--maxw), 100%);
  margin-inline: auto;
  text-align: center;
}

/* Copy slides up as each screen scrolls into view.
   This is deliberately opt-in: the `has-reveal` class is added to <html> by
   js/site.js only once it knows it can drive the animation. Without it — no
   JS, no IntersectionObserver, reduced motion — the copy is simply visible,
   so the page never depends on script to render its own content. */
.has-reveal .splash__content {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}
.has-reveal .splash.is-visible .splash__content {
  opacity: 1;
  transform: none;
}

.splash--left .splash__content {
  margin-inline: 0 auto;
  text-align: left;
}

.splash__eyebrow {
  margin: 0 0 14px;
  font-size: clamp(10px, 1.1vw, 13px);
  font-weight: 600;
  /* Tightened from the default, because this can be several stacked lines
     (DaxBot) and the normal 1.55 body leading leaves them floating apart. */
  line-height: 1.9;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-dim);
}

.splash__title {
  margin: 0;
  font-size: clamp(2.6rem, 8.5vw, 6rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: var(--track-tight);
  text-transform: uppercase;
  text-shadow: 0 2px 40px rgba(0, 0, 0, 0.5);
}

.splash__tagline {
  margin: 22px auto 0;
  max-width: 46ch;
  font-size: clamp(1rem, 1.5vw, 1.25rem);
  color: var(--ink-dim);
}
.splash--left .splash__tagline { margin-inline: 0; }

/* The eyebrow's mirror image — same small, wide-tracked caption, sitting under
   the copy instead of over it, and a shade fainter because it's an aside. */
.splash__footnote {
  margin: 20px 0 0;
  font-size: clamp(10px, 1.1vw, 13px);
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-faint);
}

.splash__body {
  margin: 20px auto 0;
  max-width: 58ch;
  font-size: clamp(0.95rem, 1.15vw, 1.05rem);
  line-height: 1.75;
  color: var(--ink-faint);
}
.splash--left .splash__body { margin-inline: 0; }

/* -- Company screen -------------------------------------------------------
   The logo in the bar already says "Nova Dynamics", so the heading here is
   pitched smaller than a product name and the statement line carries the
   weight instead. */
.splash--intro .splash__title {
  font-size: clamp(2rem, 5.5vw, 4rem);
}

/* This carries the company statement, so it is bigger and brighter than a
   product tagline. Sized for two short sentences — if the statement ever grows
   into a paragraph again, widen the measure and drop a size, or it becomes a
   wall of display type that pushes the buttons off a laptop screen. */
.splash--intro .splash__tagline {
  max-width: 34ch;
  font-size: clamp(1.15rem, 2.1vw, 1.7rem);
  font-weight: 600;
  line-height: 1.4;
  color: var(--ink);
}

.splash--intro .splash__body { color: var(--ink-dim); }

/* -- Layered photo --------------------------------------------------------
   A product shot sitting on top of the backdrop, for screens that set
   `foreground` in content/site.js. The shots are lit on white, so they read as
   a card floating over the backdrop rather than a cut-out; the shadow and the
   hairline border are what sell that. Height is capped against the viewport so
   the screen still fits without scrolling on a laptop. */
/* Stacked under the copy: the narrow-screen arrangement.

   These are cut-outs on transparency, so the shadow is a `drop-shadow` filter
   — it follows the silhouette, where `box-shadow` would draw a rectangle in
   mid-air around it. A foreground photo that still has its own background
   would need the rectangle back, plus a border to make it read as a card. */
.splash__foreground {
  margin: 28px auto 0;
  max-height: min(38vh, 330px);
  width: auto;
  filter: drop-shadow(0 20px 30px rgba(0, 0, 0, 0.6));
}
.splash--left .splash__foreground { margin-inline: 0 auto; }

/* The backdrop under a layered screen is scenery, not the subject — push it
   back so the photo on top is clearly the thing you're meant to look at. */
.splash--layered .splash__bg {
  filter: grayscale(0.4) brightness(0.48);
}

/* Stacked, on a narrow screen. `display: contents` dissolves the copy wrapper
   so the photo can sit between the words and the button, the way it reads on
   the wide layout — the wrapper only exists to be a grid column up there. */
@media (max-width: 860px) {
  .splash--layered .splash__copy { display: contents; }

  .splash--layered .splash__content {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .splash--layered .splash__foreground { order: 1; }
  .splash--layered .splash__actions    { order: 2; }
}

/* Side by side once there is width for it. Standing the photo next to the copy
   rather than under it roughly doubles the height available to it, which is the
   only reason it can be this big and still leave the screen one viewport tall.
   The heading drops a size here so it still fits its narrower column. */
@media (min-width: 861px) {
  .splash--layered .splash__content {
    width: min(1180px, 100%);
    display: grid;
    grid-template-columns: minmax(0, 1.12fr) minmax(0, 1fr);
    column-gap: clamp(32px, 4.5vw, 68px);
    align-items: center;
    text-align: left;
  }

  .splash--layered .splash__title {
    font-size: clamp(2.2rem, 5.4vw, 4.4rem);
  }

  .splash--layered .splash__tagline,
  .splash--layered .splash__body { margin-inline: 0; }

  .splash--layered .splash__actions { justify-content: flex-start; }

  /* The cut-out is 722x790, so this is well inside native resolution — what
     caps it here is vertical fit. At 1400x808 the screen lands on exactly one
     viewport with about 20px to spare; much past 540 and the copy starts
     getting pushed off the bottom of short laptop windows. */
  .splash--layered .splash__foreground {
    margin: 0;
    max-height: min(60vh, 520px);
    justify-self: center;
  }
}

/* -- Index screen ---------------------------------------------------------
   A screen that lists several projects as cards instead of giving each one a
   full screen of its own. See `items` in content/site.js. */
.splash--index .splash__content { width: min(1180px, 100%); }

.projects {
  margin-top: 44px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 18px;
  text-align: left;
}

.projects__card {
  display: block;
  padding: 26px 24px 28px;
  border: 1px solid var(--rule);
  background: rgba(7, 10, 16, 0.62);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: border-color 0.3s var(--ease), background-color 0.3s var(--ease),
              transform 0.3s var(--ease);
}

.projects__card--link:hover,
.projects__card--link:focus-visible {
  border-color: var(--accent);
  background: rgba(7, 10, 16, 0.82);
  transform: translateY(-4px);
}

.projects__eyebrow {
  margin: 0 0 10px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--accent);
}

.projects__name {
  margin: 0;
  font-size: clamp(1.05rem, 1.7vw, 1.3rem);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: var(--track-tight);
  text-transform: uppercase;
}

.projects__text {
  margin: 12px 0 0;
  font-size: 0.9rem;
  line-height: 1.65;
  color: var(--ink-dim);
}

.splash__actions {
  margin-top: 38px;
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  justify-content: center;
}
.splash--left .splash__actions { justify-content: flex-start; }

/* -- Ghost button --------------------------------------------------------- */
.btn {
  --btn-ink: var(--ink);
  position: relative;
  isolation: isolate;   /* keeps the ::before fill layer inside the button */
  display: inline-block;
  padding: 15px 42px;
  border: 1px solid var(--btn-ink);
  color: var(--btn-ink);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  overflow: hidden;
  transition: color 0.3s var(--ease), border-color 0.3s var(--ease);
}

.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--btn-ink);
  transform: translateY(101%);
  transition: transform 0.35s var(--ease);
}
.btn:hover,
.btn:focus-visible { color: #050810; }
.btn:hover::before,
.btn:focus-visible::before { transform: translateY(0); }

.btn--accent {
  --btn-ink: var(--accent);
}

/* -- Scroll cue on the first screen --------------------------------------- */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 34px;
  translate: -50% 0;
  display: grid;
  justify-items: center;
  gap: 10px;
  font-size: 10px;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-faint);
}

.scroll-cue__line {
  width: 1px;
  height: 46px;
  background: linear-gradient(to bottom, var(--ink-faint), transparent);
  animation: cue 2.2s var(--ease) infinite;
  transform-origin: top;
}

@keyframes cue {
  0%        { transform: scaleY(0); opacity: 0; }
  40%       { transform: scaleY(1); opacity: 1; }
  100%      { transform: scaleY(1); opacity: 0; transform-origin: bottom; }
}

/* ============================================================================
   SCROLL DOTS
   ========================================================================== */
.dots {
  position: fixed;
  z-index: 50;
  right: clamp(12px, 2vw, 26px);
  top: 50%;
  translate: 0 -50%;
  display: grid;
  gap: 16px;
}

.dots__dot {
  width: 9px;
  height: 9px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--ink-faint);
  background: transparent;
  transition: background-color 0.3s var(--ease),
              border-color     0.3s var(--ease),
              scale            0.3s var(--ease);
}
.dots__dot:hover { border-color: var(--ink); }
.dots__dot.is-active {
  background: var(--accent);
  border-color: var(--accent);
  scale: 1.25;
}

/* ============================================================================
   PRODUCT PAGES
   ----------------------------------------------------------------------------
   earthworm.html, nethatchet.html — the pages behind the "Learn More" buttons.
   Same shell, same chrome as the home page; only the body below differs.
   ========================================================================== */
/* A product page can be shorter than the window — Net Hatchet is, until its
   copy is written. Without this the footer would sit stranded halfway down
   with page background below it. */
.page-body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
.page-body #main {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}

.page {
  position: relative;
  flex: 1 0 auto;
  /* Sized off the *tall* bar, unlike the splash screens: a product page is at
     scroll 0 when you arrive, so the bar hasn't shrunk yet. */
  padding: calc(var(--bar-h) + 48px) var(--gutter) 88px;
}

/* The picture behind the whole page. Fixed, so it holds still while the copy
   scrolls over it, and knocked well back so the copy stays readable. */
.page__bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  background-repeat: no-repeat;
  pointer-events: none;
}

/* Line art is drawn dark-on-pale, which is backwards for this site. Inverting
   it turns it into a blueprint — pale lines on a dark ground — and it sits at
   its own size rather than being stretched to fill. */
.page__bg--drawing {
  background-position: center 38%;
  background-size: min(1500px, 130%) auto;
  filter: invert(1);
  opacity: 0.16;
}

.page__bg--photo {
  background-position: center;
  background-size: cover;
  opacity: 0.22;
}

/* -- Hero ----------------------------------------------------------------- */
.page__hero {
  width: min(var(--maxw), 100%);
  margin-inline: auto;
}

.page__back {
  display: inline-block;
  margin-bottom: 34px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: color 0.25s var(--ease);
}
.page__back:hover { color: var(--accent); }

.page__eyebrow {
  margin: 0 0 14px;
  font-size: clamp(10px, 1.1vw, 13px);
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-dim);
}

.page__title {
  margin: 0;
  font-size: clamp(2.4rem, 6.5vw, 4.6rem);
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: var(--track-tight);
  text-transform: uppercase;
  text-shadow: 0 2px 40px rgba(0, 0, 0, 0.5);
}

.page__tagline {
  margin: 20px 0 0;
  max-width: 52ch;
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  color: var(--ink-dim);
}

/* -- Description ---------------------------------------------------------- */
.page__body {
  width: min(var(--maxw), 100%);
  margin: 44px auto 0;
}

.page__body p {
  margin: 0 0 20px;
  max-width: 72ch;
  font-size: clamp(0.98rem, 1.2vw, 1.08rem);
  line-height: 1.85;
  color: var(--ink-dim);
}
.page__body p:last-child { margin-bottom: 0; }

/* -- Specifications table ------------------------------------------------- */
.specs {
  width: min(var(--maxw), 100%);
  margin: 64px auto 0;
}

.specs__title {
  margin: 0 0 8px;
  font-size: clamp(1.25rem, 2.4vw, 1.7rem);
  font-weight: 700;
  letter-spacing: var(--track-tight);
}

.specs__intro {
  margin: 0 0 22px;
  max-width: 76ch;
  font-size: 0.92rem;
  line-height: 1.7;
  color: var(--ink-faint);
}

/* The table is wide; let it scroll inside its own box rather than pushing the
   whole page sideways on a phone. */
.specs__scroll {
  overflow-x: auto;
  border: 1px solid var(--rule);
  background: rgba(7, 10, 16, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.specs__table {
  width: 100%;
  min-width: 620px;
  border-collapse: collapse;
  font-size: 0.93rem;
}

.specs__table th,
.specs__table td {
  padding: 12px 16px;
  border: 1px solid var(--rule);
  text-align: left;
  vertical-align: top;
  line-height: 1.6;
}

.specs__table thead th {
  background: rgba(33, 198, 234, 0.13);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
}

.specs__table tbody tr:nth-child(even) { background: rgba(255, 255, 255, 0.03); }

.specs__label {
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
}

.specs__table td { color: var(--ink-dim); }

.specs__note {
  margin: 14px 0 0;
  font-size: 0.82rem;
  line-height: 1.6;
  color: var(--ink-faint);
}

/* -- Blocks: features, application notes, documentation ------------------- */
.block {
  width: min(var(--maxw), 100%);
  margin: 52px auto 0;
}

.block__title {
  margin: 0 0 14px;
  font-size: clamp(1.15rem, 2.2vw, 1.5rem);
  font-weight: 700;
  letter-spacing: var(--track-tight);
}

.block__text {
  margin: 0 0 16px;
  max-width: 72ch;
  line-height: 1.8;
  color: var(--ink-dim);
}

.block__list {
  max-width: 76ch;
  display: grid;
  gap: 10px;
}

.block__list li {
  position: relative;
  padding-left: 24px;
  line-height: 1.7;
  color: var(--ink-dim);
}
.block__list li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.72em;
  width: 7px;
  height: 1px;
  background: var(--accent);
}

/* Numbered steps, for the application notes. The counter replaces the dash —
   and the browser's own <ol> marker has to go, or you get "1. 1.". The reset
   at the top of this file only clears `ul`. */
.block__list--steps {
  counter-reset: step;
  gap: 16px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.block__list--steps li { padding-left: 40px; }
.block__list--steps li::before {
  counter-increment: step;
  content: counter(step) ".";
  top: 0;
  left: 0;
  width: 30px;
  height: auto;
  background: none;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--accent);
}

.block__link {
  color: var(--ink);
  border-bottom: 1px solid rgba(33, 198, 234, 0.5);
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.block__link:hover,
.block__link:focus-visible {
  color: var(--accent);
  border-color: var(--accent);
}

/* -- Revision / author line on an application note ------------------------ */
.page__meta {
  margin: 24px 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 28px;
  font-size: 11px;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-faint);
}
.page__meta dt { font-weight: 600; }
.page__meta dt::after { content: ":"; }
.page__meta dd { margin: 0 0 0 -20px; }

.block__note {
  margin: 18px 0 0;
  max-width: 76ch;
  padding: 14px 18px;
  border-left: 2px solid var(--accent);
  background: rgba(33, 198, 234, 0.07);
  font-size: 0.9rem;
  line-height: 1.65;
  color: var(--ink-dim);
}

/* -- Postal address -------------------------------------------------------- */
.page__address {
  width: min(var(--maxw), 100%);
  margin: 44px auto 0;
  font-style: normal;
  line-height: 1.9;
  color: var(--ink-dim);
}

/* -- Contact form ---------------------------------------------------------- */
.form-block {
  width: min(var(--maxw), 100%);
  margin: 44px auto 0;
}

.form {
  max-width: 620px;
  padding: 28px;
  border: 1px solid var(--rule);
  background: rgba(7, 10, 16, 0.7);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.form__row { margin: 0 0 20px; }

.form__label {
  display: block;
  margin-bottom: 8px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-dim);
}

.form__req { margin-left: 4px; color: var(--accent); }

.form__input {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--rule);
  background: rgba(255, 255, 255, 0.04);
  color: var(--ink);
  font: inherit;
  transition: border-color 0.25s var(--ease), background-color 0.25s var(--ease);
}
.form__input:focus {
  outline: none;
  border-color: var(--accent);
  background: rgba(255, 255, 255, 0.07);
}

.form__input--area { resize: vertical; min-height: 150px; }

/* The spam trap. Off-screen rather than display:none, so bots that skip
   hidden fields still fill it in. */
.form__trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.form__actions { margin-top: 26px; }

.form__status {
  margin: 16px 0 0;
  min-height: 1.2em;
  font-size: 0.88rem;
  color: var(--ink-faint);
}

/* -- Copy that hasn't been written yet ------------------------------------ */
.page__todo,
.page__missing {
  width: min(var(--maxw), 100%);
  margin: 44px auto 0;
  padding: 18px 22px;
  border: 1px dashed var(--rule);
  font-size: 0.92rem;
  color: var(--ink-faint);
}

@media (max-width: 720px) {
  .specs__table th,
  .specs__table td { padding: 10px 12px; }
}

/* ============================================================================
   FOOTER
   ========================================================================== */
.footer {
  scroll-snap-align: end;
  padding: 64px var(--gutter) 40px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  background: var(--bg);
}

.footer__inner {
  width: min(var(--maxw), 100%);
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 24px 40px;
}

.footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 30px;
}

.footer__link {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: color 0.25s var(--ease);
}
.footer__link:hover { color: var(--ink); }

.footer__copy {
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
}

/* ============================================================================
   RESPONSIVE
   ========================================================================== */
@media (max-width: 720px) {
  .dots { display: none; }

  .splash__actions { justify-content: center; }
  .splash--left .splash__content { text-align: center; }
  .splash--left .splash__actions { justify-content: center; }
  .splash--left .splash__tagline { margin-inline: auto; }
  .splash--left .splash__body { margin-inline: auto; }

  .footer__inner { justify-content: center; text-align: center; }
  .footer__links { justify-content: center; }
}

/* The hamburger is the only navigation now, at every width. */
.menu-toggle { margin-left: 8px; }

/* ---- Motion preferences ------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; scroll-snap-type: none; }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }

  .has-reveal .splash__content { opacity: 1; transform: none; }
}

/* ---- Print -------------------------------------------------------------- */
@media print {
  .topbar, .dots, .menu, .scroll-cue { display: none; }
  .splash { min-height: auto; page-break-after: always; }
  body { background: #fff; color: #000; }
}
