/* =====================================================================
   NEWTECK website v1 - stylesheet
   Brand: turquoise #2BD5E6 on near-black #0B0E11. Chakra Petch (display) + Inter (body).
   Radius max 4px (pill only for the liquid-metal CTA).
   Dark theme only (brand decision). All colors are tokens on :root.
   ===================================================================== */

:root {
  color-scheme: dark;
  --tq: #2BD5E6;
  --tq2: #20B2C4;
  --tq-ink: #06181B;            /* text on turquoise */
  --bg: #0B0E11;
  --panel: #12161B;
  --panel2: #161B21;
  --line: #1A2027;
  --line2: #242B33;
  --fg: #F4F7F9;
  --mute: #9AA5B1;
  --mute2: #5C6773;
  --glow: rgba(43, 213, 230, .35);
  --err: #FF7A6B;
  --ok: #4BE0A0;
  --display: "Chakra Petch", "Inter", system-ui, sans-serif;
  --body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --gutter: clamp(16px, 4vw, 56px);
  --max: 1280px;
  --nav-h: 64px;
  --r: 4px;
  --ease: cubic-bezier(.22, .61, .36, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  /* z-index scale */
  --z-stage: 0; --z-vig: 1; --z-main: 2; --z-nav: 30; --z-mbar: 25; --z-toast: 40;
}

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: auto; -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--fg);
  font-family: var(--body); font-size: 16px; line-height: 1.55;
  overflow-x: hidden; -webkit-font-smoothing: antialiased;
}
img, video { max-width: 100%; display: block; }
a { color: inherit; }
button { font: inherit; color: inherit; }
h1, h2, h3, h4, p { margin: 0; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
:focus-visible { outline: 2px solid var(--tq); outline-offset: 3px; }

/* ---------- type ---------- */
.d { font-family: var(--display); letter-spacing: -.01em; }
.h1 { font-family: var(--display); font-weight: 700; font-size: clamp(34px, 6.2vw, 84px); line-height: 1.02; letter-spacing: -.02em; }
.h2 { font-family: var(--display); font-weight: 700; font-size: clamp(28px, 4.4vw, 56px); line-height: 1.06; letter-spacing: -.015em; }
.h3 { font-family: var(--display); font-weight: 700; font-size: clamp(17px, 1.6vw, 22px); line-height: 1.25; }
.lead { color: var(--mute); font-size: clamp(16px, 1.4vw, 20px); max-width: 60ch; }
.label { font-family: var(--display); font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--tq); font-weight: 700; }
.em-tq { color: var(--tq); font-style: normal; }
.kin .w { display: inline-block; opacity: 0; transform: translateY(.6em) rotate(1.5deg); transform-origin: left bottom; transition: opacity .7s var(--ease-out), transform .9s var(--ease-out); transition-delay: calc(var(--i) * 55ms); will-change: transform; }
.kin.in .w { opacity: 1; transform: none; }

/* technical divider with 45 degree step */
.tline { width: 220px; height: 10px; margin: 18px 0 0;
  background: linear-gradient(90deg, var(--tq), rgba(43, 213, 230, .25));
  clip-path: polygon(0 4px, 118px 4px, 126px 0, 220px 0, 220px 2px, 127px 2px, 119px 6px, 0 6px); }

/* ---------- fixed background layers ---------- */
#stage { position: fixed; inset: 0; z-index: var(--z-stage); pointer-events: none; background: var(--bg); }
#stage::after { /* hexagon honeycomb texture */
  content: ""; position: absolute; inset: 0; opacity: .07;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='97' viewBox='0 0 56 97'%3E%3Cpath d='M28 1 54 16v31L28 62 2 47V16z M28 62v34 M2 47 2 81l26 15 26-15V47' fill='none' stroke='%232BD5E6' stroke-width='1'/%3E%3C/svg%3E");
  background-size: 56px 97px;
  mask-image: radial-gradient(80% 70% at 50% 40%, #000 30%, transparent 100%);
  -webkit-mask-image: radial-gradient(80% 70% at 50% 40%, #000 30%, transparent 100%);
}
#vignette { position: fixed; inset: 0; z-index: var(--z-vig); pointer-events: none;
  background: radial-gradient(120% 90% at 50% 50%, transparent 45%, rgba(11, 14, 17, .8) 100%);
  opacity: 1; transition: opacity .6s; }
body.novig #vignette { opacity: .3; }
main { position: relative; z-index: var(--z-main); }

/* ---------- nav ---------- */
.nav { position: fixed; top: 0; left: 0; right: 0; z-index: var(--z-nav); height: var(--nav-h);
  display: flex; align-items: center; gap: 24px; padding: 0 var(--gutter);
  background: linear-gradient(180deg, rgba(11, 14, 17, .85), rgba(11, 14, 17, 0));
  transition: background .4s, backdrop-filter .4s; }
.nav.solid { background: rgba(11, 14, 17, .82); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); border-bottom: 1px solid var(--line); }
/* Logo: the NEWTECK wordmark (letters and the stepped line) as one flat turquoise PNG made from Iván's neon logo render
   with docs/tools/logo-clean.swift. Provisional until the official vector logo (.AI, .EPS, .SVG) arrives from NEWTECK. */
.logo { display: inline-flex; align-items: center; text-decoration: none; flex: none; }
.logo img { display: block; height: 32px; width: auto; }
footer .logo img { height: 38px; }
.nav-links { display: flex; gap: 2px; margin-left: auto; }
.nav-links a { position: relative; isolation: isolate; display: inline-block; padding: 8px 9px; text-decoration: none; white-space: nowrap;
  font-family: var(--display); font-weight: 600; font-size: 11.5px; letter-spacing: .045em; text-transform: uppercase; color: var(--mute);
  transition: color .3s var(--ease); }
.nav-links a::before, .nav-links a::after { content: ""; position: absolute; left: 0; width: 100%; z-index: -1; pointer-events: none; }
.nav-links a::before { top: 0; height: 100%; border-top: 2px solid var(--tq); border-bottom: 2px solid var(--tq);
  transform: scaleY(2); opacity: 0; transform-origin: 50% 50%; transition: transform .3s var(--ease), opacity .3s var(--ease); }
.nav-links a::after { top: 0; height: 100%; background: var(--tq);
  transform: scale(0); opacity: 0; transform-origin: 50% 0; transition: transform .3s var(--ease), opacity .3s var(--ease); }
.nav-links a:is(:focus-visible, :active) { color: var(--tq-ink); }
.nav-links a:is(:focus-visible, :active)::before { transform: scaleY(1); opacity: 1; }
.nav-links a:is(:focus-visible, :active)::after { transform: scale(1); opacity: 1; }
@media (hover: hover) {
  .nav-links a:hover { color: var(--tq-ink); }
  .nav-links a:hover::before { transform: scaleY(1); opacity: 1; }
  .nav-links a:hover::after { transform: scale(1); opacity: 1; }
}
.nav-right { display: flex; align-items: center; gap: 12px; margin-left: auto; flex: none; }
.nav-links + .nav-right { margin-left: 0; }
.lang-btn, .nav-right .btn { flex: none; white-space: nowrap; }
.lang-btn { background: transparent; border: 1px solid var(--line2); color: var(--fg); border-radius: var(--r); padding: 7px 10px; font-family: var(--display); font-size: 11px; letter-spacing: .14em; cursor: pointer; display: inline-flex; gap: 6px; align-items: center; }
.lang-btn span { color: var(--mute2); }
.lang-btn span.on { color: var(--tq); }
.lang-btn:hover { border-color: var(--tq); }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 42px; padding: 0 18px;
  border-radius: var(--r); border: 1px solid var(--line2); background: transparent; color: var(--fg);
  text-decoration: none; font-weight: 600; font-size: 14px; cursor: pointer; white-space: nowrap;
  transition: transform .15s, border-color .2s, background .2s, color .2s; }
.btn:hover { border-color: var(--tq); }
.btn:active { transform: translateY(1px) scale(.99); }
.btn.p { background: var(--tq); color: var(--tq-ink); border-color: var(--tq); }
.btn.p:hover { background: var(--tq2); border-color: var(--tq2); }
.btn.sm { min-height: 36px; padding: 0 14px; font-size: 13px; }
.btn.wide { width: 100%; }
.btn[disabled] { opacity: .6; cursor: progress; }
/* Nav CTA: vanilla port of the FlameButton React component, shape kept from the sharp button before it (chamfered corners at
   top left and bottom right, the brand's angular chevron cut, no radius). Turquoise face (the button's original color) with a lighter
   turquoise flame INSIDE the button that follows the pointer (two glows centered on --fx, faded in and out by --fi). js/ui.js
   (NT.flameButton) only writes those two custom properties. The flame is a lighter turquoise (see --flame-rgb) instead of the original
   orange and red: brighter than the face, never white. There is deliberately no glow outside the button.
   clip-path would crop an outline, so keyboard focus uses an inset ring. */
.flame { --flame-rgb: 150, 243, 251;   /* lighter turquoise (#96F3FB), the light of the hover flame */
  position: relative; display: inline-flex; isolation: isolate; flex: none; }
.nav .btn.nav-cta { --face: var(--tq);
  position: relative; z-index: 1; isolation: isolate; overflow: hidden; border: 0; border-radius: 0; min-height: 38px; gap: 8px; padding: 0 13px 0 18px;
  background: var(--face); color: var(--tq-ink);
  font-family: var(--display); font-weight: 700; font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase;
  clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
  transition: transform .15s; }
.nav .btn.nav-cta::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: var(--fi, 0); transition: opacity .15s ease-out;
  background:
    radial-gradient(102px 51.5px at var(--fx, 50%) 50%, rgba(var(--flame-rgb), 1) 29%, rgba(var(--flame-rgb), .7) 48.5%, rgba(var(--flame-rgb), .28) 60.71%, rgba(var(--flame-rgb), 0) 100%),
    radial-gradient(60.5px 60.5px at var(--fx, 50%) 50%, rgba(var(--flame-rgb), 1) 3.5%, rgba(var(--flame-rgb), 1) 26.5%, rgba(var(--flame-rgb), .8) 37.5%, rgba(var(--flame-rgb), .4) 49%, rgba(var(--flame-rgb), 0) 92.5%); }
.nav .btn.nav-cta::after { content: ""; flex: none; width: 15px; height: 15px; background: currentColor; transition: transform .3s var(--ease);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6l-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6l-6 6'/%3E%3C/svg%3E") center / contain no-repeat; }
.nav .btn.nav-cta:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--bg), inset 0 0 0 4px var(--fg); }
.nav .btn.nav-cta:active { transform: translateY(1px); }
@media (hover: hover) {
  .nav .btn.nav-cta:hover { background: var(--face); }   /* .btn.p:hover would otherwise darken the face to --tq2 */
  .nav .btn.nav-cta:hover::after { transform: translateX(3px); }
}
.menu-btn { display: none; background: transparent; border: 1px solid var(--line2); border-radius: var(--r); width: 40px; height: 40px; cursor: pointer; }
.menu-btn svg { width: 20px; height: 20px; stroke: var(--fg); fill: none; stroke-width: 2; }
/* Roomy sizes on wide screens. 1241 to 1399 px keeps the compact sizes above so the Spanish labels still fit on one line. */
@media (min-width: 1400px) {
  .nav-links a { padding: 8px 13px; font-size: 12.5px; letter-spacing: .09em; }
  .nav .btn.nav-cta { gap: 10px; padding: 0 16px 0 20px; font-size: 12.5px; letter-spacing: .09em; }
}
@media (max-width: 1240px) {
  .nav-links { display: none; }
  .nav-links + .nav-right { margin-left: auto; }   /* with the links hidden, push the right group (language, CTA, burger) to the edge */
  .menu-btn { display: inline-flex; align-items: center; justify-content: center; }
  body.menu .nav-links { display: flex; flex-direction: column; align-items: center; gap: 8px; position: fixed; top: var(--nav-h); left: 0; right: 0; bottom: 0; padding: 24px var(--gutter); overflow-y: auto; background: rgba(11, 14, 17, .96); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); }
  body.menu .nav-links a:first-child { margin-top: auto; }   /* centers the list, and stays scrollable on short screens */
  body.menu .nav-links a:last-child { margin-bottom: auto; }
  body.menu .nav-links a { font-size: 19px; padding: 12px 26px; color: var(--fg); }
  body.menu { overflow: hidden; }
}
@media (max-width: 639px) { .nav .flame, .nav .btn.nav-cta { display: none; } }

/* ---------- chapters (sticky pin model from scroll-transitions-extract.html) ---------- */
.ch { position: relative; }
.ch[data-h="120"] { height: 120vh; } .ch[data-h="170"] { height: 170vh; } .ch[data-h="200"] { height: 200vh; }
.ch[data-h="220"] { height: 220vh; } .ch[data-h="260"] { height: 260vh; } .ch[data-h="300"] { height: 300vh; } .ch[data-h="290"] { height: 290vh; }
.pin { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; display: flex; align-items: center; padding: 0 var(--gutter); }
.cap { position: absolute; left: var(--gutter); right: var(--gutter); max-width: 560px; }
.cap.tl { top: calc(var(--nav-h) + 32px + env(safe-area-inset-top, 0px)); }
.cap.bl { bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }
.step { opacity: 0; transform: translateY(16px); transition: opacity .55s var(--ease), transform .55s var(--ease); pointer-events: none; }
.step.on { opacity: 1; transform: none; pointer-events: auto; }

