/* ============================================================
   VISTEX — Page compositions
   home · systems catalog · product · industries · about · contact
   ============================================================ */

/* ============================================================
   HOME — HERO
   ============================================================ */
.hero {
  position: relative; isolation: isolate; overflow: hidden;
  min-height: min(94svh, 940px);
  display: flex; align-items: center;
  /* the nav is fixed and transparent over this section, so the top padding has
     to clear it while the artwork still runs to the top of the viewport */
  padding-block: calc(var(--header-h) + clamp(40px, 9vh, 120px)) clamp(64px, 10vh, 120px);
  background:
    radial-gradient(120% 80% at 78% 8%, color-mix(in srgb, var(--aqua-100) 70%, transparent), transparent 60%),
    linear-gradient(168deg, var(--n-0) 0%, var(--n-50) 48%, var(--blue-50) 100%);
}
[data-theme="dark"] .hero {
  background:
    radial-gradient(120% 80% at 78% 8%, color-mix(in srgb, var(--blue-800) 70%, transparent), transparent 62%),
    linear-gradient(168deg, #050a18 0%, #070d1f 46%, #0a1330 100%);
}
/* The photograph reads as a photograph — no washed-out blend mode. Legibility
   is protected by an explicit scrim over the copy side instead of by hiding
   the image, so the picture stays present and the text stays readable. */
.hero-bg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: -2;
  opacity: 1;               /* full strength — it runs edge to edge, top included */
}
/* Dark theme still knocks it back so the deep-ink page background reads through */
[data-theme="dark"] .hero-bg { opacity: .5; }

