/* ============================================================================
   LRT redesign — base + nav. Hero and sections appended after nav is verified.
   Signature: the ablation boundary. Nav is the invariant; built first.
   ============================================================================ */

/* --- reset / base --------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  color: var(--ink-on-dark);
  background: var(--surface);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img, svg, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
::selection { background: var(--aperture); color: #fff; }

/* Two rings, because no single colour clears the 3:1 non-text floor on all three
   surfaces this site puts focusable things on. The red is 3.33:1 on --surface
   and 3.48:1 on the light plate but only 2.10:1 on --surface-2 panels; the light
   halo is 17:1 and 10.8:1 on those dark surfaces but vanishes on the plate.
   Together, one of the two always carries the boundary. */
:focus-visible {
  outline: 2px solid var(--aperture);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px rgba(253, 251, 244, 0.9);
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-stretch: var(--display-stretch);
  font-weight: 900;
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  /* Backstop for enlarged text. Raise the browser's default font size and a
     display word can outgrow its column; body sets overflow-x:hidden, so the
     part that overflows is not merely ugly, it is unreachable — there is
     nothing to scroll. Inert at normal sizes, where nothing overflows. */
  overflow-wrap: break-word;
}

.container { width: min(100% - 2 * var(--gutter), var(--container)); margin-inline: auto; }

.mono {
  font-family: var(--font-mono);
  font-size: var(--t-data);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  font-weight: 500;
}

.skip {
  position: absolute; left: var(--s2); top: -4rem; z-index: 100;
  background: var(--aperture); color: #fff; padding: 0.6rem 1rem;
  font-family: var(--font-mono); font-size: var(--t-data); text-transform: uppercase; letter-spacing: 0.04em;
  transition: top var(--aperture-dur) var(--ease-ui);
}
.skip:focus { top: var(--s2); }

/* --- buttons -------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: 0.5em;
  font-family: var(--font-mono); font-size: var(--t-data); font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.06em;
  min-height: 44px;                       /* touch target floor */
  padding: 0.7em 1.1em; border: var(--hair) solid var(--edge-ui); border-radius: 2px;
  color: var(--ink-on-dark); background: transparent;
  transition: border-color var(--aperture-dur) var(--ease-ui), color var(--aperture-dur) var(--ease-ui), background var(--aperture-dur) var(--ease-ui);
}
.btn:hover { border-color: var(--edge); color: var(--ink-hi); }
.btn--aperture {
  background: var(--aperture); border-color: var(--aperture); color: #fff;
  position: relative;
}
.btn--aperture:hover { background: var(--aperture); color: #fff; box-shadow: inset 0 0 0 1px rgba(255,255,255,.35), 0 0 0 3px rgba(210,31,39,.28); }

/* ========================================================================== */
/* NAV — the invariant                                                        */
/* ========================================================================== */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 60;
  transition: transform 220ms var(--ease-ui), background-color 220ms var(--ease-ui);
  will-change: transform;
}
.nav__in {
  display: flex; align-items: center; gap: var(--s4);
  height: var(--nav-h);
}
.nav__edge {                       /* the boundary at rest — persistent anchor */
  position: absolute; left: 0; right: 0; bottom: 0; height: var(--hair);
  background: var(--edge-dim);
}

/* states */
.nav.is-top { background: transparent; }
.nav.is-top .nav__edge { background: linear-gradient(90deg, transparent, rgba(253,251,244,.22) 12%, rgba(253,251,244,.22) 88%, transparent); }
.nav.is-stuck { background: var(--surface-2); }
.nav.is-stuck .nav__edge { background: var(--edge-dim); }
.nav.is-hidden { transform: translateY(-100%); }

/* brand — the client's own lockup (reversed colourway for dark UI) */
.brand { display: inline-flex; align-items: center; margin-right: auto; }
.brand__logo { height: 40px; width: auto; }
@media (max-width: 767px) { .brand__logo { height: 34px; } }

/* primary links — the spec-plate voice, with the cleaning-edge underline */
.nav__list { display: flex; align-items: center; gap: clamp(0.9rem, 2vw, 1.9rem); list-style: none; padding: 0; }
.nav__list a {
  position: relative; display: inline-block; padding: 0.4rem 0;
  font-family: var(--font-mono); font-size: var(--t-data); font-weight: 500;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-dim-panel);
  transition: color var(--aperture-dur) var(--ease-ui);
}
.nav__list a::after {                 /* the lit edge segment = wayfinding */
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: var(--hair);
  background: var(--edge); transform: scaleX(0); transform-origin: left;
  transition: transform var(--aperture-dur) var(--ease-pass);
}
.nav__list a:hover { color: var(--ink-hi); }
.nav__list a:hover::after { transform: scaleX(1); }
.nav__list a[aria-current="true"] { color: var(--ink-hi); }
.nav__list a[aria-current="true"]::after { transform: scaleX(1); }