/* ---------- sections (normal flow) ---------- */
.sec { position: relative; padding: clamp(88px, 12vw, 184px) var(--gutter); }   /* Iván asked for more air between sections (Oct 2026) */
.wrap { max-width: var(--max); margin: 0 auto; }
.sec-head { max-width: 760px; margin-bottom: clamp(32px, 5vw, 64px); }
.sec-head .lead { margin-top: 18px; }
.rv { opacity: 0; transform: translateY(26px); transition: opacity .8s var(--ease-out), transform .9s var(--ease-out); transition-delay: calc(var(--i, 0) * 90ms); }
.rv.in { opacity: 1; transform: none; }

/* ---------- hero ---------- */
/* The bottom of the hero fades to real transparency (mask), not to a flat color. The page background behind it has
   a glow and a hex pattern, so a flat-color fade left a hard line where the hero ends. */
.hero-media { position: absolute; inset: 0; z-index: 0; overflow: hidden; background: #000;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 62%, rgba(0,0,0,.954) 67%, rgba(0,0,0,.83) 72%, rgba(0,0,0,.655) 77%, rgba(0,0,0,.46) 82%, rgba(0,0,0,.27) 87%, rgba(0,0,0,.115) 92%, rgba(0,0,0,.031) 96%, transparent 100%); mask-image: linear-gradient(180deg, #000 0%, #000 62%, rgba(0,0,0,.954) 67%, rgba(0,0,0,.83) 72%, rgba(0,0,0,.655) 77%, rgba(0,0,0,.46) 82%, rgba(0,0,0,.27) 87%, rgba(0,0,0,.115) 92%, rgba(0,0,0,.031) 96%, transparent 100%); }
.hero-media video { width: 100%; height: 100%; object-fit: cover; filter: brightness(.9) saturate(.95); }
.hero-media::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(11, 14, 17, .78) 0%, rgba(11, 14, 17, .35) 55%, rgba(11, 14, 17, .15) 100%); }
.hero-copy { position: relative; z-index: 1; max-width: min(1180px, 100%); padding-top: var(--nav-h); }   /* wide enough for the bigger headline to stay on two lines on desktop */
.hero-copy .h1 { font-weight: var(--wght, 700); font-size: clamp(51px, 9.3vw, 126px); }   /* 50% bigger than the old clamp(34px, 6.2vw, 84px) */
.hero-copy .lead { margin-top: 22px; max-width: 46ch; }
.hero-cta { display: flex; align-items: center; gap: 18px; margin-top: 34px; flex-wrap: wrap; }
.hero-cta .btn { min-height: 46px; }
/* Hero entrance in one beat: the video plays alone, then the headline rolls in while the paragraph and both buttons rise in,
   sharpen and fade up in a short cascade. js/home.js adds html.hero-go 3.75 s after the hero video starts (js/boot.js adds it by itself after 9 s if anything
   fails, so the buttons can never stay hidden). Hidden elements are also visibility:hidden, so they cannot be focused or tapped.
   Reduced motion never hides them. */
@media (prefers-reduced-motion: no-preference) {
  html.js:not(.hero-go) .hero-copy .h1 { visibility: hidden; }   /* the headline appears with the paragraph and buttons: its letters come in at hero-go */
  html.js:not(.hero-go) .hero-copy .lead,
  html.js:not(.hero-go) .hero-cta > * { opacity: 0; transform: translateY(22px); filter: blur(8px); visibility: hidden; pointer-events: none; }
  .hero-copy .lead, .hero-cta > * { transition: opacity .9s var(--ease-out), transform .9s var(--ease-out), filter .9s var(--ease-out), visibility 0s linear; }
  .hero-cta > :nth-child(1) { transition-delay: .18s; }
  .hero-cta > :nth-child(2) { transition-delay: .32s; }
}

/* ---------- engineered and tested: looping van video that takes over the hero ----------
   The video layer lives inside the hero's pinned stage. As you scroll, js/home.js writes --u (0 to 1, eased) on #hero and the
   chosen transition variant (data-tx on #hero: a dissolve, b chevron wipe, c hexagon iris, d zoom-through) reveals the layer
   while the hero underneath is dimmed or pushed. After that the title builds in: --t1 words, --ln stepped line, --t2 second line,
   --drift rise; --cf is a light pulse on the cuts of the video; --mk fades the bottom edge to real transparency for the exit.
   Only transform, opacity, filter and clip-path are animated. */
.van-layer { position: absolute; inset: 0; z-index: 3; pointer-events: none; background: #05080a; visibility: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 84%, rgba(0, 0, 0, calc(1 - var(--mk, 0))) 100%); mask-image: linear-gradient(180deg, #000 0%, #000 84%, rgba(0, 0, 0, calc(1 - var(--mk, 0))) 100%); }
#hero.tx-on .van-layer, #hero.tx-on .tx-edge, #hero.tx-on .tx-ring, #hero.tx-on .tx-flash { visibility: visible; }
#hero.covered .hero-media, #hero.covered .hero-copy { visibility: hidden; }
.van-frame { position: absolute; inset: 0; overflow: hidden; }
.van-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.van-grade { position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(0deg, rgba(11, 14, 17, .94) 0%, rgba(11, 14, 17, .62) 26%, rgba(11, 14, 17, 0) 58%),
              radial-gradient(70% 55% at 0% 100%, rgba(43, 213, 230, .22), transparent 72%),
              radial-gradient(120% 95% at 50% 40%, transparent 58%, rgba(11, 14, 17, .5) 100%); }
.van-cutflash { position: absolute; inset: 0; pointer-events: none; opacity: var(--cf, 0);
  background: radial-gradient(90% 90% at 50% 50%, rgba(206, 250, 255, .9), rgba(43, 213, 230, .5) 55%, rgba(43, 213, 230, 0) 100%); }
/* The title block sits centered on the screen with its lines centered (Iván, Oct 2026). It hugs the text (fit-content, centered
   by the auto side margins between left 0 and right 0). */
.van-title { position: absolute; left: 0; right: 0; bottom: 12vh; z-index: 2; width: fit-content; max-width: min(1180px, calc(100% - 2 * var(--gutter)));
  margin-inline: auto; padding: clamp(18px, 2.2vw, 32px) clamp(22px, 2.6vw, 40px); text-align: center; transform: translateY(var(--drift, 0px)); }
.van-h { font-size: clamp(30px, 6vw, 92px); text-align: center; text-shadow: 0 2px 28px rgba(0, 0, 0, .55); }
.van-h .vw { --k: clamp(0, calc(var(--t1, 0) * var(--n, 3) - var(--i, 0)), 1);
  display: inline-block; opacity: var(--k); transform: translateY(calc((1 - var(--k)) * .55em)); filter: blur(calc((1 - var(--k)) * 10px)); }
.van-line { display: block; width: 220px; height: 10px; margin: 18px auto 14px; transform-origin: 50% 50%; transform: scaleX(var(--ln, 0));
  background: linear-gradient(90deg, var(--tq), rgba(43, 213, 230, .25));
  clip-path: polygon(0 4px, 118px 4px, 126px 0, 220px 0, 220px 2px, 127px 2px, 119px 6px, 0 6px); }
.van-sub { text-align: center; opacity: var(--t2, 0); transform: translateY(calc((1 - var(--t2, 0)) * 18px)); text-shadow: 0 2px 20px rgba(0, 0, 0, .6); }
.ct-l2.van-sub { font-size: clamp(22px, 3.8vw, 58px); }   /* the turquoise line, bigger at Iván's request (was 2.8vw) */
/* Gray glass plate behind the title (Iván, Oct 2026), so the words read apart from the moving video (the van's own lettering
   sat right behind "Delivered across Texas"): translucent dark gray that also blurs and grays the video behind it. It fades in
   with the first word (--t1), rises and fades out with the title. No hard rectangle (Iván: blurrier contours): the plate reaches
   --pf past the text box and fades out over that margin on an eased curve, so it melts into the picture. Two layers:
   ::after is the gray tint: its own background fades it at the top and bottom and ONE mask fades it at the sides (inside this
   composited, masked video layer WebKit dropped the tint entirely when two mask layers were intersected; one layer renders).
   ::before blurs the video (backdrop-filter), feathered on both sides by two intersected masks; where a browser cannot mask a
   backdrop that way, that layer drops out and the feathered tint alone remains, never a hard edge. Wide screens only: on phones
   and tall screens the title sits under the video, on the page background. */
.van-title::before, .van-title::after { --pf: clamp(28px, 3.4vw, 56px);
  --fade: transparent 0, rgba(0, 0, 0, .1) calc(var(--pf) * .25), rgba(0, 0, 0, .5) calc(var(--pf) * .5), rgba(0, 0, 0, .9) calc(var(--pf) * .75), #000 var(--pf),
    #000 calc(100% - var(--pf)), rgba(0, 0, 0, .9) calc(100% - var(--pf) * .75), rgba(0, 0, 0, .5) calc(100% - var(--pf) * .5), rgba(0, 0, 0, .1) calc(100% - var(--pf) * .25), transparent 100%;
  content: ""; position: absolute; inset: calc(-1 * var(--pf)); z-index: -1; pointer-events: none;
  opacity: clamp(0, calc(var(--t1, 0) * 3), 1); }
.van-title::before { -webkit-backdrop-filter: blur(10px) saturate(.6); backdrop-filter: blur(10px) saturate(.6);
  -webkit-mask-image: linear-gradient(90deg, var(--fade)), linear-gradient(180deg, var(--fade)); -webkit-mask-composite: source-in;
  mask-image: linear-gradient(90deg, var(--fade)), linear-gradient(180deg, var(--fade)); mask-composite: intersect; }
.van-title::after { --c: 22, 26, 30;
  background: linear-gradient(180deg, rgba(var(--c), 0) 0, rgba(var(--c), .056) calc(var(--pf) * .25), rgba(var(--c), .28) calc(var(--pf) * .5), rgba(var(--c), .5) calc(var(--pf) * .75),
    rgba(var(--c), .56) var(--pf), rgba(var(--c), .56) calc(100% - var(--pf)), rgba(var(--c), .5) calc(100% - var(--pf) * .75), rgba(var(--c), .28) calc(100% - var(--pf) * .5),
    rgba(var(--c), .056) calc(100% - var(--pf) * .25), rgba(var(--c), 0) 100%);
  -webkit-mask-image: linear-gradient(90deg, var(--fade)); mask-image: linear-gradient(90deg, var(--fade)); }
@media (max-width: 760px), (max-aspect-ratio: 1/1) {
  /* tall screens: the video is a 16:9 band like a cinema screen, the title sits under it (no plate needed there) */
  .van-frame { top: calc(var(--nav-h) + 16vh); bottom: auto; height: 56.25vw; }
  .van-grade { background: linear-gradient(0deg, rgba(11, 14, 17, .7) 0%, rgba(11, 14, 17, 0) 40%), radial-gradient(90% 70% at 0% 100%, rgba(43, 213, 230, .2), transparent 72%); }
  .van-title { bottom: auto; top: calc(var(--nav-h) + 16vh + 56.25vw + 36px); padding: 0; }
  .van-title::before, .van-title::after { content: none; }
  .van-h { font-size: clamp(28px, 8.4vw, 56px); }
}

/* transition helpers (they only show for the variants that use them) */
.tx-edge, .tx-ring, .tx-flash { position: absolute; inset: 0; z-index: 4; pointer-events: none; visibility: hidden; opacity: 0; }
.tx-edge i, .tx-ring { position: absolute; inset: 0; display: block; }
.tx-flash { background: radial-gradient(80% 80% at 50% 50%, rgba(235, 253, 255, .96), rgba(43, 213, 230, .85) 45%, rgba(43, 213, 230, 0) 100%); }

/* A. dissolve with push: the video fades in and settles from 1.1 to 1, soft to sharp; the hero dims and drifts toward the viewer */
#hero[data-tx="a"] .van-layer { opacity: var(--u, 0); }
#hero[data-tx="a"] .van-video { transform: scale(calc(1.1 - var(--u, 0) * .1)); filter: blur(calc((1 - var(--u, 0)) * 10px)); }
#hero[data-tx="a"] .hero-media { transform: scale(calc(1 + var(--u, 0) * .06)); filter: brightness(calc(1 - var(--u, 0) * .5)); }

/* B. chevron wipe: a slanted edge (the logo's angle) sweeps from the bottom left to the top right and uncovers the video, with a turquoise line on the edge */
#hero[data-tx="b"] { --bt: calc(-5% + var(--u, 0) * 140%); --bb: calc(-40% + var(--u, 0) * 140%); }
#hero[data-tx="b"] .van-layer { clip-path: polygon(0 0, var(--bt) 0, var(--bb) 100%, 0 100%); }
#hero[data-tx="b"] .tx-edge { opacity: calc(var(--u, 0) * (1 - var(--u, 0)) * 4); filter: drop-shadow(0 0 10px rgba(43, 213, 230, .95)); }
#hero[data-tx="b"] .tx-edge i { background: linear-gradient(180deg, #CFFBFF, var(--tq)); clip-path: polygon(var(--bt) 0, calc(var(--bt) + .7%) 0, calc(var(--bb) + .7%) 100%, var(--bb) 100%); }
#hero[data-tx="b"] .hero-media { filter: brightness(calc(1 - var(--u, 0) * .35)); }

/* C. hexagon iris: a pointy-top hexagon (the brand hex) grows from the center and uncovers the video; a turquoise ring rides its edge */
#hero[data-tx="c"] { --R: calc(var(--u, 0) * 100vmax); --Rr: calc(var(--u, 0) * 100vmax + .7vmax); }
#hero[data-tx="c"] .van-layer { clip-path: polygon(50% calc(50% - var(--R)), calc(50% + var(--R) * .866) calc(50% - var(--R) * .5), calc(50% + var(--R) * .866) calc(50% + var(--R) * .5), 50% calc(50% + var(--R)), calc(50% - var(--R) * .866) calc(50% + var(--R) * .5), calc(50% - var(--R) * .866) calc(50% - var(--R) * .5)); }
#hero[data-tx="c"] .tx-ring { opacity: calc(var(--u, 0) * (1 - var(--u, 0)) * 4); background: var(--tq); filter: drop-shadow(0 0 10px rgba(43, 213, 230, .9));
  clip-path: polygon(evenodd, 50% calc(50% - var(--Rr)), calc(50% + var(--Rr) * .866) calc(50% - var(--Rr) * .5), calc(50% + var(--Rr) * .866) calc(50% + var(--Rr) * .5), 50% calc(50% + var(--Rr)), calc(50% - var(--Rr) * .866) calc(50% + var(--Rr) * .5), calc(50% - var(--Rr) * .866) calc(50% - var(--Rr) * .5), 50% calc(50% - var(--Rr)),
    50% calc(50% - var(--R)), calc(50% - var(--R) * .866) calc(50% - var(--R) * .5), calc(50% - var(--R) * .866) calc(50% + var(--R) * .5), 50% calc(50% + var(--R)), calc(50% + var(--R) * .866) calc(50% + var(--R) * .5), calc(50% + var(--R) * .866) calc(50% - var(--R) * .5), 50% calc(50% - var(--R))); }