.hero::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    /* anchored over the copy, NOT across the top — the photo reaches the very
       top edge of the viewport and the nav sits directly on the artwork */
    radial-gradient(ellipse 88% 78% at 10% 66%,
      color-mix(in srgb, var(--n-0) 30%, transparent) 0%,
      color-mix(in srgb, var(--n-0) 16%, transparent) 45%,
      transparent 72%),
    linear-gradient(180deg, transparent 62%, color-mix(in srgb, var(--bg) 88%, transparent) 100%);
}
[data-theme="dark"] .hero::before {
  background:
    radial-gradient(ellipse 88% 78% at 10% 66%,
      color-mix(in srgb, #050a18 34%, transparent) 0%,
      color-mix(in srgb, #050a18 18%, transparent) 45%,
      transparent 72%),
    linear-gradient(180deg, transparent 62%, color-mix(in srgb, var(--bg) 90%, transparent) 100%);
}
@media (max-width: 980px) {
  /* Stacked layout: protect the copy from below the nav downward, top stays clear */
  .hero::before {
    background: linear-gradient(180deg,
      transparent 0%,
      transparent calc(var(--header-h) - 8px),
      color-mix(in srgb, var(--n-0) 34%, transparent) calc(var(--header-h) + 90px),
      color-mix(in srgb, var(--n-0) 44%, transparent) 60%,
      color-mix(in srgb, var(--bg) 92%, transparent) 100%);
  }
  [data-theme="dark"] .hero::before {
    background: linear-gradient(180deg,
      transparent 0%,
      transparent calc(var(--header-h) - 8px),
      color-mix(in srgb, #050a18 38%, transparent) calc(var(--header-h) + 90px),
      color-mix(in srgb, #050a18 48%, transparent) 60%,
      color-mix(in srgb, var(--bg) 94%, transparent) 100%);
  }
}

/* Copy left, product stage right. */
.hero-grid {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: 0.92fr 1.08fr;
  gap: clamp(24px, 4vw, 56px); align-items: center;
}
@media (max-width: 980px) { .hero-grid { grid-template-columns: 1fr; gap: var(--s-8); } }

.hero-copy {
  display: grid; gap: var(--s-6); justify-items: start;
  max-width: min(58ch, 100%);
}
/* Measured against the un-scrimmed photo: --text-2 lands at 2.58:1 (fails),
   --text at 6.31:1. So the copy is darkened rather than the picture lightened. */
.hero-lede { color: var(--text); }
.hero-trust { color: var(--text); border-top-color: color-mix(in srgb, var(--text) 22%, transparent); }
.hero-trust strong { color: var(--text); }
/* The copy column is ~558px in the two-column hero; --step-7 tops out at
   101px there, which wrapped the headline to three lines 409px tall. */
.hero .h-hero {
  font-size: clamp(2.6rem, 4.6vw, 4.4rem);
  line-height: 1.0;
  max-width: 13ch;
}
.hero-lede { max-width: 46ch; }

/* Sector word rotator — mask + slide, no layout jump */
.hero-rotator {
  position: relative; display: inline-grid;
  vertical-align: baseline; overflow: hidden;
  padding-bottom: .1em; margin-bottom: -.1em;
}
.hero-rotator .w {
  grid-area: 1 / 1;
  transition: transform .42s var(--ease-out), opacity .2s linear, filter .2s linear;
}
.hero-rotator .w.out { transform: translateY(-88%); opacity: 0; filter: blur(6px); }
.hero-rotator .w.in  { transform: translateY(88%);  opacity: 0; filter: blur(6px); }

.hero-ctas { display: flex; flex-wrap: wrap; gap: var(--s-3); }

/* ============================================================
   HERO PRODUCT STAGE  —  perspective conveyor
   ============================================================ */
.hero-visual {
  position: relative;
  /* The query container must be the PARENT: an element cannot match a
     @container rule against itself. cqw units inside resolve against this. */
  container-type: inline-size;
  container-name: pstage;
}
@media (max-width: 980px) { .hero-visual { max-width: 620px; margin-inline: auto; width: 100%; } }

/* ---- Swift mark, hung over the conveyor ---------------------------------
   Centred on the belt's vanishing point, so the mark, the point everything
   converges on and the spotlight product all sit on one vertical axis — the
   mark reads as signage over the line rather than a sticker in a corner.
   The spotlight product tops out around 30% down the stage, so this band is
   clear at every width (measured, not assumed).
   Centring is done with auto margins, NOT translateX(-50%): the span carries
   data-anim="scale", and the reveal system ends on `[data-anim].is-in {
   transform: none }`, which outspecifies this rule and wiped a centring
   transform out — the mark slid right by half its width the moment the reveal
   finished. Auto margins are immune to that, which leaves the span's transform
   free for the reveal and the <img>'s free for the float. */
.hero-swift {
  position: absolute;
  top: -4%; left: 0; right: 0;
  margin-inline: auto;
  z-index: 4;
  width: clamp(110px, 22cqw, 190px);
  pointer-events: none;
  opacity: 0;
  animation: swift-in .9s var(--ease-out) .55s forwards;
}
.hero-swift img {
  width: 100%; height: auto; display: block;
  /* NO drop-shadow, deliberately. On this element the filter painted a visible
     grey rectangle the size of the image box — the badge appeared to sit on a
     plate. Proven by A/B with every animation frozen: `filter: none` removes
     the rectangle and nothing else changes. The element is promoted (opacity +
     a running animation) inside a `container-type: inline-size` ancestor, and
     the filter region ends up rendered from the layer bounds rather than the
     alpha. The badge carries its own metallic rim and internal shading, so it
     reads as dimensional without one. */
  animation: swift-float 7.5s var(--ease-in-out) infinite;
}
/* The artwork is fully saturated brand blue against an already-blue hero, which
   is what made the badge shout. Backing it off lets the photograph read through
   the mark instead of the mark punching a hole in the photograph. */
.hero-swift { opacity: 0; }
@keyframes swift-in { to { opacity: .84; } }

@keyframes swift-float {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(-1.5deg); }
  50%      { transform: translate3d(0, -9px, 0) rotate(1.5deg); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-swift { opacity: .84; animation: none; }
  .hero-swift img { animation: none; }
}
/* Stacked hero: the stage is centred and the belt sits lower, so the mark
   drops onto the stage itself rather than hanging above it. */
@media (max-width: 980px) { .hero-swift { top: -1%; width: clamp(96px, 26cqw, 150px); } }
/* The mark stays centred on every width. On a phone the room for it comes
   from a taller stage (see responsive.css) rather than from a smaller
   product — the belt scales with stage WIDTH, so extra height is free. */
@media (max-width: 620px) { .hero-swift { top: 1%; width: clamp(88px, 27cqw, 132px); } }

.pstage {
  position: relative;
  /* width MUST be definite. With width:auto, `aspect-ratio` + `min-height`
     resolve the other way round — a 350px column produced a 500px-wide stage
     that overflowed and clipped the products on mobile. */
  width: 100%;
  max-width: 100%;
  aspect-ratio: 5 / 3.2;
  min-height: 300px;

  /* ---- Conveyor geometry -------------------------------------------------
     The belt is a horizontal circle drawn in true one-point perspective, and
     these five numbers ARE the camera. js/home.js reads them, so a container
     query can re-aim the shot at any width without touching the script.

       --cv-cam    camera distance from the circle centre, in radii. Must stay
                   > 1 or the belt would pass through the lens. Lower = wider
                   angle = more dramatic depth.
       --cv-span   horizontal reach. Peak excursion is span x 0.785, so 48
                   sends the widest product to 37.7% either side of centre.
       --cv-floor  the near baseline: where a product stands in the spotlight.
       --cv-rise   how far the belt climbs as it recedes. floor + rise is the
                   vanishing point, so 12 + 30 puts it 42% up the stage.
       --cv-scale  scale of the product in the spotlight.
       --cv-fade   opacity falloff exponent with depth.
     One product width for all of them: the cut-outs share one frame, so a
     single width already reproduces true relative scale. */
  --cv-pw:    20%;
  --cv-cam:   1.62;
  --cv-span:  48;
  --cv-floor: 12;
  --cv-rise:  30;
  --cv-scale: 1.75;
  --cv-fade:  1.2;
}
/* Container queries, not viewport: the stage sizes off its own column.
   As the belt narrows, products must grow (or they become unreadable, which
   is the failure this stage has had before) and the belt must pull its reach
   in, or the widest product overhangs the edge. */
@container pstage (max-width: 560px) {
  .pstage { --cv-pw: 24%; --cv-span: 43; --cv-scale: 1.68; --cv-rise: 27; --cv-floor: 11; }
}
@container pstage (max-width: 420px) {
  .pstage { --cv-pw: 28%; --cv-span: 37; --cv-scale: 1.66; --cv-rise: 24; --cv-floor: 10; --cv-cam: 1.72; }
}
/* the phone stage is sized in responsive.css, which loads after this file */

/* ---- the belt ----------------------------------------------------------
   The perspective image of a circle is an ellipse, and because both axes of
   the projection are linear in 1/Z that ellipse is exactly this box: it spans
   --cv-floor to --cv-floor + --cv-rise vertically, and span x 0.785 either
   side horizontally. So a plain CSS ellipse lands on the product baselines
   with no JS and no SVG. The mask fades the far rim into the haze. */
.pstage-floor {
  position: absolute;
  left: 50%; bottom: calc(var(--cv-floor) * 1%);
  width: calc(var(--cv-span) * 1.57%);
  height: calc(var(--cv-rise) * 1%);
  transform: translateX(-50%);
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--blue-600) 30%, transparent);
  box-shadow: 0 0 34px -6px color-mix(in srgb, var(--aqua-400) 22%, transparent) inset;
  -webkit-mask-image: linear-gradient(to top, #000 22%, color-mix(in srgb, #000 45%, transparent) 62%, transparent 94%);
  mask-image: linear-gradient(to top, #000 22%, color-mix(in srgb, #000 45%, transparent) 62%, transparent 94%);
  opacity: 0; transition: opacity .9s var(--ease-out);
}
[data-theme="dark"] .pstage-floor { border-color: color-mix(in srgb, var(--aqua-400) 26%, transparent); }
.pstage.lined .pstage-floor { opacity: 1; }

/* the light pool under the spotlight — fixed at front centre, where the
   nearest point of the belt always is */
.pstage-pool {
  position: absolute; left: 50%; bottom: calc(var(--cv-floor) * 1% - 22px);
  width: 40%; height: 54px; transform: translateX(-50%) scaleX(.7);
  border-radius: 50%;
  background: radial-gradient(ellipse at center,
    color-mix(in srgb, var(--aqua-400) 44%, transparent), transparent 70%);
  filter: blur(13px); opacity: 0;
  transition: opacity .7s var(--ease-out), transform .7s var(--ease-out);
}
.pstage.featuring .pstage-pool { opacity: .85; transform: translateX(-50%) scaleX(1); }

/* The hero photograph is a high-contrast water swirl. Without this the
   products fight it for attention; a soft halo lifts them off the background
   without putting a visible panel on top of the image. */
.pstage::before {
  content: ""; position: absolute; inset: -6% -4% -10% -4%;
  background: radial-gradient(ellipse 62% 58% at 50% 62%,
    color-mix(in srgb, var(--bg) 62%, transparent) 0%,
    color-mix(in srgb, var(--bg) 30%, transparent) 45%,
    transparent 72%);
  pointer-events: none;
}

.pstage-items { position: absolute; inset: 0; }

/* Every product is the same box in the same place. Position on the belt is
   ENTIRELY transform, so the rAF loop never touches layout. */
.pitem {
  position: absolute;
  left: 50%; bottom: 0;
  width: var(--cv-pw);
  margin-left: calc(var(--cv-pw) * -0.5);
  transform-origin: 50% 100%;
  will-change: transform, opacity;
}
.pitem img {
  width: 100%; height: auto; display: block;
  filter: drop-shadow(0 16px 20px rgba(20, 32, 72, .26));
}
.pitem.is-hero img {
  filter: drop-shadow(0 26px 30px rgba(20, 32, 72, .42)) drop-shadow(0 6px 10px rgba(20, 32, 72, .25));
}
/* Depth of field in three fixed steps. Animating a blur radius on 16 elements
   every frame is the one thing that reliably drops frames here, so the script
   only ever swaps a class. */
.pitem.dof0 { filter: none; }
.pitem.dof1 { filter: blur(.7px); }
.pitem.dof2 { filter: blur(1.7px); }
/* A phone is doing this on a smaller, busier GPU budget for less visual
   payoff — the far products are already tiny and faint. */
@container pstage (max-width: 560px) {
  .pitem.dof1, .pitem.dof2 { filter: none; }
}
/* Reduced motion steps the belt instead of turning it, so the jumps need to
   be transitions rather than frames. */
.pstage.stepped .pitem { transition: transform .8s var(--ease-out), opacity .5s linear; }

/* Caption + dots: a flow block under the stage. Absolutely positioning this
   over the stage meant the hero-lift product covered its own name at every
   viewport (measured 4-19px of overlap). In flow it cannot happen. */
.pstage-meta {
  display: grid; justify-items: center; gap: var(--s-3);
  margin-top: var(--s-4);
  min-height: 62px;                 /* reserved, so nothing jumps on swap */
}
.pstage-cap {
  text-align: center; opacity: 0;
  transition: opacity .4s var(--ease-out);
}
.pstage.featuring ~ .pstage-meta .pstage-cap,
.pstage-meta .pstage-cap.on { opacity: 1; }
.pstage-cap b {
  display: block; font-family: var(--font-display); font-weight: 600;
  font-size: var(--step-1); letter-spacing: var(--tr-tight); color: var(--text);
}
.pstage-cap span {
  display: inline-block; margin-top: 3px;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--text-3);
}
.pstage-cap:hover b { color: var(--accent); }

/* 16 products now, not 10 — the row must be allowed to wrap on a phone
   rather than force the meta block wider than the stage. */
.pstage-dots { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px;
  max-width: 100%; opacity: 0; transition: opacity .4s var(--ease-out); }
.pstage.featuring ~ .pstage-meta .pstage-dots { opacity: 1; }
.pstage-dots i {
  width: 5px; height: 5px; border-radius: var(--r-full); display: block;
  background: color-mix(in srgb, var(--text) 22%, transparent);
  transition: all var(--t-mid);
}
.pstage-dots i.on { background: var(--accent); width: 18px; }

.hero-trust {
  display: flex; align-items: center; gap: var(--s-4);
  padding-top: var(--s-5); border-top: 1px solid var(--border);
  width: 100%; max-width: 44ch;
  font-size: var(--step--1); color: var(--text-3);
}
.hero-trust strong { color: var(--text); font-weight: 600; }
.drop-mark {
  flex: none; width: 24px; height: 24px; border-radius: 50% 50% 50% 4px;
  transform: rotate(-45deg);
  background: linear-gradient(140deg, var(--aqua-400), var(--blue-600));
  box-shadow: 0 6px 18px -8px var(--aqua-500);
}

.scroll-cue-wrap {
  position: absolute; left: 50%; bottom: 26px; transform: translateX(-50%); z-index: 3;
}
@media (max-height: 720px) { .scroll-cue-wrap { display: none; } }

/* ============================================================
   PHOTO BAND — the product shot IS the background
   A product photo used full-bleed will fight the copy, so it is anchored to
   the free side, scaled up, softly blurred and desaturated into the brand
   palette, then covered by a directional scrim. It reads as atmosphere, and
   the bucket still resolves on the right where nothing overlaps it.
   ============================================================ */
.band-photo {
  position: relative; isolation: isolate; overflow: hidden;
  background: linear-gradient(160deg, var(--bg) 0%, var(--bg-sunk) 60%, var(--blue-50) 100%);
}
[data-theme="dark"] .band-photo {
  background: linear-gradient(160deg, var(--bg) 0%, #080d1e 60%, #0b1330 100%);
}
.band-photo-bg {
  position: absolute; z-index: -2;
  /* This is the product poster, so it must read clearly — the mask only
     dissolves the outer rectangle edge, it does not veil the artwork. */
  -webkit-mask-image: radial-gradient(ellipse 86% 88% at 55% 50%, #000 62%, rgba(0,0,0,.85) 78%, transparent 97%);
  mask-image: radial-gradient(ellipse 86% 88% at 55% 50%, #000 62%, rgba(0,0,0,.85) 78%, transparent 97%);
  /* Centred with auto margins, NOT translateY(-50%): this element also carries
     data-parallax, and motion.js writes to `transform` — a transform used for
     layout here would be overwritten and the image would drop out of frame. */
  right: -4%; top: 0; bottom: 0; margin-block: auto;
  /* capped at the native 1280px source so it is never upscaled, even at 2x */
  width: min(58%, 640px); height: auto; aspect-ratio: 1 / 1;
  object-fit: contain;
  filter: saturate(1.04) contrast(1.05);
}
/* tint it into the palette + fade its edges so it has no hard boundary */
.band-photo::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(95deg,
      var(--bg) 0%,
      color-mix(in srgb, var(--bg) 94%, transparent) 30%,
      color-mix(in srgb, var(--bg) 40%, transparent) 48%,
      transparent 62%),
    radial-gradient(90% 70% at 78% 50%,
      color-mix(in srgb, var(--aqua-200) 34%, transparent), transparent 68%);
}
[data-theme="dark"] .band-photo::before {
  background:
    linear-gradient(95deg,
      var(--bg) 0%,
      color-mix(in srgb, var(--bg) 92%, transparent) 38%,
      color-mix(in srgb, var(--bg) 58%, transparent) 58%,
      transparent 78%),
    radial-gradient(90% 70% at 78% 50%,
      color-mix(in srgb, var(--blue-700) 46%, transparent), transparent 68%);
}
.band-photo-inner { position: relative; z-index: 1; }
.band-photo-inner .split-copy { max-width: 52ch; }
/* Brand statement — the Swift badge plus the sentence that ties it to Vistex.
   Replaced a type-only lockup now that the real brand asset exists. */
.brand-statement {
  margin-top: var(--s-9);
  display: flex; align-items: center; gap: clamp(16px, 2.4vw, 28px);
  flex-wrap: wrap;
  padding-top: var(--s-7);
  border-top: 1px solid var(--border);
}
.brand-statement .swift-badge {
  filter: drop-shadow(0 10px 24px rgba(20,32,72,.28));
}
.brand-statement__note {
  flex: 1 1 22ch; min-width: 0;
  font-size: var(--step--1); line-height: 1.65; color: var(--text-3);
  max-width: 40ch;
}
.brand-statement__note strong { color: var(--text); font-weight: 600; }

@media (max-width: 900px) {
  /* Stacked: the poster comes OUT of the background and sits in flow beneath
     the copy. Behind the text it made both the words and the artwork hard to
     read; as its own block it is fully legible and the copy is clean. */
  .band-photo { display: flex; flex-direction: column; }
  .band-photo > picture { order: 2; display: block; }
  .band-photo-inner { order: 1; }
  .band-photo::before { display: none; }

  .band-photo-bg {
    position: static; transform: none;
    width: calc(100% - var(--gutter) * 2);
    max-width: 520px;
    margin: var(--s-8) auto 0;
    aspect-ratio: auto;
    border-radius: var(--r-xl);
    -webkit-mask-image: none; mask-image: none;
    box-shadow: var(--shadow-2);
  }
  .band-photo-inner .split-copy { max-width: 100%; }
  .brand-statement { margin-top: var(--s-7); }
}

/* ============================================================
   HOME — PROOF STRIP
   ============================================================ */
.proof-strip {
  display: grid; grid-template-columns: repeat(4, 1fr);
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--surface); overflow: hidden;
}
.proof-strip > div {
  padding: var(--s-6) var(--s-5); text-align: center;
  border-right: 1px solid var(--border-2);
}
.proof-strip > div:last-child { border-right: 0; }
.proof-strip .n {
  font-family: var(--font-display); font-size: var(--step-3);
  font-weight: 600; letter-spacing: var(--tr-display); line-height: 1;
}
.proof-strip .l {
  margin-top: 8px; font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--text-3);
}
@media (max-width: 760px) {
  .proof-strip { grid-template-columns: 1fr 1fr; }
  .proof-strip > div:nth-child(2n) { border-right: 0; }
  .proof-strip > div:nth-child(-n+2) { border-bottom: 1px solid var(--border-2); }
}

/* ============================================================
   RIPPLE BAND — "End-to-end hygiene"
   The upload was warm orange; it is shipped duotoned into the brand ramp so
   the water texture survives but the colour belongs here. The band flips to
   ink so the light type and the photo cards read as one dark composition.
   ============================================================ */
.section--ripple {
  position: relative; isolation: isolate; overflow: hidden;
  background: linear-gradient(165deg, var(--blue-900), var(--blue-950) 60%, #070b1c);
  color: #fff;
  --text: #fff;
  --text-2: rgba(255,255,255,.78);
  --text-3: rgba(255,255,255,.6);
  --text-4: rgba(255,255,255,.44);
  --border: rgba(255,255,255,.14);
  --accent: var(--aqua-300);
}
.ripple-bg {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
  opacity: .5;
}
/* keep the middle calm so the headline and cards sit on quiet ground */
.section--ripple::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(120% 80% at 50% 40%,
      color-mix(in srgb, var(--blue-950) 78%, transparent) 0%,
      color-mix(in srgb, var(--blue-950) 46%, transparent) 45%,
      transparent 80%),
    linear-gradient(180deg, var(--blue-950) 0%, transparent 22%, transparent 78%, var(--blue-950) 100%);
}
/* the section it butts against should melt into the band, not hard-edge */
.section--ripple + .section, .section--ripple { --seam: 0; }

/* ============================================================
   HOME — SYSTEMS SHOWCASE
   ============================================================ */
.sys-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--s-5); }
/* 5 cards: 2 wide on the first row, 3 on the second */
.sys-card:nth-child(1), .sys-card:nth-child(2) { grid-column: span 3; }
.sys-card:nth-child(3), .sys-card:nth-child(4), .sys-card:nth-child(5) { grid-column: span 2; }
@media (max-width: 900px) {
  .sys-grid { grid-template-columns: repeat(2, 1fr); }
  .sys-card { grid-column: span 1 !important; }
}
@media (max-width: 600px) { .sys-grid { grid-template-columns: 1fr; } }

.sys-card {
  position: relative; isolation: isolate; overflow: hidden;
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: 340px; padding: var(--s-6);
  border-radius: var(--r-xl); border: 1px solid var(--border);
  color: #fff; box-shadow: var(--shadow-1);
  transition: transform var(--t-mid), box-shadow var(--t-mid);
}
.sys-card:nth-child(1), .sys-card:nth-child(2) { min-height: 400px; }
.sys-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-3); }
.sys-card-img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.3s var(--ease-out);
}
.sys-card:hover .sys-card-img { transform: scale(1.07); }
.sys-card::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(180deg, transparent 8%, color-mix(in srgb, var(--blue-950) 30%, transparent) 44%, color-mix(in srgb, var(--blue-950) 90%, transparent) 100%);
  transition: opacity var(--t-mid);
}
.sys-card-top {
  position: absolute; top: var(--s-6); left: var(--s-6); right: var(--s-6);
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
}
.sys-emblem {
  width: 46px; height: 46px; display: grid; place-items: center;
  border-radius: var(--r-md);
  background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.26);
  backdrop-filter: blur(10px); color: #fff;
}
.sys-count {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-label); color: rgba(255,255,255,.82);
  padding: 6px 11px; border-radius: var(--r-full);
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.2);
  backdrop-filter: blur(10px);
}
.sys-card h3 { font-size: var(--step-2); color: #fff; }
.sys-card p {
  margin-top: 9px; font-size: var(--step--1); line-height: 1.6;
  color: rgba(255,255,255,.8); max-width: 42ch;
}
.sys-more {
  margin-top: var(--s-5); display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--aqua-200);
}
.sys-more svg { width: 15px; height: 15px; transition: transform var(--t-mid); }
.sys-card:hover .sys-more svg { transform: translateX(5px); }