.nav__end { display: flex; align-items: center; gap: var(--s3); }
.nav__tel { color: var(--ink-on-dark); }
.nav__tel:hover { color: var(--ink-hi); }

.nav__menu { display: none; align-items: center; gap: 0.5rem; font-family: var(--font-mono); font-size: var(--t-data); text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-hi); min-height: 44px; padding: 0 0.25rem; }
.nav__menu-bars, .nav__menu-bars::before, .nav__menu-bars::after {
  content: ""; display: block; width: 22px; height: 2px; background: currentColor; position: relative;
}
.nav__menu-bars::before { position: absolute; top: -7px; }
.nav__menu-bars::after { position: absolute; top: 7px; }

/* --- breakpoints: each structure is deliberate --------------------------- */
/* Stated in em, not px, and that is the whole point. A media query in em is
   measured against the user's own default font size, so someone browsing at
   200% text gets the Menu button at twice the viewport width — exactly when the
   full nav stops fitting. In px the bar kept trying to lay out links, phone
   number and "Book a demo" at double size and pushed the last two clean off the
   right edge on every page. At a 16px default these evaluate to the same 1023px
   and 768px as before, so nothing moves at normal settings.
   63.9375em = 1023px, 48em = 768px. */
/* ≥1024 desktop: mark · links · tel · Book */
@media (max-width: 63.9375em) {
  .nav__nav, .nav__tel, .nav__cta { display: none; }
  .nav__menu { display: inline-flex; }
}
/* 768–1023 tablet: mark · tel · Menu  (Book lives in the sheet) */
@media (min-width: 48em) and (max-width: 63.9375em) {
  .nav__tel { display: inline-block; }
}
/* <768 mobile: mark · Menu ; bottom bar Call|Book ; links in sheet */

/* ========================================================================== */
/* SHEET — full-bleed destinations (tablet / mobile)                          */
/* ========================================================================== */
.sheet {
  position: fixed; inset: 0; z-index: 70; background: var(--surface);
  opacity: 0; visibility: hidden; transform: translateY(-1.5%);
  /* visibility flips SYNCHRONOUSLY on open and only delays on close. Animating
     it in both directions left the sheet visibility:hidden for 240ms after the
     class went on — and an element that is still hidden cannot take focus, so
     the closeBtn.focus() in app.js silently did nothing and the keyboard user
     was left on the Menu button underneath an opaque overlay. */
  transition: opacity 240ms var(--ease-ui), transform 240ms var(--ease-ui), visibility 0s linear 240ms;
  overscroll-behavior: contain;
}
/* opening: visibility applies on frame one, so focus() lands. The delayed form
   above is for CLOSING only, where it keeps the sheet on screen for the fade. */
.sheet.is-open {
  opacity: 1; visibility: visible; transform: none;
  transition: opacity 240ms var(--ease-ui), transform 240ms var(--ease-ui), visibility 0s linear 0s;
}
/* scrolls if the list is taller than the (dynamic) viewport, and respects the
   iOS notch + home indicator so nothing hides behind the browser chrome */
.sheet { overflow-y: auto; -webkit-overflow-scrolling: touch; }
.sheet__in {
  min-height: 100%;
  display: flex; flex-direction: column;
  padding-inline: clamp(var(--gutter), 4vw, var(--s5));
  padding-top: env(safe-area-inset-top, 0px);
  padding-bottom: calc(var(--s4) + env(safe-area-inset-bottom, 0px));
}
/* mirrors the nav row, so the brand + close sit exactly where the header was */
.sheet__top {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3); min-height: var(--nav-h);
}
.sheet__close {
  font-family: var(--font-mono); font-size: var(--t-data); text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--ink-dim);
  min-height: 44px; display: inline-flex; align-items: center; padding: 0 0.25rem;
}
.sheet__close:hover, .sheet__close:focus-visible { color: var(--ink-hi); }
.sheet__list { list-style: none; padding: 0; margin-top: var(--s3); }
.sheet__list li { border-top: var(--hair) solid var(--edge-dim); }
.sheet__list li:last-child { border-bottom: var(--hair) solid var(--edge-dim); }
.sheet__list a {
  display: block; padding: var(--s3) 0;
  font-family: var(--font-display); font-stretch: 125%; font-weight: 800; text-transform: uppercase;
  font-size: var(--t-d1); color: var(--ink-on-dark); letter-spacing: var(--track-display);
  transition: color var(--aperture-dur) var(--ease-ui), padding-left 160ms var(--ease-ui);
}
.sheet__list a:hover, .sheet__list a:focus-visible { color: var(--ink-hi); padding-left: var(--s2); }
.sheet__foot { margin-top: auto; padding-top: var(--s4); display: grid; gap: var(--s2); justify-items: start; }
.sheet__cta { align-self: start; }
.sheet__tel { font-size: var(--t-data-lg); color: var(--ink-hi); letter-spacing: 0.04em; }
.sheet__where { color: var(--ink-dim); }
@media (min-width: 1024px) { .sheet { display: none; } }