#hero[data-tx="c"] .hero-media { filter: brightness(calc(1 - var(--u, 0) * .6)); transform: scale(calc(1 + var(--u, 0) * .05)); }

/* D. zoom-through: the hero rushes toward you, blurs and floods with a turquoise flash; the video emerges from the flash settling from 1.25 to 1 */
#hero[data-tx="d"] .hero-media { transform: scale(calc(1 + var(--u, 0) * .5)); filter: blur(calc(var(--u, 0) * 14px)); }
#hero[data-tx="d"] .tx-flash { opacity: calc(var(--u, 0) * (1 - var(--u, 0)) * 4); }
#hero[data-tx="d"] .van-layer { opacity: clamp(0, calc((var(--u, 0) - .45) * 3.6), 1); }
#hero[data-tx="d"] .van-video { transform: scale(calc(1.25 - var(--u, 0) * .25)); }

/* reduced motion: no animated transition, the layer simply appears (js/home.js switches --u from 0 to 1 at one scroll position) */
@media (prefers-reduced-motion: reduce) {
  #hero.ch[data-h] { height: 200vh; }
  #hero .van-layer { clip-path: none !important; }
  #hero .tx-edge, #hero .tx-ring, #hero .tx-flash { display: none; }
  #hero .hero-media, #hero .van-video { transform: none !important; filter: none !important; }
}

/* temporary picker for the four transition options (only built when the address has ?options) */
.tx-pick { position: fixed; left: 50%; bottom: calc(24px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%); z-index: 45; display: flex; align-items: center; gap: 6px; padding: 8px;
  background: rgba(11, 14, 17, .92); border: 1px solid var(--line2); border-radius: var(--r); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); max-width: calc(100vw - 24px); }
.tx-pick span { font-family: var(--display); font-size: 10px; letter-spacing: .18em; text-transform: uppercase; color: var(--mute2); padding: 0 6px; }
.tx-pick button { min-height: 36px; padding: 0 12px; background: transparent; border: 1px solid var(--line2); border-radius: var(--r); color: var(--fg); font-size: 12.5px; font-weight: 600; cursor: pointer; white-space: nowrap; }
.tx-pick button[aria-pressed="true"] { background: var(--tq); border-color: var(--tq); color: var(--tq-ink); }
@media (max-width: 760px) { .tx-pick { bottom: calc(66px + env(safe-area-inset-bottom, 0px)); flex-wrap: wrap; justify-content: center; } .tx-pick span { width: 100%; text-align: center; } }

/* ---------- supply: vertical tabs ----------
   Vanilla port of the vertical-tabs React component. A list of services on the left (number, title, and for the active one its
   description and link) with a progress bar that fills in 5 s and then moves to the next one; on the right a frame whose picture
   slides vertically when the active service changes, with previous and next buttons. js/home.js (supplyTabs) toggles .is-active,
   .is-on and --y; the progress bar is a CSS animation and its animationend event is what advances to the next service.
   Brand adaptation: radius 4px instead of 24 to 40px, square buttons, turquoise progress, no text over the photos. */
/* "Our products" title: the words pull up (vanilla port of the WordPullUp React component, framer-motion; it replaced the
   AnimatedText breathing letters at Iván's request, Oct 2026), in the same type as "WINDOW FILM" (Chakra Petch 700, uppercase,
   light grey) and bigger than the other section titles. When the title comes into view (js/home.js, wordPullUp) the heading fades
   in and each word rises and fades in, 0.2 s after the previous one, like the component's staggerChildren .2. Same motion as the
   component: opacity in 0.3 s on framer's default ease, and the rise on framer's default spring for y (stiffness 500, damping 25),
   drawn with a linear() curve sampled from that spring (a small overshoot, then it settles); browsers without linear() keep the
   close cubic-bezier of the first declaration. The rise is .28em, the component's 20px at its 72px demo size, so it keeps its
   proportion on this bigger title. The divider under it draws in once the words are up. Reduced motion: nothing is split. */
#supply .sec-head { max-width: none; }
#supply .sec-head.rv { opacity: 1; transform: none; transition: none; }   /* the words animate, not the block */
.h2.wpu-title { font-family: var(--display); font-weight: 700; text-transform: uppercase; color: #D9DEE3; font-size: clamp(46px, 8.6vw, 132px); line-height: .95; letter-spacing: -.01em; }
.wpu-word { display: inline-block; }
html.js .wpu-split { opacity: 0; }
html.js .wpu-split .wpu-word { opacity: 0; transform: translateY(.28em); }
html.js .wpu-split.wpu-go { opacity: 1; transition: opacity .3s cubic-bezier(.25, .1, .35, 1); }
html.js .wpu-split.wpu-go .wpu-word { opacity: 1; transform: none;
  transition: opacity .3s cubic-bezier(.25, .1, .35, 1) calc(var(--i, 0) * .2s), transform .6s cubic-bezier(.34, 1.56, .64, 1) calc(var(--i, 0) * .2s);
  transition: opacity .3s cubic-bezier(.25, .1, .35, 1) calc(var(--i, 0) * .2s), transform .6s linear(0, .084 3.3%, .277 6.7%, .505 10%, .721 13.3%, .895 16.7%, 1.016 20%, 1.088 23.3%, 1.117 26.7%, 1.117 30%, 1.099 33.3%, 1.059 38.3%, 1.022 43.3%, .993 50%, .986 56.7%, .99 63.3%, .997 71.7%, 1.002 83.3%, 1) calc(var(--i, 0) * .2s); }
html.js .wpu-split + .tline { opacity: 0; transform: scaleX(.3); transform-origin: 0 50%; }
html.js .wpu-split.wpu-go + .tline { opacity: 1; transform: none; transition: opacity .5s var(--ease-out) .45s, transform .8s var(--ease-out) .45s; }
.vt { display: grid; grid-template-columns: 1fr; gap: 36px; align-items: start; }
.vt-media { order: -1; }
@media (min-width: 1024px) { .vt { grid-template-columns: 5fr 7fr; gap: 64px; } .vt-media { order: 0; } }
.vt-list { list-style: none; margin: 0; padding: 0; }
.vt-item { position: relative; border-top: 1px solid var(--line); padding-left: 20px; }
.vt-item:first-child { border-top: 0; }
.vt-item::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px; background: var(--line2); }
.vt-prog { position: absolute; left: 0; top: 0; bottom: 0; width: 2px; z-index: 1; background: var(--tq); transform-origin: 50% 0; transform: scaleY(0); }
.vt-item.is-active .vt-prog { animation: vt-fill 5s linear forwards; }
.vt.is-paused .vt-item.is-active .vt-prog { animation-play-state: paused; }
@keyframes vt-fill { to { transform: scaleY(1); } }
.vt-tab { width: 100%; display: flex; align-items: baseline; gap: 14px; padding: 22px 0; text-align: left; cursor: pointer; background: none; border: 0; color: var(--mute2); transition: color .4s var(--ease); }
.vt-tab:hover, .vt-item.is-active .vt-tab { color: var(--fg); }
.vt-n { font-family: var(--display); font-size: 11px; letter-spacing: .14em; color: var(--mute2); font-variant-numeric: tabular-nums; transition: color .4s; }
.vt-item.is-active .vt-n { color: var(--tq); }
.vt-t { font-family: var(--display); font-weight: 700; font-size: clamp(22px, 2.6vw, 36px); line-height: 1.1; letter-spacing: -.01em; }
.vt-panel { display: grid; grid-template-rows: 0fr; visibility: hidden; transition: grid-template-rows .4s var(--ease-out), visibility 0s linear .4s; }
.vt-item.is-active .vt-panel { grid-template-rows: 1fr; visibility: visible; transition: grid-template-rows .4s var(--ease-out), visibility 0s; }
.vt-panel-in { overflow: hidden; min-height: 0; }
.vt-panel-in p { color: var(--mute); font-size: 15.5px; max-width: 40ch; padding-bottom: 6px; }
.vt .go { margin: 8px 0 24px; color: var(--tq); font-size: 13.5px; font-weight: 600; text-decoration: none; display: inline-flex; gap: 6px; align-items: center; }
.vt .go svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 2; transition: transform .3s; }
.vt .go:hover svg { transform: translateX(4px); }
.vt-stage { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); }
.vt-slide { position: absolute; inset: 0; cursor: pointer; opacity: 0; transform: translateY(var(--y, 100%)); transition: transform .7s cubic-bezier(.22, 1, .36, 1), opacity .4s ease; }
.vt-slide.is-on { z-index: 1; opacity: 1; transform: none; }
.vt-slide.no-t { transition: none; }
.vt-slide img { display: block; width: 100%; height: 100%; object-fit: cover; filter: saturate(.92) brightness(.92); transition: transform .8s var(--ease-out); }
/* Slide 1 (window tint) is a cream poster (media/supply-tint.jpg). The frame has the poster's own 4:3 shape at every width, so the whole poster is
   shown: object-fit contain, never cover, no zoom on hover and no dark overlay (real colors). */