/* Scroll-focus: on touch there is no hover, so the card nearest the middle of
   the viewport takes the lifted state as you scroll. Same language as hover,
   driven by position instead of a pointer. */
@media (hover: none), (max-width: 900px) {
  .sys-card { transition: transform .55s var(--ease-out), box-shadow .55s var(--ease-out); }
  .sys-card.in-focus { transform: translateY(-6px) scale(1.018); box-shadow: var(--shadow-3); }
  .sys-card.in-focus .sys-card-img { transform: scale(1.06); }
  .sys-card.in-focus::after { opacity: .92; }
  .sys-card.in-focus .sys-more svg { transform: translateX(5px); }
}

/* Water line at the base of each card */
.sys-wave { position: absolute; left: 0; right: 0; bottom: -1px; z-index: -1; opacity: .5; color: var(--aqua-400); }
.sys-wave svg { width: 200%; height: 46px; animation: wave-drift 11s linear infinite; }
@keyframes wave-drift { to { transform: translateX(-50%); } }

/* ============================================================
   HOME — PROCESS SCROLLYTELLING
   ============================================================ */
.process { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: clamp(32px, 6vw, 88px); align-items: start; }
@media (max-width: 900px) { .process { grid-template-columns: 1fr; } }

/* A photo stage rather than an abstract diagram — the image cross-fades to the
   step you are reading, with the numeral and label sitting over it. */