/* ========================================================================== */
/* MOBAR — persistent bottom action bar (<768)                                */
/* ========================================================================== */
.mobar { display: none; }
@media (max-width: 767px) {
  .mobar {
    position: fixed; inset: auto 0 0 0; z-index: 65; display: grid; grid-template-columns: 1fr 1.4fr;
    /* The inset is ADDED to the height, not taken out of it. box-sizing is
       border-box globally, so a fixed 56px height with the safe-area padding
       inside it squeezed both buttons into the ~22px above an iPhone's home
       indicator and drew the rest underneath it — the two most important
       actions on the phone site, half under the gesture bar. body already
       reserves the same total, so this matches what is held for it. */
    height: calc(var(--mobar-h) + env(safe-area-inset-bottom, 0px));
    background: var(--surface-2); border-top: var(--hair) solid var(--edge-dim);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .mobar__btn {
    display: inline-flex; align-items: center; justify-content: center;
    font-family: var(--font-mono); font-size: var(--t-data-lg); text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--ink-hi); min-height: var(--mobar-h);
  }
  .mobar__btn + .mobar__btn { border-left: var(--hair) solid var(--edge-dim); }
  .mobar__btn--aperture { background: var(--aperture); color: #fff; }
  /* reserved space — includes the iOS home-indicator inset, no layout shift */
  body { padding-bottom: calc(var(--mobar-h) + env(safe-area-inset-bottom, 0px)); }
}

/* ========================================================================== */
/* HERO — "The Pass" (signature at 100%)                                      */
/* ========================================================================== */
@property --clip { syntax: '<number>'; inherits: true; initial-value: 100; }

.hero {
  --clip: 100;                     /* % revealed (cleaned). Safe default = shown */
  position: relative; overflow: hidden; isolation: isolate;
  min-height: 100vh; min-height: 100svh; background: var(--graphite);
}
.hero::before {                    /* top scrim — keeps the transparent nav legible */
  content: ""; position: absolute; inset: 0 0 auto 0; height: 170px; z-index: 2; pointer-events: none;
  background: linear-gradient(180deg, rgba(9,10,12,0.72), transparent);
}
.js-pass .hero { --clip: 0; }      /* armed (JS + motion): first paint oxidized  */
.hero.is-passing { --clip: 100; transition: --clip var(--pass-dur) var(--ease-pass); }  /* The Pass */

.hero__photo { position: absolute; inset: 0; z-index: 0; }
.hero__photo img { width: 100%; height: 100%; object-fit: cover; object-position: 44% 52%; }

/* The ignite: a dark overlay the Pass clips away left->right, lighting the frame.
   clip=0 -> covers all (dark);  clip=100 -> gone (photo fully lit). */
.hero__dim { position: absolute; inset: 0; z-index: 1; background: rgba(10,12,16,0.9); clip-path: inset(0 0 0 calc(var(--clip) * 1%)); }

/* scrim — a darker band across the middle where the type wall sits, so the words
   hold, while the beam above and the flash stay bright */
.hero__scrim {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(to bottom,
    rgba(8,9,11,0.62) 0%, rgba(8,9,11,0.30) 16%,
    rgba(8,9,11,0.60) 34%, rgba(8,9,11,0.66) 68%,
    rgba(8,9,11,0.88) 100%);
}

/* the flash edge-light, riding the boundary */
.hero__edge {
  position: absolute; top: 0; bottom: 0; z-index: 3; width: 2px;
  left: calc(var(--clip) * 1%); transform: translateX(-1px);
  background: linear-gradient(180deg, transparent, var(--flash) 14%, var(--flash) 86%, transparent);
  box-shadow: 0 0 20px 2px rgba(253,251,244,0.5), 0 0 5px rgba(253,251,244,0.9);
  opacity: 0; transition: opacity 200ms var(--ease-ui);
}
.hero.is-passing .hero__edge { opacity: 1; }
.hero.is-done .hero__edge { opacity: 0; }

/* --- the type WALL: edge-to-edge, no side-block ------------------------- */
.hero__tag {
  position: absolute; z-index: 5;
  top: calc(var(--nav-h) + var(--s3)); left: clamp(var(--gutter), 4vw, var(--s5));
  color: var(--flash);
}
.hero__title {
  position: absolute; z-index: 5; left: 0; right: 0; top: 50%;
  transform: translateY(-54%);
  padding-inline: clamp(0.35rem, 1.2vw, 1.25rem);
  /* sized in vw so each sentence spans the frame on ONE line at any width —
     tuned to the longest line ("Preserves the substrate.", 24 chars) */
  font-size: clamp(1.5rem, 5.0vw, 6.9rem);
  line-height: 0.92; letter-spacing: -0.03em; text-align: center;
}
.hero__line { display: block; color: var(--flash); white-space: nowrap; }
.hero__line--steel { color: #aeb7c2; }          /* rust removed -> steel kept */

/* the flash, re-blended: screen keeps darks invisible and lets only the light
   bloom through, so the beam lights the frame a second time.
   z-index 4 puts it above the photo, the dim and the edge, but BELOW the type
   at 5. It used to sit at 6, over the words. `screen` only ever lightens, so
   where the bright flame crosses the headline it pushed the glyphs AND the
   pixels around them toward white together, collapsing the contrast of the
   site's main h1 exactly where the picture is brightest. The mobile rule below
   already caps this at opacity .5 "to protect the words" — the same problem,
   found once before. Under the type it cannot wash them out at any opacity. */
.hero__burn { display: none; }                    /* safe default: never covers type */
@supports (mix-blend-mode: screen) {
  .hero__burn {
    display: block;
    position: absolute; inset: 0; z-index: 4; pointer-events: none;
    mix-blend-mode: screen;
    clip-path: inset(0 calc((100 - var(--clip)) * 1%) 0 0);
  }
}
.hero__burn img { width: 100%; height: 100%; object-fit: cover; object-position: 44% 52%; }

/* bottom control rail — specs left, actions right, full width */
.hero__rail {
  position: absolute; z-index: 7; left: 0; right: 0; bottom: 0;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3) var(--s4); flex-wrap: wrap;
  padding: var(--s3) clamp(var(--gutter), 4vw, var(--s5));
  border-top: var(--hair) solid rgba(253,251,244,0.22);
  background: linear-gradient(to top, rgba(8,9,11,0.9), rgba(8,9,11,0.35));
}
.hero__spec { color: var(--steel); font-size: var(--t-data-lg); }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* reveal after the Pass */
.js-pass .hero__tag, .js-pass .hero__title, .js-pass .hero__rail { opacity: 0; }
.hero.is-done .hero__tag, .hero.is-done .hero__title, .hero.is-done .hero__rail {
  opacity: 1; transition: opacity 520ms var(--ease-ui);
}
.hero.is-done .hero__title { transition-delay: 60ms; }
.hero.is-done .hero__rail  { transition-delay: 150ms; }

/* A phone held sideways is ~350px tall at a width ABOVE the 767px mobile
   breakpoint, so it got the desktop hero: full-size type absolutely centred
   between a tag pinned to the top and a rail pinned to the bottom, in a box
   with no room for any of it. The headline printed straight through the Book a
   demo / Call buttons and its last line was cut off by the hero's own
   overflow:hidden. Sized off height, so a short desktop window is covered too:
   give the hero room to exist and let the page scroll instead of overlapping. */
@media (max-height: 30em) {
  .hero { min-height: 30em; }
  .hero__title { font-size: clamp(1.15rem, 3.2vw, 2.2rem); }
  .hero__tag { top: calc(var(--nav-h) + var(--s2)); }
}

@media (max-width: 767px) {
  .hero { min-height: calc(100vh - var(--mobar-h)); min-height: calc(100svh - var(--mobar-h) - env(safe-area-inset-bottom, 0px)); }

  /* type sits in the upper band; the flash is pushed below it so the bloom
     grazes the last line instead of washing the whole headline out */
  .hero__photo img, .hero__burn img { object-position: 44% 72%; }
  .hero__title {
    top: calc(var(--nav-h) + var(--s5)); transform: none;   /* clears the tag */
    font-size: clamp(2.05rem, 10.3vw, 4.2rem);   /* "SUBSTRATE" must fit 320px */
    text-align: left; padding-inline: var(--gutter); line-height: 0.94;
  }
  .hero__line { white-space: normal; }
  .hero__burn { opacity: 0.5; }               /* keep the effect, protect the words */
  .hero__scrim {
    background: linear-gradient(to bottom,
      rgba(8,9,11,0.55) 0%, rgba(8,9,11,0.74) 12%,
      rgba(8,9,11,0.74) 50%, rgba(8,9,11,0.34) 64%,
      rgba(8,9,11,0.88) 100%);
  }
  .hero__rail { flex-direction: column; align-items: flex-start; gap: var(--s2); padding-block: var(--s2) var(--s3); }
}

/* ========================================================================== */
/* SECTIONS — decay tiers 60 -> 30, boundary reduced to structural traits     */
/* ========================================================================== */
@property --wipe { syntax: '<number>'; inherits: true; initial-value: 100; }

section[id] { scroll-margin-top: calc(var(--nav-h) + var(--s2)); }
.anchor { position: absolute; margin-top: calc(-1 * var(--nav-h)); }
.section { padding-block: var(--s6); }
.section--panel { background: var(--surface-2); }
/* panels sit ON --surface-2, so every hairline inside one needs the lighter edge */
.section--panel .rows li,
.section--panel .stack li,
.section--panel .data-row,
.section--panel .data-row li,
.section--panel .team li,
.section--panel .wipe,
.section--panel .frame { border-color: var(--edge-panel); }
.maxw { max-width: 46ch; }

/* eyebrow = the boundary reduced to a mark (signature ~30%) */
.eyebrow { display: inline-flex; align-items: center; gap: 0.75rem; color: var(--flash); margin-bottom: var(--s2); }
.eyebrow::before { content: ""; width: 30px; height: var(--hair); background: currentColor; }
.eyebrow--dark { color: var(--oxide-on-light); }

.section__head { margin-bottom: var(--s4); }
.section__title { font-size: var(--t-d3); color: var(--ink-hi); }
.section--panel .section__title { color: var(--ink-hi); }
/* secondary copy on a panel needs the lighter muted tone to clear AA */
.section--panel :is(.lead, .rows__desc, .col-label, .stack__v, .card p, .figfull figcaption, .vitem__t, .foot__where) { color: var(--ink-dim-panel); }
.lead { font-size: var(--t-lead); color: var(--ink-dim); margin-top: var(--s2); line-height: 1.55; }

/* split: media + copy */
.split { display: grid; gap: var(--s4); }
/* Grid and flex items default to min-width:auto, which refuses to shrink below
   the longest word in them. On a 320px screen one long word ("environmentally")
   is then enough to push the whole page sideways. Every track child opts out. */
.split > *, .cols > *, .cta > * { min-width: 0; }
@media (min-width: 860px) { .split { grid-template-columns: 1fr 1fr; gap: var(--s5); align-items: center; } }
/* The moment .split goes two-up, a heading inside it is living in a ~374px
   column at full display size — the same squeeze the phone rule below solves,
   arriving from the other direction. One long word ("contaminants") is wider
   than the column on its own, and no arrangement of <br> fixes a word that does
   not fit. Hyphenate inside split copy only; the full-width section heads keep
   their whole words. break-word is the backstop for anything with no legal
   hyphenation point.

   NOT overflow-wrap:break-word. "contaminants" very nearly fits this column —
   it is the full stop after it that tips the line over — so break-word finds
   the last legal point and strands the period alone on its own line.

   hyphens:auto is the nice-to-have, not the fix: Chrome only hyphenates when
   its dictionary component is present, so it cannot be relied on. The
   deterministic part is the size. --t-d3 is clamp(2.25rem, 4vw, 3.5rem), which
   has already bottomed out on its 2.25rem floor by 900px — so the type stops
   shrinking exactly where the two-up column is narrowest. Give that band its
   own floor; above it the column is wide enough and the normal scale returns. */
@media (min-width: 860px) {
  .split__copy .section__title { -webkit-hyphens: auto; hyphens: auto; }
}
@media (min-width: 860px) and (max-width: 919px) {
  .split__copy .section__title { font-size: 1.95rem; }
}

/* the section wipe (before -> after on scroll-in) */
.wipe, .frame {
  position: relative; overflow: hidden; border-left: 2px solid var(--flash);
  background: var(--surface-2); --wipe: 100;
}
.wipe { aspect-ratio: 3 / 2; }
.frame { aspect-ratio: 4 / 5; }
.wipe__before, .wipe__after { position: absolute; inset: 0; }
.wipe__before img, .wipe__after img, .frame img { width: 100%; height: 100%; object-fit: cover; }
.wipe__after { clip-path: inset(0 calc((100 - var(--wipe)) * 1%) 0 0); }
.js-pass .wipe { --wipe: 0; }
.wipe.in-view { --wipe: 100; transition: --wipe var(--wipe-dur) var(--ease-pass); }
.wipe__edge { display: none; }

/* layer stack list (artifact #3) */
.stack { list-style: none; padding: 0; margin-top: var(--s3); }
.stack li { display: flex; justify-content: space-between; gap: var(--s3); padding: 0.7rem 0; border-top: var(--hair) solid var(--edge-dim); }
.stack li:last-child { border-bottom: var(--hair) solid var(--edge-dim); }
.stack__k { color: var(--ink-on-dark); }
.stack__v { color: var(--ink-dim); }
.stack__v--keep { color: var(--flash); }

/* removes / surfaces columns */
.cols { display: grid; gap: var(--s3); margin-top: var(--s3); }
@media (min-width: 520px) { .cols { grid-template-columns: 1fr 1fr; gap: var(--s4); } }
.col-label { color: var(--ink-dim); margin-bottom: 0.6rem; }
.tags { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 0.35rem 1rem; }
.tags li { color: var(--ink-on-dark); position: relative; }
.tags li::before { content: "· "; color: var(--accent-text); }

/* equipment data row */
.data-row { list-style: none; padding: 0; margin-top: var(--s3); display: grid; gap: 0; border-top: var(--hair) solid var(--edge-dim); }
.data-row li { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 0.4rem; padding: var(--s3) 0; border-bottom: var(--hair) solid var(--edge-dim); }
/* sized to fit three-up in the narrowest split column (~130px) — "100–2000 W"
   is a single non-breaking token, so the type has to fit rather than wrap */
.data-row__v { font-family: var(--font-display); font-stretch: 110%; font-weight: 800; font-size: 1.1rem; letter-spacing: -0.01em; color: var(--ink-hi); text-transform: uppercase; overflow-wrap: anywhere; }
.data-row__k { color: var(--ink-dim); }
@media (min-width: 760px) { .data-row { grid-template-columns: repeat(3, 1fr); } .data-row li { flex-direction: column; align-items: flex-start; gap: 0.5rem; border-bottom: 0; border-right: var(--hair) solid var(--edge-dim); padding: var(--s3) var(--s4) var(--s3) 0; } .data-row li:last-child { border-right: 0; } }

/* markets rows */
.rows { list-style: none; padding: 0; }
.rows li { display: grid; gap: 0.35rem; padding: var(--s4) 0; border-top: var(--hair) solid var(--edge-dim); position: relative; }
.rows li:last-child { border-bottom: var(--hair) solid var(--edge-dim); }
.rows li::before { content: ""; position: absolute; left: 0; top: -1px; width: 0; height: 2px; background: var(--flash); transition: width var(--wipe-dur) var(--ease-pass); }
.rows li:hover::before { width: 64px; }
@media (min-width: 760px) { .rows li { grid-template-columns: minmax(0, 1.1fr) 1fr; gap: var(--s4); align-items: baseline; } }
.rows__name { font-family: var(--font-display); font-stretch: 118%; font-weight: 800; font-size: clamp(1.5rem, 3vw, 2.1rem); line-height: 1.05; color: var(--ink-hi); }
.rows__desc { color: var(--ink-dim); }

/* the spec plate (bright steel — material shift) */
.section--plate { background: var(--surface-light); color: var(--ink-on-light); }
.section--plate .plate-line { font-size: clamp(1.25rem, 2.6vw, 1.9rem); font-weight: 500; max-width: 30ch; margin-top: var(--s2); color: var(--ink-on-light); }
.section--plate .plate-line strong { font-weight: 600; color: #10121a; }
.plate { list-style: none; padding: 0; margin-top: var(--s4); display: flex; flex-wrap: wrap; gap: 0; border-top: 2px solid var(--ink-on-light); }
.plate li { padding: var(--s2) var(--s3); border-right: var(--hair) solid rgba(16,18,26,0.25); color: var(--ink-on-light); font-weight: 500; }
.plate li:first-child { padding-left: 0; }

/* cta + team */
.section--cta { position: relative; }
.section--cta::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px; background: linear-gradient(90deg, var(--flash), transparent 40%); }
.cta { display: grid; gap: var(--s5); }
@media (min-width: 860px) { .cta { grid-template-columns: 1.2fr 1fr; gap: var(--s6); align-items: start; } }
.team { list-style: none; padding: 0; }
.team li { border-top: var(--hair) solid var(--edge-dim); }
.team li:last-child { border-bottom: var(--hair) solid var(--edge-dim); }
.team a { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); padding: var(--s3) 0; color: var(--ink-on-dark); }
.team a:hover { color: var(--ink-hi); }
.team__who { display: flex; flex-direction: column; gap: 0.25rem; }
.team__city { color: var(--ink-dim); font-size: var(--t-data); letter-spacing: 0.08em; }
.team__num { color: var(--ink-dim); white-space: nowrap; }
.team a:hover .team__num { color: var(--flash); }