.vt-s1 { background: #0a0a0a; }   /* the poster has a thin black border of its own, so the sub-pixel the 4:3 frame can leave blends with it */
.vt-s1::after { display: none; }
.vt-s1 img { object-fit: contain; object-position: 50% 50%; filter: none; }
.vt-stage:hover .vt-slide.vt-s1 img { transform: none; }
/* Slide 2 (PPF) is a turquoise poster (media/supply-ppf.jpg), shown whole like slide 1: contain, no zoom, no overlay. The frame background is a
   vertical gradient between the poster's own top and bottom turquoise, so the half pixel the 4:3 frame can leave never shows as a seam. */
.vt-s2 { background: linear-gradient(180deg, #0DD0E2, #12DAE8); }
.vt-s2::after { display: none; }
.vt-s2 img { object-fit: contain; object-position: 50% 50%; filter: none; }
.vt-stage:hover .vt-slide.vt-s2 img { transform: none; }
.vt-stage:hover .vt-slide.is-on img { transform: scale(1.04); }
.vt-slide::after { content: ""; position: absolute; inset: auto 0 0 0; height: 36%; pointer-events: none; background: linear-gradient(0deg, rgba(11, 14, 17, .55), transparent); }
/* Slides 3 (ceramic coating) and 4 (installer tools) have no picture: a dark turquoise panel with the hex pattern and the badge. */
.vt-blank { display: grid; place-items: center; background: linear-gradient(135deg, #0F2A2E, var(--panel)); }
.vt-blank::before, .ga-ph::before, .tm-photo::before { content: ""; position: absolute; inset: 0; opacity: .18; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='97' viewBox='0 0 56 97'%3E%3Cpath d='M28 1 54 16v31L28 62 2 47V16z M28 62v34 M2 47 2 81l26 15 26-15V47' fill='none' stroke='%232BD5E6' stroke-width='1'/%3E%3C/svg%3E"); background-size: 56px 97px;
  -webkit-mask-image: radial-gradient(75% 70% at 50% 50%, #000 25%, transparent 100%); mask-image: radial-gradient(75% 70% at 50% 50%, #000 25%, transparent 100%); }
/* "Coming soon" badge inside the picture of a service that is not available yet (03 ceramic coating, 04 installer tools): a glass
   chip centered on the picture, turquoise text and a small pulsing dot. When a service launches, delete its .vt-soon element. */
.vt-soon { position: absolute; left: 50%; top: 50%; z-index: 2; transform: translate(-50%, -50%); display: inline-flex; align-items: center; gap: 10px; white-space: nowrap;
  padding: 12px 13px 12px 16px; font-family: var(--display); font-weight: 700; font-size: clamp(12px, 1.2vw, 15px); letter-spacing: .22em; text-transform: uppercase; color: var(--tq);
  background: rgba(11, 14, 17, .66); border: 1px solid rgba(43, 213, 230, .55); border-radius: var(--r); box-shadow: 0 12px 32px rgba(0, 0, 0, .45);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
.vt-soon::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--tq); }
.vt-soon::after { content: ""; position: absolute; left: 16px; top: 50%; width: 6px; height: 6px; margin-top: -3px; border-radius: 50%; border: 1px solid var(--tq); animation: vt-ping 2.2s ease-out infinite; }
@keyframes vt-ping { from { transform: scale(1); opacity: .9; } to { transform: scale(3.2); opacity: 0; } }
.vt-nav { display: flex; justify-content: flex-end; align-items: center; gap: 8px; margin-top: 12px; }   /* below the picture, so they never cover it */
/* "Discover the line" under the picture, on the left of the arrows: one link per poster (window tint, PPF), each with its own
   gated destination; js/home.js (supplyTabs) shows the one of the active service and hides both on the coming-soon panels. */
.vt-line { margin-right: auto; }
.vt-line[hidden] { display: none; }
.vt-line svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2; }
.vt-btn { width: 44px; height: 44px; display: grid; place-items: center; cursor: pointer; color: var(--fg); background: var(--panel); border: 1px solid var(--line2); border-radius: var(--r);
  transition: border-color .2s, color .2s, transform .15s; }
.vt-btn:hover { border-color: var(--tq); color: var(--tq); }
.vt-btn:active { transform: scale(.94); }
.vt-btn svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 2; }
.vt-btn.prev svg { transform: scaleX(-1); }
@media (prefers-reduced-motion: reduce) { .vt-slide { transition: none; } .vt-item.is-active .vt-prog { animation: none; transform: scaleY(1); } .vt-stage:hover .vt-slide.is-on img { transform: none; } }
.tag { display: inline-block; font-family: var(--display); font-size: 10px; letter-spacing: .2em; text-transform: uppercase; color: var(--tq); border: 1px solid rgba(43, 213, 230, .5); padding: 5px 8px; border-radius: var(--r); }

/* ---------- beams behind "High end window film" (#lines) ----------
   Vanilla port of the BeamsBackground React component (Iván, Oct 2026: on this section only, merged with the site background, so
   it stands out a little, elegantly). js/beams.js draws slanted beams of light that drift up and pulse. They lie over the original
   background (the fixed #stage: dark gradient, turquoise streaks, honeycomb) without hiding it: translucent, turquoise, slanted
   the same way as the streaks. The layer spans the section (#lines is isolated, the layer sits under its content) and a little
   past its end; its mask fades the beams in over the first 28vh and out over the last 80vh, so they arrive softly after "Our
   products" and dissolve as the PPF section starts. The canvas is sticky: one screen of beams that stays while the section
   scrolls by, and it fades in once drawn. */
#lines { isolation: isolate; }
.beams { position: absolute; left: 0; right: 0; top: 0; bottom: -20vh; z-index: -1; pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 28vh, #000 calc(100% - 80vh), transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0, #000 28vh, #000 calc(100% - 80vh), transparent 100%); }
.beams canvas { position: sticky; top: 0; display: block; width: 100%; height: 100vh; opacity: 0; transition: opacity 1.2s var(--ease); }
.beams.beams-ready canvas { opacity: .85; }
/* the small grey notes of this section sit on the beams' light: one step lighter so they still read */
#lines .note, #lines .gate-note, #lines .layers-note { color: var(--mute); }

/* ---------- tint lines header: "HIGH END / WINDOW FILM", the film layers and the reel (Iván's references, Oct 2026) ----------
   Text (thin line, heavy line, "Three lines. One standard." and the lead), then the four film layers, and the reel. Grid areas:
   phones one column (text, layers, reel); from 880px the reel goes right of the text and the layers below both (2 x 2); from
   1200px text and layers form one column (.lines-left) stretched to the video's height: the text on top flush with the video's
   top edge, the layers at the bottom flush with its bottom edge, so the left column is level with the video. Below 1200px
   .lines-left is display: contents, so its two children take their own grid areas. The reel is shown whole: the box has the clip's own shape
   (1006 x 1612) and the video uses contain, never cropped or stretched. js/home.js (linesReel) loads it near the section, plays
   it on screen and pauses it away; the button pauses it. */
.lines-head { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-areas: "intro" "layers" "reel"; gap: clamp(32px, 4vw, 48px) clamp(32px, 5vw, 88px); margin-bottom: clamp(64px, 9vw, 128px); }
.lines-left { display: contents; }
.lines-intro { grid-area: intro; }
.lines-title { margin: 0 0 clamp(18px, 2.2vw, 30px); font-family: var(--display); text-transform: uppercase; color: #D9DEE3; line-height: .95; }
.lines-title .lt-1 { display: block; font-weight: 300; font-size: clamp(30px, min(4.4vw, 7.2vh), 64px); letter-spacing: .05em; }
.lines-title .lt-2 { display: block; margin-top: .08em; font-weight: 700; font-size: clamp(42px, min(6.4vw, 10.5vh), 96px); letter-spacing: -.01em; }
.lines-sub { margin: 0; font-size: clamp(26px, 3.1vw, 44px); }
.lines-intro .lead { margin-top: 16px; font-size: clamp(16px, 1.25vw, 18px); }
.lines-reel { grid-area: reel; justify-self: center; position: relative; margin: 0; width: min(100%, 420px, calc(72vh * 503 / 806)); aspect-ratio: 503 / 806; overflow: hidden; border-radius: var(--r); background: #000;
  border: 1px solid var(--line2); box-shadow: 0 30px 80px -30px rgba(0, 0, 0, .85), 0 0 60px -18px rgba(43, 213, 230, .35); }
/* the film layers: the construction callouts of the first prototype (line + glowing dot, LAYER 0N, title, description) */
.layers-wrap { grid-area: layers; }
.layers-wrap.rv { opacity: 1; transform: none; }   /* the items animate, not the block */
.layers { list-style: none; margin: 0; padding: 0; display: grid; gap: clamp(10px, 1.6vh, 16px) 28px; }
.layers li { display: flex; align-items: center; gap: 14px; }
.layers li > div { min-width: 0; }
.layers i { position: relative; flex: none; width: clamp(36px, 5.5vw, 88px); height: 1px; background: var(--tq); }
.layers i::before { content: ""; position: absolute; left: -3px; top: -3px; width: 7px; height: 7px; border-radius: 50%; background: var(--tq); box-shadow: 0 0 10px var(--tq); }
.layers b { display: block; margin-bottom: 3px; font-family: var(--display); font-weight: 600; font-size: 12px; letter-spacing: .22em; text-transform: uppercase; color: var(--tq); }
.layers span { display: block; font-weight: 600; font-size: clamp(16px, 1.25vw, 19px); line-height: 1.25; color: var(--fg); }
.layers small { display: block; margin-top: 2px; font-size: clamp(13px, 1vw, 14px); line-height: 1.4; color: var(--mute); }
.layers-note { margin: 14px 0 0; font-size: 12px; color: var(--mute2); }
/* entrance: each line draws out from its dot, then its text rises; one layer after the other */
html.js .layers li > div { opacity: 0; transform: translateY(10px); transition: opacity .6s var(--ease-out), transform .6s var(--ease-out); }
html.js .layers i { clip-path: inset(-5px calc(100% - 5px) -5px -5px); transition: clip-path .7s var(--ease-out); }
html.js .layers-wrap.in li > div { opacity: 1; transform: none; }
html.js .layers-wrap.in i { clip-path: inset(-5px -5px -5px -5px); }
.layers li:nth-child(2) > div, .layers li:nth-child(2) i { transition-delay: .12s; }
.layers li:nth-child(3) > div, .layers li:nth-child(3) i { transition-delay: .24s; }
.layers li:nth-child(4) > div, .layers li:nth-child(4) i { transition-delay: .36s; }
@media (prefers-reduced-motion: reduce) { html.js .layers li > div { opacity: 1; transform: none; } html.js .layers i { clip-path: none; } }
/* From 1200px the callouts come out of the reel: one line per layer, from the video's left edge to the end of that layer's
   title, drawn by the scroll (js/home.js, linksScene). The line grows from the video side (scaleX from the right), a dot rides
   its head and stays glowing against the text when the line arrives; a small dot marks where it leaves the video. Geometry
   (--x end next to the text, --y title center, --w length) is measured in js/home.js (layoutLinks); --d is the progress. */
.layer-links { display: none; position: absolute; inset: 0; pointer-events: none; }
.ll-line { position: absolute; left: var(--x); top: var(--y); width: var(--w); height: 1px; transform-origin: 100% 50%; transform: scaleX(var(--d, 0));
  background: linear-gradient(90deg, var(--tq), rgba(43, 213, 230, .38)); }
.ll-head, .ll-root { position: absolute; top: var(--y); border-radius: 50%; background: var(--tq); opacity: calc(var(--d, 0) * 25); }
.ll-head { left: var(--x); width: 7px; height: 7px; margin: -3px 0 0 -3px; box-shadow: 0 0 10px var(--tq); transform: translateX(calc(var(--w) * (1 - var(--d, 0)))); }
.ll-root { left: calc(var(--x) + var(--w)); width: 5px; height: 5px; margin: -2px 0 0 -2px; background: rgba(43, 213, 230, .75); }
@media (min-width: 1200px) { .layer-links { display: block; } .layers i { display: none; } }
@media (prefers-reduced-motion: reduce) { .ll { --d: 1 !important; } }
@media (min-width: 880px) {
  .lines-head { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "intro reel" "layers layers"; align-items: center; }
  .lines-reel { justify-self: auto; width: auto; height: min(76vh, 640px, 52vw); }
  .layers { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1200px) {
  .lines-head { grid-template-areas: "left reel"; align-items: stretch; }
  .lines-left { grid-area: left; display: flex; flex-direction: column; justify-content: space-between; gap: 28px; }
  .lines-reel { align-self: center; height: min(86vh, 720px, 56vw); }
  .layers { grid-template-columns: 1fr; }
  .layers li:nth-child(1) { padding-left: 54px; }   /* the diagonal of the reference: each layer 18px further out */
  .layers li:nth-child(2) { padding-left: 36px; }
  .layers li:nth-child(3) { padding-left: 18px; }
}
.lines-reel video { display: block; width: 100%; height: 100%; object-fit: contain; }
.reel-btn { position: absolute; right: 12px; bottom: 12px; width: 40px; height: 40px; display: grid; place-items: center; cursor: pointer; opacity: .82; color: var(--fg);
  background: rgba(11, 14, 17, .6); border: 1px solid var(--line2); border-radius: var(--r); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); transition: opacity .2s, border-color .2s; }
.reel-btn:hover { opacity: 1; border-color: var(--tq); }
.reel-btn:focus-visible { outline: 2px solid var(--tq); outline-offset: 2px; }
.reel-btn[hidden] { display: none; }
.reel-btn svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.reel-btn .i-play { display: none; fill: currentColor; stroke: none; }
.reel-btn[aria-pressed="true"] .i-pause { display: none; }
.reel-btn[aria-pressed="true"] .i-play { display: inline; }

/* ---------- tint lines (interactive) ---------- */
.lines { display: grid; grid-template-columns: 1.05fr .95fr; gap: clamp(24px, 4vw, 64px); align-items: start; }
.tabs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.tab { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 16px 14px; text-align: left; cursor: pointer; transition: border-color .2s, background .2s; position: relative; overflow: hidden; }
.tab small { display: block; font-family: var(--display); font-size: 10px; letter-spacing: .2em; text-transform: uppercase; color: var(--mute2); }
.tab strong { display: block; font-family: var(--display); font-size: clamp(13px, 1.2vw, 16px); margin-top: 6px; font-weight: 700; }
.tab[aria-selected="true"] { border-color: var(--tq); background: #10191C; }
.tab[aria-selected="true"] small { color: var(--tq); }
.tab[aria-selected="true"]::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--tq); }
.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 14px; }
.stat { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 18px 16px; }
.stat b { display: block; font-family: var(--display); font-size: clamp(28px, 3.6vw, 48px); font-weight: 700; letter-spacing: -.02em; line-height: 1; color: var(--fg); font-variant-numeric: tabular-nums; }
.stat b i { font-style: normal; font-size: .5em; color: var(--tq); margin-left: 2px; }
.stat span { display: block; margin-top: 8px; font-size: 12.5px; color: var(--mute); line-height: 1.35; }
.stat small { display: block; margin-top: 4px; font-size: 11px; color: var(--mute2); }
.line-meta { margin-top: 18px; display: flex; flex-wrap: wrap; gap: 10px 22px; font-size: 14px; color: var(--mute); }
.line-meta b { color: var(--fg); font-weight: 600; }
.vlt { margin-top: 22px; }
.vlt .label { color: var(--mute); }
.chips { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.chip { font-family: var(--display); font-size: 13px; font-weight: 700; min-width: 54px; min-height: 40px; padding: 0 12px; background: transparent; border: 1px solid var(--line2); border-radius: var(--r); cursor: pointer; transition: all .2s; }
.chip[aria-pressed="true"] { background: var(--tq); color: var(--tq-ink); border-color: var(--tq); }
.chip[hidden] { display: none; }
.gate-row { margin-top: 26px; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.gate-note { font-size: 12.5px; color: var(--mute2); display: inline-flex; gap: 6px; align-items: center; }
.gate-note svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 2; }
.note { margin-top: 18px; font-size: 12.5px; color: var(--mute2); }
/* VLT shade preview: Iván's car photo (dark grey Urus in profile), whole (its own 235:133 shape). Only the glass changes with the VLT: a second copy of the
   photo is cut to the windows by media/vlt-glass.png (made with docs/tools/glass-mask.swift from docs/tools/vlt-windows.txt; it
   keeps only the dark part of the glass, so the reflections on its surface and the paint never change) and gets a brightness and
   contrast filter that js/home.js sets per VLT (renderVlt, --wb and --wc). The photo as it is reads as 20%. A simulation of the
   shade, not a measurement. */
.win { position: sticky; top: calc(var(--nav-h) + 24px); aspect-ratio: 235 / 133; border-radius: var(--r); border: 1px solid var(--line); overflow: hidden; background: #1a1f24; isolation: isolate; }
.win img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.win-glass { -webkit-mask: url("../media/vlt-glass.png") 0 0 / 100% 100% no-repeat; mask: url("../media/vlt-glass.png") 0 0 / 100% 100% no-repeat;
  filter: brightness(var(--wb, 1)) contrast(var(--wc, 1)); transition: filter .6s var(--ease); }
.win .readout { position: absolute; left: 22px; bottom: 22px; font-family: var(--display); font-size: 12px; letter-spacing: .14em; color: #fff; text-shadow: 0 1px 6px rgba(0, 0, 0, .8); background: rgba(11, 14, 17, .55); padding: 8px 10px; border-radius: var(--r); backdrop-filter: blur(6px); }
.win .readout b { color: var(--tq); }
.heat { position: absolute; right: 22px; bottom: 22px; display: flex; gap: 4px; align-items: flex-end; height: 44px; }
.heat i { width: 8px; background: linear-gradient(180deg, #ff9b6b, #ffd36b); border-radius: 2px; height: calc(10px + var(--h) * 34px); opacity: calc(.25 + var(--h) * .75); transition: height .6s var(--ease), opacity .6s; }
@media (max-width: 880px) { .lines { grid-template-columns: 1fr; } .win { position: relative; top: 0; order: -1; } }
@media (max-width: 640px) {
  .win .readout { left: 10px; bottom: 10px; font-size: 10px; padding: 6px 8px; }
  .heat { right: 10px; bottom: 10px; height: 30px; gap: 3px; }
  .heat i { width: 6px; height: calc(7px + var(--h) * 23px); }
}

/* ---------- high end PPF (#ppf, Iván, Oct 2026) ----------
   Built from the window film classes, so it reads as its twin: .lines-head (title, film layers with the callout lines from the
   video, the vertical video frame), then .lines (the approved facts, the gated spec sheet and a wide video frame). The longer
   title "Paint protection film" is set a size smaller than "Window film" so it stays on two lines beside the video. Both video
   frames hold the "Coming soon" chip until the clips arrive. The site background only (the beams are for window film). */
.ppf-title .lt-2 { font-size: clamp(34px, min(5.2vw, 8.6vh), 78px); text-wrap: balance; }
.ppf-stats { grid-template-columns: repeat(2, 1fr); margin-top: 0; }
.ppf-shot { aspect-ratio: 16 / 9; }

/* ---------- gallery: cars finished with NEWTECK ----------
   Vanilla port of the animated-gallery React component (motion/react). The copy comes in group after group, blurred and transparent
   to sharp, 0.2 s apart, once (.in from js/home.js), like the component's blurVariants with staggerChildren .2. Below it a 350vh
   scroll container holds a sticky screen with a wall of photos in 3 columns. js/home.js measures the progress p of the container the
   way the component's useScroll({ target }) does (0 when its top meets the bottom of the screen, 1 when its bottom leaves through the
   top) and writes the component's useTransform ranges as three variables: --ga-rx (the wall leans back 75deg and stands upright at
   p = .5), --ga-sc (1.2 down to 1 between p = .5 and .9) and --ga-t (0 to 1 between p = .5 and 1: the outer columns drift from -10%
   to 2% of their height and the middle one from 15% to 5%). Brand adaptation: dark page, a turquoise glow instead of the purple blob,
   radius 4px. The 12 tiles are numbered empty slots (hex pattern) until the real photos arrive: an <img> inside a .ga-tile covers its
   slot. Reduced motion: no tilt, no drift and no pin, the wall is a still grid. */
.ga { position: relative; scroll-margin-top: var(--nav-h); }
.ga-glow { position: absolute; left: 0; right: 0; top: 0; height: 70vh; z-index: 2; pointer-events: none; mix-blend-mode: screen;
  background: radial-gradient(60% 55% at 50% 20%, rgba(43, 213, 230, .16), rgba(43, 213, 230, 0) 72%); }
.ga-copy { position: relative; z-index: 3; max-width: 980px; margin: 0 auto -48px; padding: clamp(72px, 10vw, 140px) var(--gutter) 0; text-align: center; }
.ga-h { margin: 0; font-family: var(--display); font-weight: 700; font-size: clamp(38px, 5.6vw, 76px); line-height: 1.02; letter-spacing: -.02em; }
.ga-h .ga-a { display: block; }
/* The NEWTECK logo in the title, in place of the word (Iván, Oct 2026): the wordmark image itself (letters and stepped line,
   media/newteck-wordmark.png, never retyped), sized so its letters (rows 2 to 111 of the 204px image) are as tall as the title's
   capitals and stand on the same baseline (1.3em tall, bottom edge .59em under the baseline); the stepped line hangs below like an
   underline, with .15em of air under it before the next line (the margin, offset in vertical-align so the logo does not move).
   The copy block is wide enough for "Made with" and the logo on one line down to about 450px screens; narrower, the logo takes
   its own line. Its alt text keeps the heading readable ("Made with NEWTECK"). */
.ga-logo { display: inline-block; height: 1.3em; width: auto; vertical-align: -.74em; margin: 0 0 .15em .04em; }
.ga-p { margin: 18px auto 0; max-width: 44ch; color: var(--mute); font-size: clamp(15px, 1.25vw, 17px); line-height: 1.55; }
.ga-cta { margin-top: 26px; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 10px 24px; }
.ga-cta .btn svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2; }
.ga-link { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; color: var(--fg); font-size: 14px; font-weight: 600; text-decoration: none; text-underline-offset: 4px; transition: color .2s; }
.ga-link:hover { color: var(--tq); text-decoration: underline; }
.ga-link svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; }
html.js .ga-a { opacity: 0; filter: blur(10px); transition: opacity .8s cubic-bezier(.22, 1, .36, 1), filter .8s cubic-bezier(.22, 1, .36, 1); }
html.js .ga-copy.in .ga-a { opacity: 1; filter: none; }
.ga-h .ga-a + .ga-a { transition-delay: .2s; }
.ga-copy .ga-p { transition-delay: .4s; }
.ga-copy .ga-cta { transition-delay: .6s; }
.ga-scroll { position: relative; height: 350vh; }
.ga-sticky { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; perspective: 1000px; perspective-origin: 50% 0; }
.ga-grid { position: relative; height: 100%; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; padding: 0 8px; align-items: start;
  transform-style: preserve-3d; transform-origin: 50% 50%; transform: rotateX(var(--ga-rx, 0deg)) scale(var(--ga-sc, 1)); }
.ga-col { display: flex; flex-direction: column; gap: 8px; margin-top: -8px; transform: translateY(calc(-10% + 12% * var(--ga-t, 0))); }
.ga-col.ga-mid { margin-top: -50%; transform: translateY(calc(15% - 10% * var(--ga-t, 0))); }
/* Tiles are 16:9 like the component, but never shorter than a quarter of the screen height: in a tall window (a tablet or a phone
   held upright) 16:9 tiles would leave the bottom half of the pinned screen empty. 103% covers the outer columns' upward drift.
   An explicit height and not aspect-ratio + min-height: with those two the browser widens the tile to keep the ratio and it
   overflows its column. 100cqw is the column width (each column is a size container); the first line is the fallback. */
.ga-col { container-type: inline-size; }
.ga-tile { position: relative; height: max(calc((100vw - 32px) * 3 / 16), calc((103vh - 16px) / 4)); height: max(calc(100cqw * 9 / 16), calc((103svh - 16px) / 4)); overflow: hidden; border-radius: var(--r); background: var(--panel); border: 1px solid var(--line); box-shadow: 0 1px 3px rgba(0, 0, 0, .45); }
.ga-tile img { position: absolute; inset: 0; z-index: 1; display: block; width: 100%; height: 100%; object-fit: cover; }
.ga-ph { position: absolute; inset: 0; z-index: 0; display: flex; align-items: flex-end; padding: 10px 12px; font-family: var(--display); font-size: 11px; letter-spacing: .18em; color: var(--mute2);
  background: linear-gradient(135deg, #0F2A2E, var(--panel) 70%); }
.ga-ph::before { z-index: -1; opacity: .12; }   /* the hex pattern (shared with .vt-blank), under the number */
@media (max-width: 640px) { .ga-grid { gap: 6px; padding: 0 6px; } .ga-col { gap: 6px; } .ga-ph { padding: 8px; font-size: 10px; } }
@media (prefers-reduced-motion: reduce) {
  html.js .ga-a { opacity: 1; filter: none; }
  .ga-scroll { height: auto; }
  .ga-sticky { position: relative; height: auto; padding: 72px 0 24px; }
  .ga-grid, .ga-col, .ga-col.ga-mid { transform: none; }
  .ga-col, .ga-col.ga-mid { margin-top: 0; }
}

/* ---------- family manifesto ---------- */
.fam-bg { position: absolute; inset: 0; z-index: 0; display: grid; place-items: center; overflow: hidden; }
/* Crew photo behind the manifesto (media/crew.jpg, Iván, Oct 2026), revealed by the scroll (js/home.js famScene sets --fe and --fp
   on #family). Coming in (--fe 0 to 1, from the section's top edge entering at the bottom of the screen until it pins) the photo
   opens from the center like a cinema curtain (clip-path), fades in and settles from scale 1.16 to 1.04; while the words build
   during the pin (--fp) it keeps a slow push to 1.0 (Ken Burns). Only transform, opacity and clip-path move. A dark veil keeps
   the white and turquoise words readable: heavy on the left behind the text, opening on the right so the group shows, and fading
   into the page color at the bottom. Reduced motion: the photo is simply there. */
.fam-photo { position: absolute; inset: 0; opacity: var(--fe, 0); transform: scale(calc(1.16 - var(--fe, 0) * .12 - var(--fp, 0) * .04)); transform-origin: 50% 45%;
  clip-path: inset(calc((1 - var(--fe, 0)) * 18%) calc((1 - var(--fe, 0)) * 26%)); }
.fam-photo img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 45%; filter: saturate(.85); }
.fam-shade { position: absolute; inset: 0; background:
  linear-gradient(90deg, rgba(11, 14, 17, .9) 0%, rgba(11, 14, 17, .8) 40%, rgba(11, 14, 17, .56) 72%, rgba(11, 14, 17, .5) 100%),
  linear-gradient(0deg, var(--bg) 0%, rgba(11, 14, 17, 0) 28%), linear-gradient(180deg, rgba(11, 14, 17, .55) 0%, rgba(11, 14, 17, 0) 24%); }
@media (max-width: 760px) { .fam-shade { background: linear-gradient(0deg, var(--bg) 0%, rgba(11, 14, 17, .7) 30%, rgba(11, 14, 17, .74) 100%); } }
@media (prefers-reduced-motion: reduce) { .fam-photo { opacity: 1; transform: none; clip-path: none; } }
.sparkles { position: absolute; inset: 0; opacity: 0; transition: opacity 1s ease; pointer-events: auto;
  mask-image: radial-gradient(60% 55% at 50% 50%, #000 30%, transparent 100%); -webkit-mask-image: radial-gradient(60% 55% at 50% 50%, #000 30%, transparent 100%); }
.sparkles.sparkles-ready { opacity: 1; }
.sparkles canvas { display: block; width: 100%; height: 100%; }
.fam-copy { pointer-events: none; } .fam-copy a, .fam-copy button { pointer-events: auto; }
.fam-copy { position: relative; z-index: 1; width: 100%; max-width: var(--max); margin: 0 auto; padding-top: var(--nav-h); }
.fam-copy .big { font-family: var(--display); font-weight: 700; font-size: clamp(36px, 8vw, 118px); line-height: .98; letter-spacing: -.03em; text-transform: uppercase; }
.fam-copy .big + .big { color: var(--tq); }
.fam-copy h2.big { font-size: clamp(22px, 4.8vw, 71px); }   /* the white line 40% smaller than the turquoise one (Iván, Oct 2026) */
.fam-copy .lead { margin-top: 28px; max-width: 52ch; color: var(--fg); opacity: .85; }
/* The manifesto builds with the scroll while the section is pinned (js/home.js, famScene): the white line word by word, then the
   turquoise line, then the paragraph; scrolling back takes them away again. --wo (each word) and --lo (the paragraph) are their
   progress, 0 to 1; the words rise and straighten like the original kinetic type. Reduced motion: everything visible. */
.fam-copy .kin .w, .fam-copy .kin.in .w { opacity: var(--wo, 0); transform: translateY(calc((1 - var(--wo, 0)) * .6em)) rotate(calc((1 - var(--wo, 0)) * 1.5deg)); transition: none; }
.fam-copy .lead.rv, .fam-copy .lead.rv.in { opacity: calc(var(--lo, 0) * .85); transform: translateY(calc((1 - var(--lo, 0)) * 26px)); transition: none; }
@media (prefers-reduced-motion: reduce) { .fam-copy .kin .w, .fam-copy .kin.in .w { opacity: 1; transform: none; } .fam-copy .lead.rv, .fam-copy .lead.rv.in { opacity: .85; transform: none; } }

/* benefits */
.benefits { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.ben { background: var(--bg); padding: 28px 26px; position: relative; transition: background .3s; }
.ben:hover { background: var(--panel); }
.ben svg { width: 26px; height: 26px; stroke: var(--tq); fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.ben .h3 { margin-top: 16px; font-size: 17px; }
.ben p { margin-top: 8px; color: var(--mute); font-size: 14.5px; }
@media (max-width: 900px) { .benefits { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .benefits { grid-template-columns: 1fr; } }
.numbers { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-top: 56px; }
.num b { display: block; font-family: var(--display); font-weight: 700; font-size: clamp(30px, 4.6vw, 60px); line-height: 1; letter-spacing: -.02em; color: var(--tq); }
.num span { display: block; margin-top: 8px; color: var(--mute); font-size: 14px; }
@media (max-width: 760px) { .numbers { grid-template-columns: 1fr 1fr; } }
/* Video frames waiting for their clips (.vid-ph): black, framed like the lines reel, the "Coming soon" chip of the products panels
   in the middle. When a clip arrives, the frame takes the clip's own shape (no crop) and the clip loads near its section, like the
   lines reel. Under the numbers (Iván's mockup, Oct 2026; it replaced the two concept renders): a wide frame the width of the
   content, about 2.75 to 1 like his drawing (16:9 on phones, where a strip that wide would be too thin). */
.vid-ph { position: relative; border-radius: var(--r); overflow: hidden; background: #000;
  border: 1px solid var(--line2); box-shadow: 0 30px 80px -30px rgba(0, 0, 0, .85), 0 0 60px -18px rgba(43, 213, 230, .35); }
.ben-video { margin-top: 56px; aspect-ratio: 11 / 4; }
@media (max-width: 760px) { .ben-video { aspect-ratio: 16 / 9; } }
.fam-cta { margin-top: 48px; display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }

/* ---------- certified partners (#partners) ----------
   Vanilla port of the Team-02 React component (motion/react; Iván, Oct 2026: it replaced "Meet the crew"). A centered head (the
   component's outline Badge is the site's .tag, radius 4px), then 4 cards: 1 column on phones, 2 from 640px, 4 from 1024px, 24px
   apart. Each card: a 320px picture (h-80, cover), then the name and the role. Motion like the component, once, when in view
   (.rv / .in from js/ui.js): the head comes down from -40px, the cards rise from 40px, 0.8 s on the component's ease, 0.1 s apart.
   With real partners a dark layer with the social buttons (square, radius 4px, instead of round) fades in over the picture on
   hover; on touch screens it stays on, over a gradient. Until real shops exist the pictures are empty slots (hex pattern, "Photo
   coming", "Sample" chip), the 4th card is "Your shop here" with the Become a Dealer button, and a line under the grid asks
   "Want to become a certified dealer?" (Iván). Reduced motion: no movement (global .rv rule). */
#partners { --tm-ease: cubic-bezier(.21, .47, .32, .98); }
.tm-head { max-width: 900px; margin: 0 auto clamp(40px, 5vw, 64px); display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
.tm-head .h2 { text-wrap: balance; }   /* one line on desktop; balanced lines on narrow screens */
.tm-head .lead { max-width: 52ch; }
.tm-head.rv { transform: translateY(-40px); transition: opacity .8s var(--tm-ease), transform .8s var(--tm-ease); }
.tm-head.rv.in { transform: none; }
.tm-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; }
@media (min-width: 640px) { .tm-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .tm-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.tm-card { display: flex; flex-direction: column; align-items: flex-start; }
.tm-card.rv { transform: translateY(40px); transition: opacity .8s var(--tm-ease), transform .8s var(--tm-ease); transition-delay: var(--tm-d, 0s); }
.tm-card.rv.in { transform: none; }
.tm-card:nth-child(2) { --tm-d: .1s; }
.tm-card:nth-child(3) { --tm-d: .2s; }
.tm-card:nth-child(4) { --tm-d: .3s; }
.tm-photo { position: relative; width: 100%; height: 20rem; display: grid; place-items: center; overflow: hidden; border-radius: var(--r);
  border: 1px solid var(--line); background: linear-gradient(135deg, #0F2A2E, var(--panel) 70%); }
.tm-photo img { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; object-fit: cover; }
.tm-ph { position: relative; font-family: var(--display); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--mute2); }
.tm-card .sample { position: absolute; top: 12px; right: 12px; z-index: 2; padding: 4px 7px; font-family: var(--display); font-size: 10px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--mute); background: rgba(11, 14, 17, .6); border: 1px solid var(--line2); border-radius: var(--r); }
.tm-over { position: absolute; inset: 0; z-index: 2; display: flex; align-items: flex-end; justify-content: flex-end; gap: 8px; padding: 20px;
  background: rgba(3, 7, 18, .5); opacity: 0; transition: opacity .3s; }
.tm-card:hover .tm-over, .tm-over:focus-within { opacity: 1; }
@media (hover: none) { .tm-over { opacity: 1; background: linear-gradient(0deg, rgba(3, 7, 18, .62), rgba(3, 7, 18, 0) 55%); } }
.tm-soc { display: grid; place-items: center; width: 40px; height: 40px; color: var(--fg); background: var(--bg); border-radius: var(--r); transition: opacity .3s, color .3s; }
.tm-soc:hover { opacity: .8; color: var(--tq); }
.tm-soc svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.tm-name { margin: 24px 0 0; font-family: var(--body); font-weight: 500; font-size: 20px; line-height: 1.3; color: var(--fg); }
.tm-role { margin-top: 4px; font-size: 14px; color: var(--mute); }
.tm-you .tm-photo { border-color: rgba(43, 213, 230, .4); }
.tm-you .btn svg, .tm-cta .btn svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2; }
.tm-cta { margin-top: clamp(40px, 5vw, 64px); display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 14px 24px; text-align: center; }
.tm-cta p { font-family: var(--display); font-weight: 600; font-size: clamp(20px, 2vw, 26px); color: var(--fg); }
/* Houston HQ title in capitals (Iván, Oct 2026: "HOUSTON HEADQUARTERS") */
.h2.hq-title { text-transform: uppercase; }

/* ---------- Houston HQ ---------- */
.photos { display: grid; grid-template-columns: repeat(6, 1fr); grid-auto-rows: 200px; gap: 12px; }
.ph { position: relative; overflow: hidden; border-radius: var(--r); border: 1px solid var(--line); background: var(--panel); }
.ph img { width: 100%; height: 100%; object-fit: cover; filter: saturate(.85) contrast(1.05) brightness(.95); transform: scale(1.01); transition: transform 1.2s var(--ease-out); }
.ph:hover img { transform: scale(1.07); }
.ph figure { margin: 0; height: 100%; }
.ph figcaption { position: absolute; left: 14px; bottom: 12px; font-size: 12px; color: var(--fg); text-shadow: 0 1px 4px rgba(0, 0, 0, .8); background: rgba(11, 14, 17, .45); padding: 4px 8px; border-radius: var(--r); }
.ph.a { grid-column: span 4; grid-row: span 2; } .ph.b { grid-column: span 2; } .ph.c { grid-column: span 2; } .ph.d { grid-column: span 3; } .ph.e { grid-column: span 3; }
@media (max-width: 760px) { .photos { grid-template-columns: 1fr 1fr; grid-auto-rows: 170px; } .ph.a { grid-column: span 2; } .ph.b, .ph.c, .ph.d, .ph.e { grid-column: span 1; } }
.coverage { margin-top: 56px; display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center; }
.cities { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.city { border-top: 2px solid var(--line2); padding-top: 12px; transition: border-color .3s; }
.city:hover, .city.hq { border-color: var(--tq); }
.city b { display: block; font-family: var(--display); font-size: 15px; }
.city span { display: block; color: var(--mute); font-size: 13px; margin-top: 4px; }
.route { position: relative; height: 3px; background: var(--line2); margin-top: 22px; border-radius: 2px; overflow: hidden; }
.route i { position: absolute; left: 0; top: 0; bottom: 0; width: 30%; background: linear-gradient(90deg, transparent, var(--tq)); animation: drive 3.2s var(--ease) infinite; }
@keyframes drive { 0% { transform: translateX(-100%); } 100% { transform: translateX(340%); } }
@media (max-width: 760px) { .coverage { grid-template-columns: 1fr; } .cities { grid-template-columns: 1fr 1fr; } }
.voices { margin-top: 64px; }
.voices .row { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(280px, 1fr); gap: 12px; overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 8px; scrollbar-width: thin; }
.q { scroll-snap-align: start; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 24px; position: relative; clip-path: polygon(0 0, calc(100% - 22px) 0, 100% 22px, 100% 100%, 0 100%); }
.q p { font-size: 17px; line-height: 1.45; }
.q small { display: block; margin-top: 16px; color: var(--mute); font-size: 13px; }
.q .sample { display: inline-block; margin-top: 10px; font-size: 10px; letter-spacing: .18em; text-transform: uppercase; color: var(--mute2); }
.voices .note { max-width: 70ch; }

/* ---------- dealer program ---------- */
.program { display: grid; grid-template-columns: 1fr 1.1fr; gap: clamp(28px, 5vw, 80px); align-items: start; }
.steps { position: relative; list-style: none; margin: 36px 0 0; padding: 0 0 0 34px; }
.steps::before { content: ""; position: absolute; left: 9px; top: 6px; bottom: 6px; width: 2px; background: var(--line2); }
.steps::after { content: ""; position: absolute; left: 9px; top: 6px; width: 2px; height: calc(var(--p, 0) * (100% - 12px)); background: var(--tq); transition: height .2s linear; }
.stp { position: relative; padding: 0 0 36px; }
.stp:last-child { padding-bottom: 0; }
.stp::before { content: ""; position: absolute; left: -34px; top: 6px; width: 20px; height: 20px; background: var(--bg); border: 2px solid var(--line2); clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%); transition: background .3s, border-color .3s; }
.stp.on::before { background: var(--tq); border-color: var(--tq); }
.stp .h3 { font-size: 20px; }
.stp p { color: var(--mute); margin-top: 6px; max-width: 46ch; }
.contact { margin-top: 40px; display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.cbox { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 18px; }
.cbox small { display: block; font-size: 12px; color: var(--mute2); letter-spacing: .08em; text-transform: uppercase; }
.cbox b { display: block; font-family: var(--display); font-size: 18px; margin-top: 8px; letter-spacing: .02em; }
.cbox .btn { margin-top: 12px; }
.cbox a.big { text-decoration: none; }
@media (max-width: 900px) { .program { grid-template-columns: 1fr; } }
@media (max-width: 520px) { .contact { grid-template-columns: 1fr; } }

/* "Become a Dealer" card of the home's dealer section. It replaced the home form (Iván, Oct 2026): the application lives on
   become-a-dealer.html, so the site has one dealer form only. Same panel with the turquoise corner the form had. */
.dl-card { position: relative; align-self: center; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: clamp(24px, 3.4vw, 44px); }
.dl-card::after { content: ""; position: absolute; top: 0; right: 0; width: 40px; height: 40px; background: var(--tq); clip-path: polygon(100% 0, 0 0, 100% 100%); }
.dl-card .h3 { font-size: clamp(22px, 2.2vw, 30px); }
.dl-card p { margin-top: 10px; color: var(--mute); max-width: 44ch; }
.dl-card .btn { margin-top: 26px; min-height: 54px; font-size: 16px; }
.dl-card .btn svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2; }
.dl-card .au-switch { margin-top: 16px; font-size: 14px; }

/* forms (Become a Dealer, sign in) */
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }   /* rows are spaced by each field's own margin */
@media (max-width: 560px) { .grid2 { grid-template-columns: 1fr; } }
.f { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.f label { font-size: 13px; font-weight: 600; color: var(--fg); }
.f input, .f select, .f textarea { width: 100%; background: var(--bg); color: var(--fg); border: 1px solid var(--line2); border-radius: var(--r); padding: 12px 12px; font: inherit; font-size: 15px; transition: border-color .2s, box-shadow .2s; }
.f input::placeholder, .f textarea::placeholder { color: var(--mute2); }
.f input:focus, .f select:focus, .f textarea:focus { outline: none; border-color: var(--tq); box-shadow: 0 0 0 3px rgba(43, 213, 230, .18); }
.f.bad input, .f.bad select, .f.bad textarea { border-color: var(--err); }
.f .err { display: none; font-size: 12.5px; color: var(--err); }
.f.bad .err { display: block; }
.f .help { font-size: 12.5px; color: var(--mute2); }
.f textarea { min-height: 96px; resize: vertical; }
.f.check { flex-direction: row; align-items: flex-start; gap: 10px; }
.f.check input { width: 18px; height: 18px; margin-top: 2px; accent-color: var(--tq); flex: none; }
.f.check label { font-weight: 400; color: var(--mute); }
/* password field with the eye button (Lucide eye / eye-off; js/auth.js flips aria-pressed and the input type) */
.pw { position: relative; }
.pw input { padding-right: 52px; }
.pw-eye { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); width: 40px; height: 40px; padding: 0; display: grid; place-items: center;
  background: transparent; border: 0; border-radius: var(--r); color: var(--mute); cursor: pointer; transition: color .2s, background .2s; }
.pw-eye:hover { color: var(--fg); background: var(--panel2); }
.pw-eye svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.pw-eye .i-eye-off, .pw-eye[aria-pressed="true"] .i-eye { display: none; }
.pw-eye[aria-pressed="true"] .i-eye-off { display: block; }
.hp { position: absolute; left: -9999px; opacity: 0; height: 0; width: 0; }
.msg { border: 1px solid var(--line2); border-left: 3px solid var(--tq); border-radius: var(--r); background: var(--bg); padding: 14px 16px; font-size: 14px; margin-top: 14px; display: none; }
.msg.show { display: block; }
.msg.err { border-left-color: var(--err); }
.msg b { display: block; font-family: var(--display); font-size: 14px; margin-bottom: 4px; }
.form-foot { margin-top: 6px; font-size: 12.5px; color: var(--mute2); }

/* ---------- social ---------- */
.social-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
.post { position: relative; aspect-ratio: 4/5; overflow: hidden; border-radius: var(--r); border: 1px solid var(--line); background: var(--panel); text-decoration: none; display: block; }
.post img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.2s var(--ease-out); }
.post:hover img { transform: scale(1.06); }
.post .net { position: absolute; left: 12px; bottom: 12px; display: inline-flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; color: #fff; background: rgba(11, 14, 17, .6); padding: 6px 9px; border-radius: var(--r); backdrop-filter: blur(6px); }
.post .net svg { width: 15px; height: 15px; fill: currentColor; }
.post.video { background: #000; }
.post.video video { width: 100%; height: 100%; object-fit: cover; }
.handles { margin-top: 22px; display: flex; gap: 12px; flex-wrap: wrap; }
.handle { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; border: 1px solid var(--line2); border-radius: var(--r); padding: 10px 14px; font-weight: 600; font-size: 14px; transition: border-color .2s, background .2s; }
.handle:hover { border-color: var(--tq); background: var(--panel); }
.handle svg { width: 18px; height: 18px; fill: var(--tq); }
@media (max-width: 760px) { .social-grid { grid-template-columns: 1fr 1fr; } }

/* ---------- footer ---------- */
footer { border-top: 1px solid var(--line); padding: 56px var(--gutter) calc(40px + env(safe-area-inset-bottom, 0px)); position: relative; z-index: var(--z-main); background: var(--bg); }
.foot { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 32px; }
.foot p { color: var(--mute); font-size: 14px; margin-top: 12px; max-width: 36ch; }
.foot h4 { font-family: var(--display); font-size: 11px; letter-spacing: .2em; text-transform: uppercase; color: var(--mute2); margin-bottom: 14px; }
.foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.foot a { text-decoration: none; color: var(--mute); font-size: 14px; }
.foot a:hover { color: var(--tq); }
.foot-bottom { margin-top: 40px; padding-top: 20px; border-top: 1px solid var(--line); display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; font-size: 12.5px; color: var(--mute2); }
@media (max-width: 860px) { .foot { grid-template-columns: 1fr 1fr; } }
@media (max-width: 760px) { footer { padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px)); } }

/* ---------- mobile bar ---------- */
.mbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-mbar); display: none; grid-template-columns: 1fr 1fr 1.5fr; gap: 1px; background: var(--line); border-top: 1px solid var(--line); padding-bottom: env(safe-area-inset-bottom, 0px); }
.mbar a { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 54px; background: var(--panel); text-decoration: none; font-size: 13px; font-weight: 600; }
.mbar a svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2; }
.mbar a.p { background: var(--tq); color: var(--tq-ink); }
@media (max-width: 760px) { .mbar { display: grid; } }

/* ---------- liquid metal button (port of LiquidMetalButton, @paper-design/shaders) ---------- */
.lm { position: relative; display: inline-block; perspective: 1000px; vertical-align: middle; }
.lm-stage { position: relative; transform-style: preserve-3d; transition: width .4s ease; }
.lm-layer { position: absolute; inset: 0; transform-style: preserve-3d; transition: transform .15s cubic-bezier(.4, 0, .2, 1); }
.lm-text { display: flex; align-items: center; justify-content: center; gap: 6px; transform: translateZ(20px); z-index: 30; pointer-events: none; font-size: 14px; font-weight: 600; letter-spacing: .02em; color: var(--fg); text-shadow: 0 1px 2px rgba(0, 0, 0, .6); white-space: nowrap; }
.lm-pill { transform: translateZ(10px); z-index: 20; }
.lm-pill > div { position: absolute; inset: 2px; border-radius: 100px; background: linear-gradient(180deg, #1a2126 0%, #05070a 100%); transition: box-shadow .15s; }
.lm.is-pressed .lm-pill > div { box-shadow: inset 0 2px 4px rgba(0, 0, 0, .5), inset 0 1px 2px rgba(0, 0, 0, .35); }
.lm-rim { transform: translateZ(0); z-index: 10; border-radius: 100px; overflow: hidden; background: conic-gradient(from 45deg, #8ee7f0, #1f6f78, #dffbfd, #2BD5E6, #0d3b41, #8ee7f0);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .35), 0 20px 12px rgba(0, 0, 0, .08), 0 9px 9px rgba(0, 0, 0, .12), 0 2px 5px rgba(0, 0, 0, .15), 0 0 24px var(--glow); transition: box-shadow .15s; }
.lm.is-hover .lm-rim { box-shadow: 0 0 0 1px rgba(0, 0, 0, .4), 0 8px 5px rgba(0, 0, 0, .1), 0 4px 4px rgba(0, 0, 0, .15), 0 1px 2px rgba(0, 0, 0, .2), 0 0 34px var(--glow); }
.lm.is-pressed .lm-pill, .lm.is-pressed .lm-rim { transform: translateY(1px) scale(.98); }
.lm-rim canvas { width: 100% !important; height: 100% !important; display: block !important; position: absolute !important; top: 0 !important; left: 0 !important; border-radius: 100px !important; }
.lm-hit { position: absolute; inset: 0; background: transparent; border: 0; cursor: pointer; z-index: 40; transform: translateZ(25px); overflow: hidden; border-radius: 100px; padding: 0; }
.lm-hit:focus-visible { outline: 2px solid var(--tq); outline-offset: 3px; }
.lm-ripple { position: absolute; width: 20px; height: 20px; border-radius: 50%; background: radial-gradient(circle, rgba(255, 255, 255, .45) 0%, rgba(255, 255, 255, 0) 70%); pointer-events: none; animation: lm-ripple .6s ease-out forwards; }
@keyframes lm-ripple { 0% { transform: translate(-50%, -50%) scale(0); opacity: .6; } 100% { transform: translate(-50%, -50%) scale(4); opacity: 0; } }
.lm-measure { position: absolute; visibility: hidden; white-space: nowrap; font-size: 14px; font-weight: 600; letter-spacing: .02em; font-family: var(--body); }
/* paper-shaders runtime styles (moved here from the library's inline injection for CSP) */
@layer paper-shaders { :where([data-paper-shader]) { isolation: isolate; position: relative; } :where([data-paper-shader]) canvas { contain: strict; display: block; position: absolute; inset: 0; z-index: -1; width: 100%; height: 100%; border-radius: inherit; } }

/* ---------- dealer pages: sign in (signin.html) and Become a Dealer (become-a-dealer.html) ----------
   Vanilla port of the LoginPage React component (split screen), adapted to the brand (Iván, Oct 2026: two clear, simple pages, every
   "Sign in" and "Become a Dealer" of the site leads to one of them). Wide screens: two halves, the picture space on the left with
   the back button at its top left, the form side on the right (logo and EN/ES on top, the form centered and 448px wide like the
   component's max-w-md). The picture space stays empty until Iván sends the images: an <img> inside .au-art covers it. Brand
   instead of the component's white panel and blue links: dark side over the site background, turquoise links and button, radius
   4px, a square back button (round shapes are kept for the liquid-metal CTA only). The component's Google and GitHub buttons are
   left out until a real account provider exists. Phones: no picture space, the back button joins the top row. */
.au { min-height: 100vh; min-height: 100svh; display: grid; grid-template-columns: minmax(0, 1fr); }
.au-art { display: none; position: relative; overflow: hidden; background: var(--panel); border-right: 1px solid var(--line); }
.au-art::before { content: ""; position: absolute; inset: 0; opacity: .1;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='97' viewBox='0 0 56 97'%3E%3Cpath d='M28 1 54 16v31L28 62 2 47V16z M28 62v34 M2 47 2 81l26 15 26-15V47' fill='none' stroke='%232BD5E6' stroke-width='1'/%3E%3C/svg%3E"); background-size: 56px 97px;
  -webkit-mask-image: radial-gradient(70% 60% at 50% 50%, #000 20%, transparent 100%); mask-image: radial-gradient(70% 60% at 50% 50%, #000 20%, transparent 100%); }
.au-art img { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; object-fit: cover; }
.au-side { display: flex; flex-direction: column; min-width: 0; padding: 20px var(--gutter) 40px; }
.au-top { display: flex; align-items: center; gap: 12px; }
.au-top .logo { margin-right: auto; }
.au-top .logo img { height: 28px; }
.au-back { flex: none; width: 40px; height: 40px; display: grid; place-items: center; color: var(--fg); background: rgba(11, 14, 17, .55);
  border: 1px solid var(--line2); border-radius: var(--r); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); transition: border-color .2s, color .2s; }
.au-back:hover { border-color: var(--tq); color: var(--tq); }
.au-back svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.au-box { width: 100%; max-width: 448px; margin: auto; padding: 48px 0 16px; }
.au-h { font-family: var(--display); font-weight: 700; font-size: clamp(28px, 3vw, 36px); line-height: 1.1; letter-spacing: -.015em; }
.au-switch { margin-top: 10px; color: var(--mute); font-size: 15px; }
.au-switch a, .au-row a { color: var(--tq); font-weight: 600; text-decoration: none; text-underline-offset: 3px; }
.au-switch a:hover, .au-row a:hover { text-decoration: underline; }
.au-lead { margin-top: 18px; color: var(--mute); font-size: 15px; }
.au-box form { margin-top: 30px; }
.au-row { display: flex; align-items: center; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; margin: 2px 0 22px; font-size: 14px; }
.au-row .f { margin: 0; }
.proto { margin-top: 28px; font-size: 12.5px; color: var(--mute2); border-top: 1px dashed var(--line2); padding-top: 14px; }
@media (min-width: 900px) {
  .au { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .au-art { display: block; }
  .au-back { position: absolute; top: 24px; left: 24px; z-index: 2; }   /* on the picture space, like the component */
}

/* ---------- portal ---------- */
.portal { padding: calc(var(--nav-h) + 40px) var(--gutter) 80px; }
.portal-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; flex-wrap: wrap; border-bottom: 1px solid var(--line); padding-bottom: 24px; }
.status { display: inline-flex; align-items: center; gap: 8px; font-family: var(--display); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; padding: 8px 10px; border-radius: var(--r); border: 1px solid var(--line2); color: var(--mute); }
.status.ok { border-color: var(--tq); color: var(--tq); }
.pgrid { display: grid; grid-template-columns: 2fr 1fr; gap: 14px; margin-top: 28px; }
.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: 24px; position: relative; overflow: hidden; }
.card .h3 { font-size: 18px; }
.card p { color: var(--mute); font-size: 14.5px; margin-top: 8px; }
.card.locked .body { filter: blur(6px); pointer-events: none; user-select: none; opacity: .55; }
.lock { position: absolute; inset: 0; display: grid; place-items: center; text-align: center; padding: 20px; background: linear-gradient(0deg, rgba(11, 14, 17, .75), rgba(11, 14, 17, .35)); }
.lock span { display: inline-flex; gap: 8px; align-items: center; font-weight: 600; font-size: 14px; background: var(--bg); border: 1px solid var(--line2); padding: 10px 14px; border-radius: var(--r); }
.lock svg { width: 16px; height: 16px; stroke: var(--tq); fill: none; stroke-width: 2; }
.card.locked .lock { display: grid; } .card .lock { display: none; }
.pending { grid-column: 1 / -1; display: grid; grid-template-columns: auto 1fr auto; gap: 20px; align-items: center; border-color: rgba(43, 213, 230, .4); }
.pending svg { width: 36px; height: 36px; stroke: var(--tq); fill: none; stroke-width: 1.6; }
.spec-tabs { display: flex; gap: 6px; margin-top: 14px; flex-wrap: wrap; }
.spec-tabs .chip { min-height: 36px; font-size: 12px; }
.table { width: 100%; border-collapse: collapse; margin-top: 14px; font-variant-numeric: tabular-nums; }
.table th, .table td { text-align: left; padding: 10px 8px; font-size: 14px; }
.table th { font-family: var(--display); font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--tq); border-bottom: 1px solid var(--line2); }
.table tbody tr:nth-child(even) { background: rgba(255, 255, 255, .025); }
.kv { display: grid; grid-template-columns: auto 1fr; gap: 8px 16px; margin-top: 12px; font-size: 14px; }
.kv dt { color: var(--mute2); } .kv dd { margin: 0; }
.demo { margin-top: 22px; font-size: 13px; color: var(--mute2); display: flex; gap: 10px; align-items: center; }
.demo input { accent-color: var(--tq); width: 16px; height: 16px; }
@media (max-width: 860px) { .pgrid { grid-template-columns: 1fr; } .pending { grid-template-columns: auto 1fr; } .pending .btn { grid-column: 1 / -1; } }

/* ---------- legal page ---------- */
.legal { padding: calc(var(--nav-h) + 48px) var(--gutter) 80px; max-width: 760px; margin: 0 auto; }
.legal h2 { margin-top: 36px; font-size: 20px; }
.legal p, .legal li { color: var(--mute); margin-top: 10px; font-size: 15px; }

/* ---------- toast ---------- */
.toast { position: fixed; left: 50%; bottom: calc(24px + env(safe-area-inset-bottom, 0px)); transform: translate(-50%, 20px); z-index: var(--z-toast); background: var(--panel); border: 1px solid var(--line2); border-left: 3px solid var(--tq); padding: 12px 16px; border-radius: var(--r); font-size: 14px; opacity: 0; pointer-events: none; transition: opacity .3s, transform .3s; max-width: calc(100vw - 32px); }
.toast.show { opacity: 1; transform: translate(-50%, 0); }
@media (max-width: 760px) { .toast { bottom: calc(72px + env(safe-area-inset-bottom, 0px)); } }

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition-duration: .01ms !important; }
  .kin .w, .rv, .step { opacity: 1; transform: none; }
}

/* ---------- small-screen nav tightening (auth and legal pages have a text button in the nav) ---------- */
@media (max-width: 480px) {
  .nav { gap: 12px; }
  .logo { font-size: 17px; gap: 8px; }
  .nav-right { gap: 8px; }
  .nav-right .btn.sm { padding: 0 10px; font-size: 12.5px; min-height: 36px; }
  .lang-btn { padding: 7px 8px; }
}

/* ---------- preloader ---------- */
html.pre-lock, html.pre-lock body { overflow: hidden; }
#preloader { position: fixed; inset: 0; z-index: 60; background: #05080a; display: grid; place-items: center; cursor: pointer; transition: opacity .6s var(--ease), visibility .6s; }
#preloader[hidden] { display: none; }
html.js #preloader[hidden] { display: grid; }
#preloader.done { opacity: 0; visibility: hidden; pointer-events: none; }
/* The wordmark wipes in from the left with a small settle, then a soft turquoise glow breathes once behind it. Only clip-path,
   transform and filter, no script. Same PNG as the nav logo (docs/tools/logo-clean.swift). */
.pre-logo { position: relative; z-index: 1; display: block; width: min(560px, 78vw); height: auto; margin-top: -8vh;
  clip-path: inset(-40px 100% -40px -40px); transform: scale(.96);   /* the clip box is 40px bigger than the image so the glow is not cut into a rectangle */ filter: drop-shadow(0 0 0 rgba(43, 213, 230, 0));
  animation: pre-wipe .8s cubic-bezier(.65, 0, .25, 1) .1s forwards, pre-glow 1.4s ease-in-out .5s 1 forwards; }
@keyframes pre-wipe { to { clip-path: inset(-40px -40px -40px -40px); transform: scale(1); } }
@keyframes pre-glow { 50% { filter: drop-shadow(0 0 22px rgba(43, 213, 230, .55)); } 100% { filter: drop-shadow(0 0 8px rgba(43, 213, 230, .22)); } }
#preloader::after { content: ""; position: absolute; inset: 0; background: radial-gradient(70% 60% at 50% 50%, transparent 40%, rgba(11, 14, 17, .85) 100%); pointer-events: none; }
#preloader .pre-sparks { pointer-events: none; z-index: 1; }
#preloader .pre-ui { position: absolute; left: 50%; top: calc(50% + 15vh); transform: translateX(-50%); z-index: 2; display: flex; flex-direction: column; align-items: center; gap: 14px; width: min(320px, 70vw); }
.pre-bar { width: 100%; height: 2px; background: rgba(244, 247, 249, .12); overflow: hidden; clip-path: polygon(0 0, calc(100% - 3px) 0, 100% 100%, 3px 100%); }
.pre-bar i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--tq2), var(--tq)); box-shadow: 0 0 12px var(--glow); transition: width 2s linear; }
#preloader.go .pre-bar i { width: 100%; }
.pre-txt { font-family: var(--display); font-size: 11px; letter-spacing: .28em; text-transform: uppercase; color: var(--mute); }
.pre-txt b { color: var(--tq); font-variant-numeric: tabular-nums; min-width: 4ch; display: inline-block; text-align: left; }
@media (prefers-reduced-motion: reduce) { .pre-bar i { transition-duration: 1s; } .pre-logo { animation: none; clip-path: none; transform: none; filter: none; } }

/* ---------- site background: elegant dark pattern ----------
   Vanilla port of the DarkGradientBg React component, used as the original (site-wide) background inside the
   fixed #stage layer on every page. Brand adaptation: the cyan streaks use NEWTECK turquoise, the hotlinked
   texture image is dropped (CSP) and the honeycomb pattern in #stage::after plays the texture role.
   Pure CSS, static, no inline styles. */
.dgb { position: absolute; inset: 0; overflow: hidden; pointer-events: none; contain: paint; }
.dgb-glow { position: absolute; inset: 0;
  background: radial-gradient(100% 100% at 0% 0%, #242B33 0%, rgba(11, 14, 17, 0) 100%);
  -webkit-mask-image: radial-gradient(125% 100% at 0% 0%, #000 0%, rgba(0, 0, 0, .224) 88.2883%, transparent 100%);
  mask-image: radial-gradient(125% 100% at 0% 0%, #000 0%, rgba(0, 0, 0, .224) 88.2883%, transparent 100%); }
.dgb-streak { position: absolute; inset: 0; opacity: .2; transform: skewX(45deg);
  background: linear-gradient(#2BD5E6 0%, rgba(43, 213, 230, 0) 100%); }
.dgb-streak.s1 { -webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,0) 0%, #000 20%, rgba(0,0,0,0) 36%, #000 55%, rgba(0,0,0,.13) 67%, #000 78%, rgba(0,0,0,0) 97%); mask-image: linear-gradient(90deg, rgba(0,0,0,0) 0%, #000 20%, rgba(0,0,0,0) 36%, #000 55%, rgba(0,0,0,.13) 67%, #000 78%, rgba(0,0,0,0) 97%); }
.dgb-streak.s2 { -webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,0) 11%, #000 25%, rgba(0,0,0,.55) 41%, rgba(0,0,0,.13) 67%, #000 78%, rgba(0,0,0,0) 97%); mask-image: linear-gradient(90deg, rgba(0,0,0,0) 11%, #000 25%, rgba(0,0,0,.55) 41%, rgba(0,0,0,.13) 67%, #000 78%, rgba(0,0,0,0) 97%); }
.dgb-streak.s3 { -webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,0) 9%, #000 20%, rgba(0,0,0,.55) 28%, rgba(0,0,0,.424) 40%, #000 48%, rgba(0,0,0,.267) 54%, rgba(0,0,0,.13) 78%, #000 88%, rgba(0,0,0,0) 97%); mask-image: linear-gradient(90deg, rgba(0,0,0,0) 9%, #000 20%, rgba(0,0,0,.55) 28%, rgba(0,0,0,.424) 40%, #000 48%, rgba(0,0,0,.267) 54%, rgba(0,0,0,.13) 78%, #000 88%, rgba(0,0,0,0) 97%); }
.dgb-streak.s4 { -webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,0) 0%, #000 17%, rgba(0,0,0,.55) 26%, #000 35%, rgba(0,0,0,0) 47%, rgba(0,0,0,.13) 69%, #000 79%, rgba(0,0,0,0) 97%); mask-image: linear-gradient(90deg, rgba(0,0,0,0) 0%, #000 17%, rgba(0,0,0,.55) 26%, #000 35%, rgba(0,0,0,0) 47%, rgba(0,0,0,.13) 69%, #000 79%, rgba(0,0,0,0) 97%); }
.dgb-streak.s5 { -webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,0) 0%, #000 20%, rgba(0,0,0,.55) 27%, #000 42%, rgba(0,0,0,0) 48%, rgba(0,0,0,.13) 67%, #000 74%, #000 82%, rgba(0,0,0,.47) 88%, rgba(0,0,0,0) 97%); mask-image: linear-gradient(90deg, rgba(0,0,0,0) 0%, #000 20%, rgba(0,0,0,.55) 27%, #000 42%, rgba(0,0,0,0) 48%, rgba(0,0,0,.13) 67%, #000 74%, #000 82%, rgba(0,0,0,.47) 88%, rgba(0,0,0,0) 97%); }

/* ---------- gradual spacing: hero headline ----------
   Vanilla port of the GradualSpacing component (Iván, Oct 2026; it replaced the TextRoll letter roll). At the hero reveal
   (revealHero, 3.75 s after the hero video starts) each letter slides in from 20px to the left and fades in, 0.5 s each,
   0.04 s after the previous one; js/home.js then puts the plain text back. Built for [data-gs] elements. Kerning and
   ligatures are off so the split letters and the plain text have identical metrics (no jump at the end). Reduced motion:
   nothing is split, the headline simply appears. */
[data-gs] { font-kerning: none; font-variant-ligatures: none; }
.gs-word { display: inline-block; white-space: nowrap; }
.gs-letter { display: inline-block; opacity: 0; transform: translateX(-20px); }
.gs-go .gs-letter { opacity: 1; transform: none; transition: opacity .5s ease-out, transform .5s cubic-bezier(.22, 1, .36, 1); transition-delay: calc(var(--i) * .04s); }

/* ---------- statement text: "Engineered and tested / Delivered across Texas" ----------
   Live text (always sharp, any screen), shared by the "Engineered and tested" title of the van chapter. */
.ct-l1 { margin: 0; font-family: var(--display); font-weight: 700; text-transform: uppercase; letter-spacing: .012em; line-height: 1.06; font-size: clamp(26px, 5.2vw, 78px); color: var(--fg); text-wrap: balance; }
.ct-l2 { margin: .5em 0 0; font-family: var(--display); font-weight: 500; line-height: 1.15; font-size: clamp(18px, 2.8vw, 42px); color: var(--tq); }