.process-visual {
  position: sticky; top: calc(var(--header-h) + 6vh);
  aspect-ratio: 4/5; border-radius: var(--r-2xl); overflow: hidden;
  border: 1px solid var(--border); box-shadow: var(--shadow-3);
  background: linear-gradient(160deg, var(--blue-700), var(--blue-950));
  display: grid; place-items: center; isolation: isolate;
}
@media (max-width: 900px) {
  .process-visual { position: relative; top: 0; aspect-ratio: 16/10; margin-bottom: var(--s-8); }
}

.pv-shot {
  position: absolute; inset: 0; z-index: 0;
  opacity: 0; transform: scale(1.08);
  transition: opacity .7s var(--ease-out), transform 1.6s var(--ease-out);
}
.pv-shot.active { opacity: 1; transform: scale(1); }
.pv-shot img { width: 100%; height: 100%; object-fit: cover; }

.process-visual::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--blue-950) 42%, transparent) 0%,
    color-mix(in srgb, var(--blue-950) 26%, transparent) 40%,
    color-mix(in srgb, var(--blue-950) 88%, transparent) 100%);
}

.process-visual .pv-num {
  position: relative; z-index: 2;
  font-family: var(--font-display);
  font-size: clamp(4.5rem, 13vw, 9rem); font-weight: 600; color: #fff;
  letter-spacing: -0.06em; line-height: 1;
  text-shadow: 0 12px 40px rgba(0,0,0,.45);
  transition: opacity .3s var(--ease-out), transform .45s var(--ease-out);
}
.process-visual .pv-label {
  position: absolute; z-index: 2; bottom: 10%; left: 0; right: 0; text-align: center;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--aqua-200);
}
/* progress pips down the side of the stage */
.pv-pips {
  position: absolute; z-index: 2; right: 18px; top: 50%;
  transform: translateY(-50%); display: grid; gap: 8px;
}
.pv-pips span {
  width: 6px; height: 6px; border-radius: var(--r-full);
  background: rgba(255,255,255,.32); transition: all var(--t-mid);
}
.pv-pips span.on { background: var(--aqua-300); height: 22px; }