/* ========================================================================== */
/* THE WORK ORDER — the enquiry form as a spec plate you fill in             */
/* Signature at ~60%: the boundary is the focus state. The row you are typing */
/* on lights its left edge, the way the beam lights the line it is on.        */
/* ========================================================================== */
.form { display: grid; gap: var(--s2); max-width: 40rem; }
.form__row { display: grid; gap: var(--s2); }
@media (min-width: 560px) { .form__row { grid-template-columns: 1fr 1fr; gap: var(--s3); } }

.field { display: grid; gap: 0.35rem; margin: 0; }
.field > label {
  font-family: var(--font-mono); font-size: var(--t-data); font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-dim);
  transition: color var(--aperture-dur) var(--ease-ui);
}
.field .req { color: var(--accent-text); margin-left: 0.35em; }

.field :is(input, textarea) {
  width: 100%; min-height: 48px;
  padding: 0.7rem 0.8rem;
  font-family: var(--font-body); font-size: 1rem; line-height: 1.5;
  color: var(--ink-hi); background: rgba(0, 0, 0, 0.22);
  border: 0;
  border-bottom: var(--hair) solid var(--edge-dim);
  border-left: 2px solid transparent;        /* the boundary, not yet lit */
  border-radius: 0;
  transition: border-color var(--aperture-dur) var(--ease-ui), background var(--aperture-dur) var(--ease-ui);
}
.field textarea { min-height: 8.25rem; resize: vertical; }
.field :is(input, textarea)::placeholder { color: #7a8390; }   /* 4.6:1 on --surface */

/* the beam arrives at this line. This IS the focus indicator — high contrast
   (#FDFBF4 on near-black), 3px down the full height plus the lit base rule —
   so the global aperture ring is suppressed here rather than doubling up. */
.field :is(input, textarea):focus,
.field :is(input, textarea):focus-visible {
  border-bottom-color: var(--flash);
  border-left-color: var(--flash);
  border-left-width: 3px;
  background: rgba(0, 0, 0, 0.34);
  outline: none;
}
.field:focus-within > label { color: var(--flash); }

.form__send { display: flex; align-items: center; gap: var(--s2) var(--s3); flex-wrap: wrap; margin-top: var(--s1); }
.form__note { color: var(--ink-dim); }
.form__status {
  margin-top: var(--s2); color: var(--flash); line-height: 1.6;
  border-left: 2px solid var(--flash); padding-left: var(--s2);
}
.form__status a { color: var(--flash); text-decoration: underline; text-underline-offset: 2px; }

/* the direct-contact column beside it */
.direct .col-label { margin-bottom: 0.75rem; }
.direct .team { margin-top: var(--s3); }

/* a quiet, in-context action — the boundary as an underline */
.act {
  display: inline-flex; align-items: center; gap: 0.5em;
  font-family: var(--font-mono); font-size: var(--t-data); font-weight: 500;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-hi);
  padding-bottom: 0.35rem; border-bottom: 2px solid var(--flash);
  min-height: 44px;
}
.act:hover, .act:focus-visible { border-bottom-color: var(--aperture); color: var(--flash); }
.section__act { margin-top: var(--s3); }