.process-steps { display: grid; gap: var(--s-4); }
.pstep {
  position: relative; padding: var(--s-6) var(--s-6) var(--s-6) var(--s-8);
  border-radius: var(--r-lg); border: 1px solid var(--border);
  background: var(--surface);
  transition: border-color var(--t-mid), background var(--t-mid), transform var(--t-mid), box-shadow var(--t-mid);
}
.pstep::before {
  content: ""; position: absolute; left: 0; top: 18px; bottom: 18px; width: 3px;
  border-radius: var(--r-full); background: var(--border);
  transition: background var(--t-mid);
}
.pstep.active {
  border-color: var(--border-lit); box-shadow: var(--shadow-2);
  transform: translateX(4px);
}
.pstep.active::before { background: linear-gradient(var(--aqua-400), var(--blue-600)); }
.pstep .pn {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-label); color: var(--text-4);
}
.pstep.active .pn { color: var(--accent); }
.pstep h4 { margin-top: 6px; font-size: var(--step-1); }
.pstep p { margin-top: 8px; color: var(--text-3); font-size: var(--step--1); line-height: 1.65; }

/* ============================================================
   HOME — STATS BAND
   ============================================================ */
.film-band {
  position: relative; isolation: isolate; overflow: hidden;
  background: linear-gradient(150deg, var(--blue-700) 0%, var(--blue-900) 55%, var(--blue-950) 100%);
  color: #fff;
}
/* The film band replaced the metrics band: same treatment, but it now carries
   the pull quote, so the type has to read as light-on-film. */
.film-band { color: #fff; --text: #fff; --text-2: rgba(255,255,255,.8); --text-3: rgba(255,255,255,.62); }
.film-band .pullquote q { color: #fff; }
.film-band .pullquote .qby { color: rgba(255,255,255,.66); }
.film-band .pullquote .qmark { color: var(--aqua-300); opacity: .34; }

.film-band .band-bg,
.film-band .band-video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: -2;
  opacity: 0; transition: opacity .9s var(--ease-out);
}
.film-band .band-video { opacity: .42; }
.film-band.video-live .band-video { opacity: .62; }
/* keep the numbers legible over moving footage */
.film-band::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(90% 70% at 50% 50%, color-mix(in srgb, var(--blue-950) 52%, transparent), transparent 78%),
    linear-gradient(180deg, color-mix(in srgb, var(--blue-950) 62%, transparent), transparent 30%,
                    transparent 70%, color-mix(in srgb, var(--blue-950) 62%, transparent));
}
.stats {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s-6);
}
@media (max-width: 820px) { .stats { grid-template-columns: 1fr 1fr; gap: var(--s-8); } }
.stat { text-align: center; }
.stat .n {
  font-family: var(--font-display); font-size: var(--step-6);
  font-weight: 600; letter-spacing: var(--tr-display); line-height: 1;
  background: linear-gradient(180deg, #fff 30%, var(--aqua-200));
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
}
.stat .l {
  margin-top: var(--s-3); font-family: var(--font-mono);
  font-size: var(--step--2); letter-spacing: var(--tr-label);
  text-transform: uppercase; color: rgba(255,255,255,.66);
}

/* ============================================================
   HOME — BENTO DIFFERENTIATORS
   ============================================================ */
.bento { display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--s-5); }
.bento > * { grid-column: span 2; }
.bento > *:nth-child(1) { grid-column: span 3; }
.bento > *:nth-child(2) { grid-column: span 3; }
@media (max-width: 900px) { .bento { grid-template-columns: repeat(2, 1fr); } .bento > * { grid-column: span 1 !important; } }
@media (max-width: 560px) { .bento { grid-template-columns: 1fr; } }

.diff-card {
  padding: var(--s-6); display: grid; gap: var(--s-3); align-content: start;
  border-radius: var(--r-lg);
}
.diff-card .ico {
  width: 48px; height: 48px; display: grid; place-items: center;
  border-radius: var(--r-md);
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--border-lit);
  transition: transform var(--t-mid), background var(--t-mid);
}
.diff-card:hover .ico { transform: translateY(-3px) rotate(-4deg); }
.diff-card h3 { font-size: var(--step-1); }
.diff-card p { color: var(--text-3); font-size: var(--step--1); line-height: 1.65; }

/* ============================================================
   PROBLEM → SOLUTION LEDGER
   ============================================================ */
.ledger-layout {
  display: grid; grid-template-columns: 0.82fr 1.18fr;
  gap: clamp(32px, 6vw, 80px); align-items: start;
}
@media (max-width: 900px) {
  .ledger-layout { grid-template-columns: 1fr; gap: var(--s-8); }
  .ledger-aside .photo { display: none; }   /* the list is the point on a phone */
}
.ledger { border-top: 1px solid var(--border); }

/* Each row is a little ledger entry: a mono index, the complaint set quietly,
   an aqua arrow, then the answer in the display face and brand blue. A blue
   rail grows down the left edge on hover to tie the palette through. */
.ledger-row {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto minmax(0, 1.1fr);
  gap: var(--s-5);
  align-items: center;
  padding: var(--s-6) var(--s-5) var(--s-6) var(--s-6);
  border-bottom: 1px solid var(--border-2);
  transition: background var(--t-mid);
}
.ledger-row::before {
  content: ""; position: absolute; left: 0; top: 50%; bottom: 50%; width: 3px;
  border-radius: var(--r-full);
  background: linear-gradient(var(--aqua-400), var(--blue-600));
  transition: top var(--t-mid), bottom var(--t-mid);
}
.ledger-row:hover { background: var(--accent-soft); }
.ledger-row:hover::before { top: 14px; bottom: 14px; }

.ledger-n {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-mono);
  color: var(--blue-300);
  padding-top: 2px;
}
[data-theme="dark"] .ledger-n { color: var(--aqua-700); }
.ledger-row:hover .ledger-n { color: var(--accent); }

.ledger-tag {
  display: block; margin-bottom: 6px;
  font-family: var(--font-mono); font-size: 10px; font-weight: 500;
  letter-spacing: var(--tr-label); text-transform: uppercase;
}
/* Both tags measured under AA on the tinted band (3.52 and 3.69). These clear
   it at 5.08 and 5.55 while keeping the muted/accent relationship intact. */
.ledger-p .ledger-tag { color: var(--text-3); }
.ledger-s .ledger-tag { color: var(--aqua-700); }
[data-theme="dark"] .ledger-p .ledger-tag { color: var(--text-3); }
[data-theme="dark"] .ledger-s .ledger-tag { color: var(--aqua-400); }

.ledger-p {
  font-size: var(--step-0); color: var(--text-3);
  font-weight: 400;
}
.ledger-s {
  font-family: var(--font-display);
  font-size: var(--step-1); font-weight: 600;
  letter-spacing: var(--tr-tight);
  color: var(--blue-700);
}
[data-theme="dark"] .ledger-s { color: var(--aqua-200); }

.ledger-arrow {
  flex: none; width: 34px; height: 34px;
  display: grid; place-items: center; border-radius: var(--r-full);
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--border-lit);
  transition: transform var(--t-mid), background var(--t-mid);
}
.ledger-row:hover .ledger-arrow {
  transform: translateX(4px);
  background: var(--accent); color: var(--on-accent); border-color: transparent;
}
.ledger-arrow svg { width: 17px; height: 17px; }

@media (max-width: 780px) {
  .ledger-row {
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--s-3) var(--s-4);
    padding: var(--s-5) var(--s-3) var(--s-5) var(--s-5);
  }
  .ledger-n { grid-row: 1 / span 3; align-self: start; }
  .ledger-arrow { transform: rotate(90deg); justify-self: start; width: 28px; height: 28px; }
  .ledger-row:hover .ledger-arrow { transform: rotate(90deg) translateX(3px); }
  .ledger-s { font-size: var(--step-0); }
}

/* ============================================================
   PULL QUOTE
   ============================================================ */
.pullquote { position: relative; text-align: center; max-width: 30ch; margin-inline: auto; }
.pullquote q {
  display: block; quotes: none;
  font-family: var(--font-quote); font-weight: 300;
  font-size: var(--step-4); line-height: 1.2; letter-spacing: -0.03em;
  color: var(--text);
}
.pullquote .qby {
  margin-top: var(--s-6); font-family: var(--font-mono);
  font-size: var(--step--2); letter-spacing: var(--tr-label);
  text-transform: uppercase; color: var(--text-3);
}
.pullquote .qmark {
  font-family: var(--font-quote); font-weight: 500;
  font-size: 7rem; line-height: .62;
  color: var(--water); opacity: .2; margin-bottom: -.08em;
}

/* ============================================================
   CLIENTS
   ============================================================ */
.client-row { display: flex; flex-wrap: wrap; gap: var(--s-3); justify-content: center; }

/* Four-up sector strip — the sectors named above, shown */
.photo-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s-4); }
.photo-strip .photo { box-shadow: var(--shadow-2); }
.photo-strip .photo:nth-child(even) { transform: translateY(clamp(14px, 2.6vw, 34px)); }
@media (max-width: 780px) {
  .photo-strip { grid-template-columns: repeat(2, 1fr); gap: var(--s-3); }
}
@media (max-width: 420px) {
  .photo-strip .photo:nth-child(even) { transform: none; }
}

/* ============================================================
   CTA BAND
   ============================================================ */
.cta-band {
  position: relative; isolation: isolate; overflow: hidden;
  border-radius: var(--r-2xl); text-align: center; color: #fff;
  padding: clamp(44px, 8vw, 92px) clamp(24px, 5vw, 64px);
  background: linear-gradient(150deg, var(--blue-600), var(--blue-900));
  box-shadow: var(--shadow-3);
}
.cta-band .band-bg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: -2; opacity: .2; mix-blend-mode: luminosity;
}
.cta-band h2 { font-size: var(--step-5); color: #fff; letter-spacing: var(--tr-display); }
.cta-band p { margin: var(--s-4) auto 0; color: rgba(255,255,255,.8); max-width: 50ch; }
.cta-band .hero-ctas { justify-content: center; margin-top: var(--s-7); }

/* ============================================================
   EDITORIAL PHOTO FRAME
   ============================================================ */
.photo {
  position: relative; overflow: hidden;
  border-radius: var(--r-xl); border: 1px solid var(--border);
  box-shadow: var(--shadow-2); background: var(--surface-3);
  aspect-ratio: var(--ar, 4/3);
}
.photo img { width: 100%; height: 100%; object-fit: cover; }
.photo--parallax img { height: 118%; margin-top: -9%; }
.photo-caption {
  position: absolute; left: var(--s-4); bottom: var(--s-4);
  padding: 8px 14px; border-radius: var(--r-full);
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  backdrop-filter: blur(12px); border: 1px solid var(--border);
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-mono); color: var(--text-2);
}

/* ============================================================
   CATALOG (systems.html)
   ============================================================ */
.cat-toolbar {
  position: sticky; top: var(--header-h); z-index: 20;
  padding-block: var(--s-4);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--s-8);
}
.cat-toolbar-inner { display: grid; grid-template-columns: minmax(200px, 340px) 1fr; gap: var(--s-4); align-items: center; }
@media (max-width: 820px) { .cat-toolbar-inner { grid-template-columns: 1fr; } }
.cat-filters { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.cat-meta {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--text-3);
}

.syscat { position: relative; margin-bottom: var(--s-11); scroll-margin-top: calc(var(--header-h) + 90px); }
.syscat-head {
  position: relative; isolation: isolate; overflow: hidden;
  border-radius: var(--r-xl); padding: clamp(26px, 4vw, 42px);
  color: #fff; margin-bottom: var(--s-6);
  border: 1px solid var(--border);
  /* solid ground beneath the photo: the white type keeps its contrast even if
     the image never loads */
  background-color: var(--blue-900);
}
.syscat-bg {
  position: absolute; inset: 0; z-index: -2;
  background-size: cover; background-position: center;
  transform: scale(1.04);
}
.syscat-head::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(120deg, color-mix(in srgb, var(--blue-950) 88%, transparent), color-mix(in srgb, var(--blue-800) 55%, transparent));
}
.syscat-head-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-4); }
.syscat-title { display: flex; align-items: center; gap: var(--s-4); font-size: var(--step-3); color: #fff; }
.syscat-title .sys-emblem { flex: none; }
.syscat-tag { margin-top: var(--s-3); color: rgba(255,255,255,.78); font-size: var(--step--1); max-width: 56ch; }
.syscat-benefits { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-5); }

.cat-empty {
  text-align: center; padding: var(--s-11) var(--s-5);
  border: 1px dashed var(--border); border-radius: var(--r-lg); color: var(--text-3);
}
.cat-empty svg { width: 44px; height: 44px; margin: 0 auto var(--s-4); color: var(--text-4); }

/* ============================================================
   PRODUCT DETAIL
   ============================================================ */