/* product plate — the unit shown whole on bright steel, never cropped, and
   sized as a centered object so a portrait unit doesn't tower over its copy */
.frame--product {
  aspect-ratio: auto; background: var(--steel);
  border-left-color: var(--graphite);
  display: grid; place-items: center; padding: var(--s4);
  max-height: 30rem;
}
/* the units are shot on white, which would melt into the bright steel plate —
   a soft shadow lifts the cabinet edge off the plate so it reads as an object */
.frame--product img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; filter: drop-shadow(0 6px 22px rgba(22, 25, 30, 0.28)); }
@media (max-width: 767px) { .frame--product { max-height: 24rem; } }

/* --- sections on phones: tighter rhythm, full-bleed media, sized headlines -- */
@media (max-width: 767px) {
  .section { padding-block: var(--s5); }
  .section__head { margin-bottom: var(--s3); }

  /* the display face is wide — size it so lines break where they should.
     A 13-letter word ("Contamination") is still wider than a 272px column at
     the clamp floor, so let it hyphenate rather than push the page sideways. */
  .section__title { font-size: clamp(1.55rem, 7.4vw, 2.4rem); -webkit-hyphens: auto; hyphens: auto; }
  .masthead__title { -webkit-hyphens: auto; hyphens: auto; }
  /* the hero holds whole words — never hyphenate it; the font is sized so the
     longest word ("PRESERVES" / "SUBSTRATE") fits a 320px line on its own */
  .hero__title { -webkit-hyphens: none; hyphens: none; }
  .hero__line { overflow-wrap: normal; word-break: keep-all; text-wrap: balance; }
  .lead { font-size: 1.02rem; }

  /* media goes edge-to-edge — a small floating card has no presence on a phone */
  .wipe, .frame {
    margin-inline: calc(-1 * var(--gutter));
    border-left: 0; border-top: 2px solid var(--flash);
  }
  .wipe { aspect-ratio: 4 / 3; }
  .frame { aspect-ratio: 3 / 4; }
  .frame--product { aspect-ratio: auto; }   /* the unit sets its own height */
  .split { gap: var(--s3); }
  /* image first, copy second — see the work before reading about it */
  .split--rev { display: flex; flex-direction: column; }
  .split--rev .frame { order: -1; }

  /* lists: less air per row so the page scans instead of scrolling forever */
  .rows li { padding: var(--s3) 0; }
  .rows__name { font-size: 1.3rem; }
  .rows__desc { font-size: 0.95rem; }
  .data-row li { padding: var(--s3) 0; }
  .data-row__v { font-size: 1.35rem; }
  .stack li { padding: 0.6rem 0; }
  .plate li { padding: 0.7rem var(--s2); }
  .cta { gap: var(--s4); }
  .team a { padding: var(--s2) 0; }
  /* one thumb, one column — and a full-width send */
  .form__send .btn { width: 100%; justify-content: center; }
  .form__note { max-width: none; }
}