.crumbs {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-mono); color: var(--text-3);
}
/* mono micro-type is 18px tall on its own — pad to a real pointer target */
.crumbs a { display: inline-flex; align-items: center; min-height: 24px; }
.crumbs a:hover { color: var(--accent); }
.crumbs .sep { opacity: .5; }

.pd-grid { display: grid; grid-template-columns: 0.95fr 1.05fr; gap: clamp(32px, 5vw, 72px); align-items: start; }
@media (max-width: 900px) { .pd-grid { grid-template-columns: 1fr; } }
.pd-media {
  position: relative; overflow: hidden; border-radius: var(--r-xl);
  border: 1px solid var(--border); box-shadow: var(--shadow-2);
  aspect-ratio: 1/1; background: var(--surface-3);
}
.pd-media img { width: 100%; height: 100%; object-fit: cover; }
.pd-title { font-size: var(--step-5); letter-spacing: var(--tr-display); }
.pd-buy { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.pd-qty { border: 1.5px solid var(--border); border-radius: var(--r-full); padding: 5px 8px; }
.pd-note { font-size: var(--step--2); color: var(--text-3); }
.pd-safety {
  display: flex; gap: var(--s-3); padding: var(--s-4);
  border-radius: var(--r-md); background: var(--signal-soft);
  border: 1px solid color-mix(in srgb, var(--signal) 22%, transparent);
  font-size: var(--step--1); color: var(--text-2);
}
.pd-safety svg { width: 18px; height: 18px; flex: none; color: var(--signal); margin-top: 2px; }

/* ============================================================
   INDUSTRIES
   ============================================================ */
.ind-band { position: relative; scroll-margin-top: calc(var(--header-h) + 40px); }
.ind-clients {
  margin-top: var(--s-5); padding-top: var(--s-4);
  border-top: 1px solid var(--border);
  font-size: var(--step--1); color: var(--text-3);
}
.ind-clients strong {
  display: block; font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-label); text-transform: uppercase;
  color: var(--text-2); margin-bottom: 6px; font-weight: 500;
}

/* ============================================================
   ABOUT
   ============================================================ */
.about-hero {
  display: grid; grid-template-columns: 1.25fr 0.75fr;
  gap: clamp(32px, 6vw, 72px); align-items: center;
}
@media (max-width: 880px) { .about-hero { grid-template-columns: 1fr; } }
.mv-card { padding: clamp(26px, 4vw, 40px); border-radius: var(--r-xl); position: relative; overflow: hidden; }
.mv-card::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: linear-gradient(var(--aqua-400), var(--blue-600));
}
.mv-card.is-vision::before { background: linear-gradient(var(--red-400), var(--red-600)); }
.mv-card h2 { font-size: var(--step-2); }
.mv-card p { margin-top: var(--s-4); color: var(--text-2); }

.client-group h3 {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-label); text-transform: uppercase;
  color: var(--accent); font-weight: 500;
}
.client-group ul { margin-top: var(--s-4); display: grid; gap: 10px; }
.client-group li {
  display: flex; gap: 10px; align-items: baseline;
  color: var(--text-2); font-size: var(--step--1);
}
.client-group li::before { content: "—"; color: var(--text-4); flex: none; }

/* ============================================================
   CONTACT
   ============================================================ */
.contact-grid { display: grid; grid-template-columns: 0.85fr 1.15fr; gap: clamp(32px, 5vw, 64px); align-items: start; }
@media (max-width: 900px) { .contact-grid { grid-template-columns: 1fr; } }
.contact-row {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-4) var(--s-5); border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--surface);
  transition: all var(--t-fast);
}
a .contact-row:hover { border-color: var(--border-lit); transform: translateX(4px); background: var(--surface-2); }
.contact-ico {
  width: 42px; height: 42px; flex: none; display: grid; place-items: center;
  border-radius: var(--r-sm); background: var(--accent-soft); color: var(--accent);
}
.contact-row .cl {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--text-3);
}
.contact-row .cv { font-weight: 600; margin-top: 2px; font-size: var(--step--1); }

/* ============================================================
   404
   ============================================================ */
.nf { min-height: 62svh; display: grid; place-items: center; text-align: center; }
.nf .code {
  font-family: var(--font-display); font-size: clamp(6rem, 20vw, 13rem);
  font-weight: 600; line-height: .85; letter-spacing: -0.06em;
}


/* ============================================================
   BRAND ARCHITECTURE — about page card + product spec row
   ============================================================ */
.brand-card {
  display: grid; grid-template-columns: auto 1fr;
  gap: clamp(24px, 4vw, 52px); align-items: center;
}
.brand-card__marks {
  display: grid; justify-items: center; gap: var(--s-5);
}
.brand-card__parent { height: 62px; width: auto; }
[data-theme="light"] .brand-card__parent,
:root:not([data-theme="dark"]) .brand-card__parent {
  /* the white-on-transparent wordmark would vanish on a light card */
  content: url("../images/logo/vistex-logo-color-on-white.png");
}
.brand-card__rule {
  width: 60%; height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-lit), transparent);
}
.brand-card__copy { min-width: 0; }
@media (max-width: 720px) {
  .brand-card { grid-template-columns: 1fr; text-align: left; }
  .brand-card__marks { justify-items: start; }
  .brand-card__rule { width: 120px; }
  .brand-card__parent { height: 52px; }
}

/* Brand row in the product spec table */
.spec-row .swift-badge { display: block; }
.spec-brand-note {
  display: block; margin-top: 8px;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-mono); color: var(--text-3);
}

/* Badge inside the no-photo product placeholder */
.pcard-noimg .sb-badge { position: relative; margin-top: 4px; }

/* ============================================================
   INDUSTRIES — recommended products rail
   Cut-outs on glass, so each sector's shortlist reads as a spec
   sheet for that environment rather than another catalogue grid.
   ============================================================ */
.ind-recs { margin-top: clamp(40px, 6vw, 72px); }
.ind-recs-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-4); flex-wrap: wrap; margin-bottom: var(--s-6);
}
.rec-all {
  display: inline-flex; align-items: center; gap: 7px;
  /* a mono micro-label is only 18px tall on its own — pad it to a real target */
  min-height: 24px; padding: 3px 2px;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-mono); text-transform: uppercase;
  color: var(--accent);
}
.rec-all svg { transition: transform var(--t-fast); }
.rec-all:hover svg { transform: translateX(3px); }