/* ========================================================================== */
/* FOOTER — boundary at rest (15%)                                            */
/* ========================================================================== */
.foot { padding-block: var(--s4); border-top: var(--hair) solid var(--edge-dim); background: var(--graphite); }

/* The destination map. This lives in main.css, not page.css, because the footer
   is in the layout on EVERY page — including the legal pages, which do not load
   page.css and would otherwise render it unstyled. */
.foot__map {
  display: grid; gap: var(--s4);
  padding-bottom: var(--s4); margin-bottom: var(--s4);
  border-bottom: var(--hair) solid var(--edge-dim);
}
@media (min-width: 620px) { .foot__map { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s5); } }
.foot__head { color: var(--flash); margin-bottom: var(--s2); }
.foot__col ul { list-style: none; padding: 0; display: grid; gap: 0.6rem; }
.foot__col a { color: var(--ink-dim); font-size: 0.95rem; overflow-wrap: anywhere; }
.foot__col a:hover, .foot__col a:focus-visible { color: var(--ink-hi); }
.foot__where { color: var(--ink-dim); font-size: 0.95rem; }

/* you-are-here for real pages. The scroll-spy set aria-current="true"; the build
   sets aria-current="page" — match on the attribute so both light the edge. */
.nav__list a[aria-current] { color: var(--ink-hi); }
.nav__list a[aria-current]::after { transform: scaleX(1); }
.sheet__list a[aria-current] { color: var(--ink-hi); }
.sheet__list a[aria-current]::before { content: ""; display: inline-block; width: 18px; height: var(--hair); background: var(--accent); vertical-align: middle; margin-right: 0.6rem; }
.foot__in { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s4); }
.foot .brand { margin-right: 0; }
.foot .brand__logo { height: 46px; }
.foot__line { color: var(--ink-dim); }
.foot__tel { font-family: var(--font-mono); font-size: var(--t-data-lg); letter-spacing: 0.04em; color: var(--ink-hi); margin-left: auto; }
.foot__fine { color: var(--ink-dim); flex-basis: 100%; padding-top: var(--s2); border-top: var(--hair) solid var(--edge-dim); }
.foot__law { color: var(--ink-dim); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--edge-ui); }
.foot__law:hover, .foot__law:focus-visible { color: var(--ink-hi); text-decoration-color: var(--flash); }
.foot__law-sep { color: var(--edge-dim); }

/* --- motion sensitivity --------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}