.rec-rail {
  display: grid; gap: var(--s-4);
  grid-template-columns: repeat(6, minmax(0, 1fr));
}
@media (max-width: 1100px) { .rec-rail { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.rec-card {
  position: relative; overflow: hidden;
  display: grid; justify-items: center; align-content: start;
  gap: 2px; padding: var(--s-5) var(--s-3) var(--s-4);
  text-align: center;
  transition: transform var(--t-mid), box-shadow var(--t-mid), border-color var(--t-mid);
}
.rec-card:hover { transform: translateY(-6px); border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
.rec-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* The specular sweep is driven by the same --drift the rail already computes,
   so the glass "moves" with the page without a single extra calculation. */
.rec-card::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(115deg,
    transparent 34%, color-mix(in srgb, #fff 26%, transparent) 47%, transparent 60%);
  background-size: 280% 100%;
  background-position: calc(50% + var(--drift, 0) * -46%) 0;
  opacity: .7;
}
[data-theme="dark"] .rec-card::after {
  background: linear-gradient(115deg,
    transparent 34%, color-mix(in srgb, var(--aqua-400) 16%, transparent) 47%, transparent 60%);
  background-size: 280% 100%;
  background-position: calc(50% + var(--drift, 0) * -46%) 0;
}

.rec-glow {
  position: absolute; left: 50%; top: 14%; width: 76%; aspect-ratio: 1;
  transform: translateX(-50%); border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle,
    color-mix(in srgb, var(--aqua-400) 26%, transparent), transparent 68%);
  opacity: 0; transition: opacity var(--t-mid);
}
.rec-card:hover .rec-glow { opacity: 1; }

/* The products fan as the rail passes, rather than the panel sliding — the
   glass stays put and the contents float inside it. */
.rec-cut {
  position: relative; display: block; width: 100%; height: 92px;
  transform: translateY(calc(var(--drift, 0) * (-4px - var(--i, 0) * 1.2px)));
}
.rec-cut img {
  width: auto; height: 100%; max-width: 100%; margin-inline: auto; display: block;
  object-fit: contain;
  filter: drop-shadow(0 10px 12px rgba(20, 32, 72, .3));
}
.rec-cut--photo img { width: 100%; height: 100%; object-fit: cover; border-radius: var(--r-sm); }

.rec-name {
  margin-top: var(--s-3);
  font-family: var(--font-display); font-weight: 600; font-size: var(--step--1);
  line-height: 1.25; color: var(--text);
}
.rec-meta {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-mono); text-transform: uppercase; color: var(--text-3);
}

/* Phones get the swipe deck this site already uses everywhere else, rather
   than a six-row stack nobody scrolls to the bottom of. */
@media (max-width: 700px) {
  .rec-rail {
    grid-template-columns: none;
    grid-auto-flow: column; grid-auto-columns: 46%;
    overflow-x: auto; scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: var(--s-3);
    /* bleed to the screen edges so the deck reads as swipeable */
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
  }
  .rec-rail::-webkit-scrollbar { display: none; }
  .rec-card { scroll-snap-align: center; }
  .rec-cut { height: 78px; }
}
@media (max-width: 380px) { .rec-rail { grid-auto-columns: 58%; } }

/* ---- Scent picker (product detail) ------------------------------------- */
.scent { display: grid; gap: var(--s-3); }
.scent-head { display: flex; align-items: baseline; gap: var(--s-3); }
.scent-now {
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--step--1); color: var(--text);
}
.scent-chips { display: flex; flex-wrap: wrap; gap: 10px; }
.scent-chip {
  width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
  background: var(--sw);
  border: 2px solid color-mix(in srgb, var(--sw) 62%, var(--bg));
  box-shadow: inset 0 2px 5px rgba(255, 255, 255, .5), 0 3px 8px -3px rgba(12, 20, 48, .5);
  transition: transform var(--t-fast), box-shadow var(--t-fast), border-color var(--t-fast);
}
.scent-chip:hover { transform: scale(1.12); }
.scent-chip.on {
  /* a ring in the page background separates the marker from the swatch, so it
     reads on the pale Clear Lemon chip as clearly as on the dark ones */
  border-color: var(--text);
  box-shadow: 0 0 0 3px var(--bg), 0 0 0 5px var(--text), 0 4px 10px -3px rgba(12, 20, 48, .5);
}
.scent-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
@media (prefers-reduced-motion: reduce) { .scent-chip:hover { transform: none; } }

/* ---- "Where it is used" (product detail) --------------------------------
   Two plain lists, side by side. Rendered only for products that declare
   `applications` / `fabrics`, so the page never shows an empty shell. */
.uses {
  margin-top: var(--s-11);
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(24px, 4vw, 56px);
}
@media (max-width: 700px) { .uses { grid-template-columns: 1fr; gap: var(--s-7); } }
.uses-title {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--font-display); font-weight: 600; font-size: var(--step-0);
  letter-spacing: var(--tr-tight); color: var(--text);
}
.uses-title svg { width: 16px; height: 16px; flex: none; color: var(--accent); }
.uses-list {
  margin-top: var(--s-4);
  display: grid; gap: 9px;
  font-size: var(--step--1); color: var(--text-3); line-height: 1.5;
}
.uses-list li {
  position: relative; padding-left: 18px;
}
.uses-list li::before {
  content: ""; position: absolute; left: 0; top: .55em;
  width: 6px; height: 6px; border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 70%, transparent);
}

/* ---- Document downloads (product detail) --------------------------------
   Renders only for products declaring `docs`. Files are plain static assets
   under docs/, so no build step is involved. */
.pd-docs { display: grid; gap: var(--s-3); }
.pd-docs-row { display: flex; flex-wrap: wrap; gap: 10px; }
.doc-chip {
  display: inline-flex; align-items: center; gap: 9px;
  min-height: 40px; padding: 8px 14px;
  border: 1px solid var(--border); border-radius: var(--r-full);
  background: var(--surface-2); color: var(--text-2);
  font-size: var(--step--1); font-weight: 500;
  transition: border-color var(--t-fast), background var(--t-fast), color var(--t-fast);
}
.doc-chip svg { width: 15px; height: 15px; flex: none; color: var(--accent); }
.doc-chip:hover { border-color: var(--accent); background: var(--surface-3); color: var(--text); }
.doc-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.doc-kind {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: var(--tr-mono); text-transform: uppercase; color: var(--text-3);
}

/* ============================================================
   PRINT — procurement teams print product pages
   Strip the chrome, keep the specification.
   ============================================================ */
@media print {
  .site-header, .site-footer, .cart-drawer, .cart-fab, #vx-loader,
  .scroll-cue-wrap, .aurora, .bubbles, .marquee, .pstage-dots,
  .pd-buy, .doc-chip, .rec-rail, .cta-band, .skip-to-content { display: none !important; }

  /* Backgrounds and shadows cost ink and hide text on paper. */
  *, *::before, *::after {
    background: transparent !important;
    box-shadow: none !important;
    text-shadow: none !important;
    color: #000 !important;
    filter: none !important;
    animation: none !important;
    transition: none !important;
  }
  body { font-size: 11pt; }
  .card, .glass, .pd-media { border: 1px solid #999 !important; }
  .pd-grid, .uses { grid-template-columns: 1fr 1fr !important; }
  /* reveal-on-scroll must not leave the page blank on paper */
  [data-anim] { opacity: 1 !important; transform: none !important; }
  .pd-media { max-height: 90mm; }
  .pd-media img { max-height: 90mm; object-fit: contain; }
  /* the URL is the only way back to the page from a printout */
  .crumbs a[href]::after { content: ""; }
  .pd-safety { border: 1px solid #999 !important; padding: 8pt !important; }
  section, .card { break-inside: avoid; }
}
