/* ═══════════════════════════════════════════════════════════════
   Notable Paramount
   Design read: B2B manufacturer landing for procurement buyers,
   industrial spec-forward language.
   DESIGN_VARIANCE 7 / MOTION_INTENSITY 5 / VISUAL_DENSITY 6

   Brand kit, and the reasoning behind every value here: BRAND.md.

   SHAPE LOCK   : rounded, on a four-step scale. The product is a sphere,
                  so the page is not all right angles. Every radius comes
                  from --r-1/-2/-3/-pill. No ad-hoc pixel radii.
   COLOR LOCK   : one accent (burnt caramel) across every section, on a
                  uniformly warm neutral family. --danger and --ok are
                  functional states, not second accents.
   THEME LOCK   : one theme, light only. There is no dark mode and no
                  prefers-color-scheme branch anywhere. No section inverts.
   ═══════════════════════════════════════════════════════════════ */

/* Geist + Geist Mono, self-hosted variable woff2. SIL Open Font License. */
@font-face{
  font-family:"Geist";
  src:url("assets/fonts/Geist-Variable.woff2") format("woff2");
  font-weight:100 900; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"Geist Mono";
  src:url("assets/fonts/GeistMono-Variable.woff2") format("woff2");
  font-weight:100 900; font-style:normal; font-display:swap;
}

:root{
  /* ── ground. Milk tea, not paper. --surface is the creamy top of the
        glass, --paper the body of the drink, --sunk a tea-forward pour;
        scrolling the alternating sections moves through those shades.
        Every neutral carries the same warm bias, so a brown sugar pearl
        sits in the page rather than on it. */
  --paper:#F3E6D3;
  --sunk:#E5D2B4;
  --surface:#FFFBF4;

  /* ── ink. The pearl at its darkest, warmed all the way through. */
  --ink:#241A14;
  --ink-2:#5E4C40;
  --ink-3:#685648;

  /* ── lines. -3 exists because a control boundary needs 3:1 under
        WCAG 1.4.11 and a decorative hairline does not. Use -3 only on
        things you can click; it is too dark for a divider. */
  --line:#E3D2B8;
  --line-2:#D3BC9B;
  --line-3:#7C6A59;

  /* ── accent. Brown sugar syrup, and deeper than it used to be: the
        milk tea ground is darker than the old cream one, so the old
        #A6521F fell to 3.8:1 on --sunk. Do not lighten it back. */
  --accent:#8F4416;
  --accent-2:#743612;
  --accent-fg:#FCF7EE;
  --accent-wash:rgba(143,68,22,.07);
  --accent-tap:rgba(143,68,22,.18);   /* touch flash, see -webkit-tap-highlight */

  /* ── the product itself. Read at runtime by the WebGL hero field, so
        the pearls cannot drift away from the palette. */
  --pearl:#3F2314;
  /* Deepened when the ground became milk tea. At #AD6520 the lit end of
     the caramel range sat only 3.4:1 from --paper and the brighter pearls
     dissolved into it; they were tuned against the old pale cream. */
  --pearl-lit:#9A5219;

  /* ── functional state, not accents */
  --danger:#9E2B1B;
  --danger-bg:rgba(158,43,27,.06);
  --ok:#2E6B45;
  --ok-bg:rgba(46,107,69,.07);

  --sans:"Geist",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono:"Geist Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  --shell:1280px;
  --gutter:clamp(20px,4vw,48px);
  --ease:cubic-bezier(.16,1,.3,1);
  /* Two durations, not six. --t-fast for changes that only recolour,
     --t-base for anything that also moves, resizes or casts a shadow.
     Every transition on the page routes through one of these AND through
     --ease; nine of them previously specified no easing at all and quietly
     fell back to the browser default, so a link hover eased on a different
     curve from the button beside it. */
  --t-fast:.16s;
  --t-base:.24s;

  /* ── radius scale. Four steps, nothing off-scale. Buttons are pills
        because a pill is the closest a control gets to a pearl. */
  --r-1:10px;      /* small controls, tags, inline code */
  --r-2:16px;      /* cards, tiles, images */
  --r-3:26px;      /* large panels: hero stage, form frame, photo bands */
  --r-pill:999px;  /* buttons */

  /* ── elevation. Every shadow is tinted from --pearl, never black: a
        black shadow over a warm ground goes grey and dirty.

        There is a reason this scale exists rather than a border alone.
        --surface against --paper is 1.15:1 and the hairline is 1.20:1, so
        a bordered card on this palette is not a card, it is an outline.
        Depth has to come from light, not from contrast the palette cannot
        supply. --edge-hi is the other half of that: a 1px lit top edge,
        which is how a real object catches light from above, and the same
        highlight the pearls carry. */
  --shadow-1:0 1px 2px rgba(63,35,20,.05), 0 4px 14px rgba(63,35,20,.06);
  --shadow-2:0 2px 6px rgba(63,35,20,.07), 0 16px 36px rgba(63,35,20,.10);
  --edge-hi:inset 0 1px 0 rgba(255,255,255,.75);
  --shadow-cta:0 2px 6px rgba(63,35,20,.16), 0 8px 20px rgba(63,35,20,.10);
  --shadow-cta-lift:0 3px 10px rgba(63,35,20,.20), 0 14px 32px rgba(63,35,20,.15);

  /* Animate.css duration. Its 1s default is too slow for a page whose
     motion is otherwise this restrained. */
  --animate-duration:.85s;

  /* z-scale, documented: nothing else gets a z-index */
  --z-header:100;
  --z-nav:90;
}


*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--sans);font-size:1.03rem;line-height:1.6;
  font-feature-settings:"cv11","ss01";
  -webkit-font-smoothing:antialiased;overflow-x:hidden;
}
img{display:block;max-width:100%;height:auto}
a{color:inherit}
/* A touch screen has no hover, so the tap flash is the only immediate
   feedback a tap gets. Make it the accent rather than the UA's grey. */
a,button,summary{-webkit-tap-highlight-color:var(--accent-tap)}
::selection{background:var(--accent);color:var(--accent-fg)}

/* text-wrap does the typesetting a designer would otherwise do by hand:
   balance evens the line lengths of a short heading rather than leaving a
   one-word second line, and pretty stops body copy ending on a stranded
   word. Both degrade to normal wrapping where unsupported. */
h1,h2,h3{margin:0;font-weight:560;letter-spacing:-.022em;line-height:1.08;text-wrap:balance}
h1{font-size:clamp(2.25rem,4.1vw,3.4rem)}
h2{font-size:clamp(1.72rem,2.9vw,2.5rem);line-height:1.1}
h3{font-size:1.12rem;letter-spacing:-.014em;line-height:1.28}
p{margin:0 0 1em;text-wrap:pretty}
p:last-child{margin-bottom:0}

.shell{width:100%;max-width:var(--shell);margin-inline:auto;padding-inline:var(--gutter)}
.shell-narrow{max-width:840px}
.section{padding-block:clamp(64px,8vw,116px)}
.section-sunk{background:var(--sunk)}

.sprite{position:absolute;width:0;height:0;overflow:hidden}
.ico{width:1.15em;height:1.15em;flex:none;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}

.skip-link{position:absolute;left:-9999px;top:0;z-index:200;background:var(--ink);color:var(--paper);padding:12px 20px}
.skip-link:focus{left:0}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* eyebrow: rationed to 3 on this page (hero, capability, quality, enquiry head uses one) */
.eyebrow{
  font-family:var(--mono);font-size:.72rem;font-weight:500;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);
  margin:0 0 18px;
}

/* ─── section heads: always stacked, never a floating right column ─── */
.head{max-width:660px;margin-bottom:clamp(34px,4vw,56px)}
.head-wide{max-width:760px}
.head-sub{margin-top:16px;font-size:1.06rem;color:var(--ink-2);max-width:62ch;text-wrap:balance}

/* ─── buttons ─────────────────────────────────────────────────────
   The primary CTA is a pearl: --pearl fill on the milk tea ground. That
   is not decoration, it is the only fill that actually separates. The
   accent brown was 5.68:1 against --paper and 4.73:1 against --sunk, so
   it read as one more warm shape in a warm palette; --pearl is 11.68:1
   and 9.72:1. Hover pours syrup over it — the fill moves to --accent,
   which is where the accent keeps its role in the button system.

   These are also the only shadowed elements on the page. Kept to the
   primary CTA on purpose: a shadow everywhere is a shadow nowhere. */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  font-family:var(--sans);font-size:.95rem;font-weight:540;line-height:1;
  padding:16px 28px;border:1px solid transparent;border-radius:var(--r-pill);
  text-decoration:none;cursor:pointer;white-space:nowrap;
  transition:background var(--t-base) var(--ease),border-color var(--t-base) var(--ease),
             color var(--t-base) var(--ease),box-shadow var(--t-base) var(--ease),
             transform var(--t-base) var(--ease);
}

.btn-solid{
  background:var(--pearl);color:var(--accent-fg);
  box-shadow:var(--shadow-cta);
}
.btn-solid:hover,
.btn-solid:focus-visible{
  background:var(--accent);
  box-shadow:var(--shadow-cta-lift);
  transform:translateY(-2px);
}
.btn-solid:active{
  background:var(--accent-2);
  box-shadow:var(--shadow-cta);
  transform:translateY(0);
}

/* Secondary reads as a button rather than a ghost: a creamy fill lifts it
   off --paper, and the border carries the 3:1 it needs. */
.btn-line{background:var(--surface);color:var(--ink);border-color:var(--line-3)}
.btn-line:hover,
.btn-line:focus-visible{
  border-color:var(--pearl);background:var(--surface);
  transform:translateY(-2px);
}
.btn-line:active{transform:translateY(0);background:var(--accent-wash)}

.btn-sm{padding:12px 20px;font-size:.88rem}

/* Visible at rest, not only on hover: .link is used inline in prose, where
   colour alone is not an adequate signal and a touch device gets no hover. */
.link{
  display:inline-flex;align-items:center;gap:6px;
  color:var(--accent);text-decoration:none;font-weight:520;
  border-bottom:1px solid color-mix(in srgb,var(--accent) 40%,transparent);
  transition:border-color var(--t-fast) var(--ease);
}
.link:hover,.link:focus-visible{border-bottom-color:var(--accent)}
.link:active{color:var(--accent-2);border-bottom-color:var(--accent-2)}
.link .ico{transition:transform var(--t-base) var(--ease)}
.link:hover .ico{transform:translateX(3px)}

/* ─── masthead: single line, 68px ─── */
.masthead{
  position:sticky;top:0;z-index:var(--z-header);
  background:color-mix(in srgb,var(--paper) 88%,transparent);
  backdrop-filter:blur(12px) saturate(150%);
  border-bottom:1px solid transparent;transition:border-color var(--t-base) var(--ease);
}
.masthead.pinned{border-bottom-color:var(--line)}
.masthead-in{display:flex;align-items:center;justify-content:space-between;gap:24px;height:68px}

/* Padding for the touch target, negative margin so it costs no layout. The
   wordmark was a 26px-tall tap area inside a 68px header. */
.brand{
  display:inline-flex;align-items:center;gap:10px;text-decoration:none;flex:none;
  padding-block:9px;margin-block:-9px;
}
.brand-mark{position:relative;width:22px;height:22px;flex:none}
.brand-mark span{position:absolute;border-radius:50%;background:var(--ink)}
.brand-mark span:nth-child(1){width:9px;height:9px;top:0;left:0}
.brand-mark span:nth-child(2){width:12px;height:12px;bottom:0;right:0}
.brand-mark span:nth-child(3){width:7px;height:7px;bottom:1px;left:1px;background:var(--accent)}
.brand-name{font-size:1.02rem;font-weight:560;letter-spacing:-.02em}

.nav{display:flex;align-items:center;gap:28px}
.nav>a:not(.btn){
  font-size:.92rem;font-weight:460;color:var(--ink-2);text-decoration:none;
  padding:4px 0;border-bottom:1px solid transparent;transition:color var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease);
}
.nav>a:not(.btn):hover{color:var(--ink);border-bottom-color:var(--ink)}

.burger{display:none;width:44px;height:44px;padding:0;background:none;border:0;cursor:pointer;flex-direction:column;justify-content:center;align-items:center;gap:6px}
.burger span{width:20px}
.burger span{display:block;height:1.5px;background:var(--ink);transition:transform .26s var(--ease),opacity .18s}
.burger[aria-expanded="true"] span:nth-child(1){transform:translateY(3.75px) rotate(45deg)}
.burger[aria-expanded="true"] span:nth-child(2){transform:translateY(-3.75px) rotate(-45deg)}

/* ─── 1. hero: full-bleed pearl field, copy set over it ──────────
   The field is the hero, not an illustration beside it. The copy sits
   on a scrim rather than on a panel, so the pearls run edge to edge
   and the section still reads at a glance on a phone. */
.hero{
  position:relative;display:flex;align-items:center;overflow:hidden;
  min-height:clamp(580px,90vh,980px);
  min-height:clamp(580px,88svh,980px);  /* svh, so mobile browser chrome
                                           cannot push the CTA off screen */
  padding-block:clamp(48px,6vw,88px);
}

/* The gradient under the canvas is not a placeholder, it is the floor of
   the scene: the same bright-sky-to-dark-ground ramp the WebGL
   environment is built from, so the canvas fades in over matching ground
   rather than over an empty box. It is also the entire hero visual on a
   browser with no ES module support. */
.hero-stage{
  position:absolute;inset:0;
  background:radial-gradient(96% 78% at 68% 26%,var(--surface),var(--sunk) 52%,var(--paper) 100%);
}
.hero-canvas{
  display:block;width:100%;height:100%;
  opacity:0;transition:opacity 1s var(--ease);
}
.hero-canvas.is-ready{opacity:1}
.hero-stage.is-photo{background:none}
.hero-stage.is-photo img{width:100%;height:100%;object-fit:cover}

/* Readability is guaranteed by the scrim, not by hoping the pearls drift
   somewhere convenient. Horizontal on desktop, vertical on a phone. */
.hero-scrim{
  position:absolute;inset:0;pointer-events:none;
  background:
    /* the field lands softly into the section below rather than stopping */
    linear-gradient(180deg,
      color-mix(in srgb,var(--paper) 0%,transparent) 74%,
      var(--paper) 100%),
    linear-gradient(97deg,
      var(--paper) 0%,
      var(--paper) 32%,
      color-mix(in srgb,var(--paper) 76%,transparent) 50%,
      color-mix(in srgb,var(--paper) 0%,transparent) 76%);
}

.hero-in{position:relative;width:100%}
.hero-copy{max-width:min(720px,56%)}
.hero h1{
  max-width:15ch;
  font-size:clamp(2.8rem,6.2vw,5.4rem);
  /* Tracking tightens as the type grows. Letter-spacing that reads as
     normal at 2.8rem reads as loose at 5.4rem. */
  letter-spacing:-.032em;
}
.lede{margin-top:22px;font-size:clamp(1.08rem,1.45vw,1.28rem);line-height:1.5;color:var(--ink-2);max-width:40ch}
.hero-cta{display:flex;flex-wrap:wrap;gap:12px;margin-top:36px}

/* ─── 2. proof: full-bleed photo with an overlapping statement panel ─── */
.proof{position:relative;padding-bottom:clamp(48px,6vw,80px)}
/* Inset to exactly the shell's content width rather than full bleed, so the
   radius has somewhere to land. A rounded corner sitting on the viewport
   edge reads as a rendering fault, not as a decision. */
.proof-img{
  display:block;margin-inline:auto;box-shadow:var(--shadow-1);
  width:calc(min(100%,var(--shell)) - var(--gutter) * 2);
  aspect-ratio:16/9;max-height:58vh;object-fit:cover;border-radius:var(--r-3);
}
.proof-in{position:relative;margin-top:clamp(-88px,-6vw,-40px)}
.proof-panel{
  max-width:min(760px,100%);
  background:var(--paper);border-radius:var(--r-3);
  padding:26px clamp(24px,2.6vw,34px) 24px;
  box-shadow:var(--shadow-2),var(--edge-hi);
}
.proof-panel h2{max-width:24ch}
.proof-panel p{margin:16px 0 0;color:var(--ink-2);max-width:60ch;font-size:1.03rem}

/* ─── 3. products: bento, 6 cells, exact count ─── */
.bento{display:grid;grid-template-columns:repeat(12,1fr);gap:clamp(8px,1vw,14px)}
.tile{
  position:relative;display:flex;flex-direction:column;overflow:hidden;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-2);
  box-shadow:var(--shadow-1),var(--edge-hi);
  transition:box-shadow var(--t-base) var(--ease),transform var(--t-base) var(--ease),
             border-color var(--t-base) var(--ease);
}
.tile:hover{
  border-color:var(--line-2);
  box-shadow:var(--shadow-2),var(--edge-hi);
  transform:translateY(-3px);
}
.tile-7{grid-column:span 7}
.tile-5{grid-column:span 5}
/* Three products, so three equal cells. The 7/5 pairing was built for a
   four-cell bento; with three it strands one tile on its own row. */
.tile-4{grid-column:span 4}
.tile-accent{background:var(--accent-wash);border-color:color-mix(in srgb,var(--accent) 18%,var(--line))}
.tile:hover{background:color-mix(in srgb,var(--accent) 5%,var(--surface))}
.tile-body{padding:clamp(20px,2.2vw,30px);display:flex;flex-direction:column;flex:1}
.tile-body>p{margin-top:9px;font-size:.94rem;color:var(--ink-2);max-width:52ch}
.tile-img{width:100%;aspect-ratio:16/9;object-fit:cover}
.tile-5 .tile-img,
.tile-4 .tile-img{aspect-ratio:4/3}


.aside{margin-top:28px;font-size:.96rem;color:var(--ink-2)}

/* ─── 4. capability: hairline matrix + mono figures ─── */
.matrix{display:grid;grid-template-columns:1fr 1fr;gap:0 clamp(32px,5vw,72px)}
.matrix>div{padding-block:26px;border-top:1px solid var(--line-2)}
.matrix h3{margin-bottom:8px}
.matrix p{font-size:.95rem;color:var(--ink-2);max-width:48ch}


.wide-shot{
  margin:0 0 clamp(36px,4vw,56px);border:1px solid var(--line);
  border-radius:var(--r-3);overflow:hidden;box-shadow:var(--shadow-1);
}
.wide-shot img{width:100%;aspect-ratio:16/9;max-height:52vh;object-fit:cover}

/* ─── 5. process: horizontal scroll-snap photo track ─── */
.process .head{margin-bottom:clamp(26px,3vw,40px)}
.track{
  display:flex;gap:clamp(8px,1vw,14px);list-style:none;margin:0;
  padding:2px var(--gutter);
  overflow-x:auto;scroll-snap-type:x mandatory;
  /* This scrollbar sits in the middle of the page rather than at its edge,
     so it is part of the composition. Left on auto it renders as OS grey
     against milk tea. */
  scrollbar-width:thin;
  scrollbar-color:var(--line-3) transparent;
}
.track li{
  flex:0 0 clamp(250px,27vw,330px);scroll-snap-align:start;
  background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r-2);overflow:hidden;padding:0 0 28px;
  box-shadow:var(--shadow-1),var(--edge-hi);
  transition:box-shadow var(--t-base) var(--ease),transform var(--t-base) var(--ease);
}
.track li:hover{box-shadow:var(--shadow-2),var(--edge-hi);transform:translateY(-3px)}
.track li img{width:100%;aspect-ratio:4/3;object-fit:cover;margin-bottom:20px}
.track h3,.track p{padding-inline:22px}
.track h3{margin-bottom:8px}
.track p{font-size:.92rem;color:var(--ink-2)}

/* ─── 6. oem: sticky head + list, then mono terms ─── */
.oem-in{display:grid;grid-template-columns:.85fr 1.15fr;gap:clamp(32px,5vw,80px);align-items:start}
.oem-head{position:sticky;top:104px}
.oem-head p{margin-top:16px;color:var(--ink-2);max-width:40ch}
.oem-head .btn{margin-top:26px}
.oem-list>div{padding-block:24px;border-top:1px solid var(--line-2)}
.oem-list>div:first-child{border-top:0;padding-top:0}
.oem-list h3{margin-bottom:7px}
.oem-list p{font-size:.95rem;color:var(--ink-2);max-width:56ch}

.moq{
  margin:clamp(40px,5vw,64px) 0 0;padding-top:26px;border-top:1px solid var(--line-2);
  font-size:clamp(1.02rem,1.4vw,1.15rem);line-height:1.55;color:var(--ink);max-width:62ch;
}

/* ─── 7. quality: credential cards ─── */
/* These were label-and-description pairs beside an empty dashed logo slot, and
   they read as a list of text because that is what they were. A credential is
   the one thing on this page a procurement buyer scans for, so it gets the
   card treatment the bento tiles get: --surface on the --paper ground, the
   elevation scale, and a mark with actual visual weight at the top.

   The mark is a --pearl disc, which is the product. It is also the one place
   on the page besides the CTA that uses a solid dark fill, and that is the
   point: four of them across a row give the section a rhythm you can see from
   the scroll, which a row of 60px dashed outlines never did. */
/* Three across or one, never two. auto-fit was right for four cards and is
   wrong for three: every width that fits two tracks but not three leaves the
   third card alone on its own row, which reads as a bug rather than a layout.
   With three it is an explicit count, and it holds down to 720px — below that
   a third of the content width gives the longest description (HACCP's) five
   lines in a 179px card, so it stacks instead. */
.creds{
  list-style:none;margin:0;padding:0;display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:clamp(16px,1.8vw,22px);
}
@media (max-width:720px){ .creds{grid-template-columns:1fr} }
.cred{
  display:flex;flex-direction:column;align-items:flex-start;
  padding:clamp(22px,2.4vw,30px);
  background:var(--surface);border:1px solid var(--line-2);
  border-radius:var(--r-2);
  box-shadow:var(--shadow-1),var(--edge-hi);
}
/* No hover lift. Nothing here is clickable, and a lift on a static card is a
   promise the card cannot keep. */
/* The real certification marks. Matched on HEIGHT, never width: Halal is a
   portrait roundel and the GMP/HACCP lockups are wide, because each carries the
   KIWACERT badge next to the Standards Malaysia accreditation oval. Forcing a
   common width would squash two of the three.

   object-fit:contain plus a height-only rule means the artwork keeps its own
   aspect ratio at every viewport. These are registered marks — no recolouring,
   masking, cropping or effects. That is also why the old --pearl disc is gone
   rather than being kept as a backing: a mark sits on its own ground. */
.cred-mark{
  display:block;flex:none;
  /* 70px left the accreditation codes baked into the artwork (N0057-G,
     ACB 048, the Halal MS 1500 line) too small to read on a 1x screen, and
     the marks are the thing a procurement buyer scans this section for. */
  height:clamp(80px,6.8vw,88px);width:auto;max-width:100%;
  object-fit:contain;object-position:left center;
  margin-bottom:22px;
}
.creds b{
  display:block;font-family:var(--mono);font-size:.92rem;font-weight:500;
  letter-spacing:.04em;margin-bottom:8px;
}
.cred-note{display:block;font-size:.93rem;line-height:1.5;color:var(--ink-2)}

.pullquote{
  margin:clamp(44px,5vw,68px) 0 0;padding-top:30px;border-top:1px solid var(--line-2);
  font-size:clamp(1.1rem,1.7vw,1.35rem);line-height:1.5;color:var(--ink);max-width:64ch;
  letter-spacing:-.012em;
}

/* ─── 8. faq: accordion ─── */
.faq{border-top:1px solid var(--line-2)}
.faq details{border-bottom:1px solid var(--line)}
.faq summary{
  display:flex;align-items:center;justify-content:space-between;gap:24px;
  list-style:none;cursor:pointer;padding:22px 0;
  font-size:1.04rem;font-weight:500;letter-spacing:-.012em;transition:color var(--t-fast) var(--ease);
}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--accent)}
.faq summary .ico{width:18px;height:18px;color:var(--ink-3);transition:transform var(--t-base) var(--ease),color var(--t-fast) var(--ease)}
.faq details[open] summary .ico{transform:rotate(45deg);color:var(--accent)}
/* Interaction rather than scroll: the answer fades in on open. Uses
   Animate.css's own keyframe by name, so it inherits the library's
   reduced-motion and print guards. */
.faq details[open]>div{animation:fadeIn .42s var(--ease) both}
.faq details>div{padding:0 clamp(24px,6vw,64px) 24px 0}
.faq details>div p{font-size:.97rem;color:var(--ink-2);max-width:68ch}

/* ─── 9. enquiry ─── */
/* Enquiry form. Posts JSON to a Lark Base webhook; see script.js.
   The panel is --surface and the controls are --paper, so a field reads as a
   well sunk into the card rather than a box drawn on it. The palette cannot
   supply that separation with contrast — --surface against --paper is 1.15:1 —
   so the boundary has to come from the border, and WCAG 1.4.11 wants 3:1 on
   anything you can operate. That is what --line-3 is for. */
.form-panel{
  border:1px solid var(--line-2);border-radius:var(--r-3);
  background:var(--surface);
  padding:clamp(24px,3.4vw,46px);
  box-shadow:var(--shadow-1),var(--edge-hi);
}

.form-grid{
  display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(18px,2.2vw,26px) clamp(18px,2.2vw,28px);
}
.field-wide{grid-column:1 / -1}

/* The three specification selects, as one row of three. Without this the form
   has seven half-width fields, and seven is odd: the last one sits alone beside
   an empty cell. Grouping them also says something true — they are one question
   asked three ways. */
.field-group{
  grid-column:1 / -1;display:grid;grid-template-columns:repeat(3,1fr);
  gap:clamp(18px,2.2vw,26px) clamp(18px,2.2vw,28px);
}

.field{display:flex;flex-direction:column;min-width:0}
.field label{
  font-size:.88rem;font-weight:540;letter-spacing:-.006em;
  color:var(--ink);margin-bottom:8px;
}
.req{color:var(--accent)}
.opt{font-weight:400;color:var(--ink-3)}
.hint{margin-top:7px;font-size:.82rem;line-height:1.45;color:var(--ink-3)}

/* 1rem is exactly 16px, and iOS zooms the viewport on focus below that.
   Do not shrink these on the mobile breakpoint. */
.field input,
.field select,
.field textarea{
  font-family:var(--sans);font-size:1rem;line-height:1.4;color:var(--ink);
  background:var(--paper);
  border:1px solid var(--line-3);border-radius:var(--r-2);
  padding:14px 16px;width:100%;
  transition:border-color var(--t-fast) var(--ease),background var(--t-fast) var(--ease),
             box-shadow var(--t-fast) var(--ease);
  -webkit-appearance:none;appearance:none;
}
.field textarea{resize:vertical;min-height:132px}
/* No opacity here. The textarea placeholder is the field's real guidance,
   not decoration, and .85 took --ink-3 on --paper from 5.66:1 to 4.09:1 —
   under AA for the one piece of text a hesitant buyer actually reads. */
.field input::placeholder,
.field textarea::placeholder{color:var(--ink-3);opacity:1}

/* appearance:none strips the native arrow, so it is drawn back in --ink-3. */
.field select{
  padding-right:46px;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23685648' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6l6 -6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 16px center;background-size:18px 18px;
}

.field input:hover,
.field select:hover,
.field textarea:hover{border-color:var(--ink-3)}
.field input:focus,
.field select:focus,
.field textarea:focus{
  background:var(--surface);border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-wash);
}

.field.invalid input,
.field.invalid select,
.field.invalid textarea{border-color:var(--danger);background:var(--danger-bg)}
.field.invalid input:focus,
.field.invalid select:focus,
.field.invalid textarea:focus{box-shadow:0 0 0 3px var(--danger-bg)}

/* [hidden] is display:none in the UA sheet, which any class selector with a
   display of its own silently beats. Restating it here is not redundant. */
.err{margin-top:7px;font-size:.83rem;line-height:1.45;color:var(--danger)}
.err[hidden]{display:none}

/* Off-screen rather than display:none or hidden: a bot that skips hidden
   inputs would walk straight past the trap. */
.trap{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

.field-consent{
  display:grid;grid-template-columns:auto 1fr;gap:0 12px;align-items:start;
  margin-top:clamp(20px,2.4vw,28px);
}
.field-consent input{
  width:24px;height:24px;margin:0;flex:none;   /* WCAG 2.5.8 floor */
  accent-color:var(--accent);cursor:pointer;
  -webkit-appearance:auto;appearance:auto;
}
.field-consent label{
  margin:0;font-weight:400;font-size:.9rem;line-height:1.5;color:var(--ink-2);
  cursor:pointer;padding-block:1px;
}
.field-consent .err{grid-column:2}
.field-consent.invalid input{outline:2px solid var(--danger);outline-offset:2px}

.form-foot{
  display:flex;flex-wrap:wrap;align-items:center;gap:14px 24px;
  margin-top:clamp(24px,3vw,34px);
}
.form-note{margin:0;font-size:.85rem;line-height:1.45;color:var(--ink-3)}

/* Sending. The label change is the real signal; the ring is confirmation
   that something is still in flight. Reduced motion freezes the ring, which
   is why the label carries the message and not the other way round. */
.btn[aria-busy="true"]{
  pointer-events:none;background:var(--accent-2);
  box-shadow:var(--shadow-cta);transform:none;
}
.btn[aria-busy="true"] .ico{display:none}
.btn[aria-busy="true"]::after{
  content:"";width:15px;height:15px;border-radius:50%;
  border:2px solid color-mix(in srgb,var(--accent-fg) 32%,transparent);
  border-top-color:var(--accent-fg);
  animation:np-spin .7s linear infinite;
}
@keyframes np-spin{to{transform:rotate(360deg)}}

/* Empty at rest, so it takes no space until there is something to say. */
.form-status:empty{display:none}
.form-status{
  display:block;margin:22px 0 0;padding:14px 18px;
  border:1px solid var(--danger);border-radius:var(--r-2);
  background:var(--danger-bg);color:var(--ink);
  font-size:.92rem;line-height:1.55;
}
.form-status a{color:var(--danger);font-weight:520}

.form-done{
  padding:clamp(8px,2vw,24px) 0;max-width:56ch;
}
.form-done:focus{outline:none}
.form-done:focus-visible{outline:2px solid var(--accent);outline-offset:6px}
.form-done-ico{
  width:42px;height:42px;stroke-width:1.8;color:var(--ok);
  margin-bottom:18px;
  padding:9px;border-radius:var(--r-pill);background:var(--ok-bg);
  box-sizing:content-box;
}
.form-done h3{font-size:1.32rem;margin-bottom:12px}
.form-done p{color:var(--ink-2);margin:0}
.form-done a{color:var(--accent);font-weight:520}

/* Setup notice, dev only: shown while the webhook URL is still a placeholder. */
.embed-notice{
  display:block;padding:clamp(20px,3vw,32px);margin:0;
  border:1px solid var(--danger);border-radius:var(--r-2);background:var(--danger-bg);
  font-size:1rem;line-height:1.6;color:var(--ink);
}
.embed-notice b{display:block;margin-bottom:8px;font-family:var(--mono);font-size:.8rem;letter-spacing:.06em;text-transform:uppercase;color:var(--danger)}
.embed-notice code{font-family:var(--mono);font-size:.88rem;background:var(--accent-wash);padding:2px 7px;border-radius:var(--r-1);overflow-wrap:anywhere}
.embed-fallback{margin:18px 0 0;font-size:.93rem;color:var(--ink-2)}
.embed-fallback .link{margin-left:4px}

/* The hairline and the top margin belong to the heading now, not the list, so
   the rule reads as the start of the contact block rather than floating above
   a group of links with nothing naming them. */
.rail-head{
  margin:clamp(36px,4vw,56px) 0 18px;padding-top:26px;
  border-top:1px solid var(--line);
}
.rail{
  list-style:none;display:flex;flex-wrap:wrap;gap:16px 40px;
  margin:0;padding:0;
}
.rail li{display:flex;align-items:center;gap:10px;font-size:.95rem;color:var(--ink-2)}
.rail .ico{color:var(--ink-3)}
.rail a{text-decoration:none;color:var(--ink);border-bottom:1px solid var(--line-2);transition:border-color var(--t-fast) var(--ease)}
.rail a:hover{border-bottom-color:var(--accent);color:var(--accent)}

/* ─── footer: same theme, no inversion ─── */
.foot{background:var(--sunk);border-top:1px solid var(--line)}
.foot-in{display:grid;grid-template-columns:1fr 1.5fr;gap:clamp(32px,5vw,72px);padding-block:clamp(48px,5vw,68px)}
/* min-width:0 on both children, or a wide grandchild sets the min-content
   width of a 1fr track and stretches the whole row past the viewport. The
   footer email did exactly that: 57px of horizontal overflow at 375px. */
.foot-in>*{min-width:0}
.foot-brand p{margin-top:16px;font-size:.92rem;color:var(--ink-2);max-width:min(38ch,100%)}
.foot-nav{display:grid;grid-template-columns:repeat(3,1fr);gap:28px}
.foot-nav>div{min-width:0}
.foot-nav h3{font-family:var(--mono);font-size:.68rem;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);margin-bottom:14px}
/* Footer links carry a permanent underline, matching .rail. Without one they
   are --ink-2 text inside a block of --ink-2 text, and on a touch screen
   there is no hover to reveal they are links at all.

   The box stays display:block at full column width, which is the tap target,
   while text-decoration underlines the text runs rather than the box — so
   the target is big and the underline still hugs the label. An earlier pass
   used width:fit-content to get the second half of that, and gave away the
   first half for nothing. */
.foot-nav a{
  display:block;
  font-size:.92rem;color:var(--ink-2);
  padding:5px 0;overflow-wrap:anywhere;
  text-decoration:underline;
  text-decoration-color:var(--line-2);
  text-decoration-thickness:1px;
  text-underline-offset:4px;
  transition:color var(--t-fast) var(--ease),text-decoration-color var(--t-fast) var(--ease),text-decoration-thickness var(--t-fast) var(--ease);
}
.foot-nav a:hover,
.foot-nav a:focus-visible{
  color:var(--accent);
  text-decoration-color:var(--accent);
  text-decoration-thickness:2px;
}
/* :active is the one state a touch device does get, so it carries the press. */
.foot-nav a:active{color:var(--accent-2);text-decoration-color:var(--accent-2)}
.foot-base{display:flex;flex-wrap:wrap;justify-content:space-between;gap:10px;padding-block:20px;border-top:1px solid var(--line);font-size:.85rem;color:var(--ink-3)}
.foot-base p{min-width:0;overflow-wrap:anywhere}
.foot-base p{margin:0}
/* inline-block + padding so the hit area clears the 24px WCAG 2.5.8 floor.
   At .85rem these were 16px tall, which is a hard target on a phone. The
   underline hugs the text run, not the box, so the padding is invisible. */
.foot-base a{
  display:inline-block;padding-block:6px;
  color:var(--ink-3);
  text-decoration:underline;
  text-decoration-color:var(--line-2);
  text-underline-offset:3px;
  transition:color var(--t-fast) var(--ease),text-decoration-color var(--t-fast) var(--ease);
}
.foot-base a:hover,
.foot-base a:focus-visible{color:var(--accent);text-decoration-color:var(--accent)}
.foot-base a:active{color:var(--accent-2)}
.sep{opacity:.5;margin-inline:4px}

/* ─── reveal ──────────────────────────────────────────────────────
   Hidden only when JS can undo it, then handed to Animate.css. script.js
   adds `in` alongside `animate__animated animate__<data-anim>`, so the
   keyframes drive the entrance while `.in` guarantees the end state on its
   own — which is what makes reduced motion, print, and a failed animation
   all resolve to simply visible.

   ONLY THREE ANIMATIONS ARE USED, and the choice is about mobile, not
   taste. A transform does not affect layout but it does extend the
   scrollable overflow area, so Animate.css's horizontal entrances
   (fadeInLeft and friends) produce horizontal scroll on a phone, and
   fadeInUp translates by 100% of the element's OWN HEIGHT — fine on a
   section heading, 600px of temporary scroll height on a tall grid.

     fadeInUp   short text blocks only: headings, asides, pull quotes
     zoomIn     the bento tiles. Scale-only, so it cannot extend the
                scroll area in any direction at all
     fadeIn     anything tall, any photo band, and anything inside an
                overflow scroller such as the process track

   Adding a fourth means checking it against that, not just liking it. */
.js .reveal{opacity:0}
.js .reveal.in{opacity:1}

/* ═══════════ responsive ═══════════ */
@media (max-width:1080px){
  .hero-copy{max-width:min(620px,68%)}

  .tile-7,.tile-5{grid-column:span 6}
  .oem-in{grid-template-columns:1fr}
  .oem-head{position:static}
  }

@media (max-width:860px){
  .nav{
    position:fixed;inset:68px 0 auto;z-index:var(--z-nav);
    flex-direction:column;align-items:stretch;gap:0;
    background:var(--paper);border-bottom:1px solid var(--line);
    padding:6px var(--gutter) 24px;
    transform:translateY(-10px);opacity:0;visibility:hidden;
    transition:opacity var(--t-base) var(--ease),transform var(--t-base) var(--ease),visibility var(--t-base);
  }
  .nav.open{transform:none;opacity:1;visibility:visible}
  .nav>a:not(.btn){padding:15px 0;border-bottom:1px solid var(--line);font-size:1rem}
  .nav>a:not(.btn):hover{border-bottom-color:var(--line)}
  /* Full-width and full-height in the drawer. A btn-sm here was 38px tall
     and sat in a corner, which is the wrong control on a touch screen. */
  .nav-cta{margin-top:20px;align-self:stretch;padding:15px 26px;font-size:.95rem}
  .burger{display:flex}

  /* Let the two pills share one row and grow to equal widths, and stack to
     full width only when they genuinely do not fit — which is at about
     384px. Hard-coding a stacking breakpoint got this wrong in both
     directions: side by side they overrun 335px by ~9px, but forcing a
     column at 612px gave two 547px-wide pills. The cap keeps them from
     stretching the full content width on a tablet. */
  .hero-cta{max-width:430px}
  .hero-cta .btn{flex:1 1 auto}

  /* Phone: the field owns the top of the screen and the copy sits under
     it on a vertical scrim, rather than being squeezed beside it. */
  .hero{align-items:flex-end;min-height:clamp(560px,86vh,820px)}
  .hero{min-height:clamp(560px,84svh,820px)}
  .hero-copy{max-width:none}
  .hero-scrim{
    background:linear-gradient(180deg,
      color-mix(in srgb,var(--paper) 58%,transparent) 0%,
      color-mix(in srgb,var(--paper) 0%,transparent) 14%,
      color-mix(in srgb,var(--paper) 0%,transparent) 24%,
      color-mix(in srgb,var(--paper) 88%,transparent) 38%,
      var(--paper) 48%);
  }
  /* Nothing overlaps on a phone, so the panel drops its backing and its
     padding and just runs on inside the shell gutter. */
  .proof-in{margin-top:0}
  .proof-panel{background:none;border-radius:0;padding:24px 0 0}

  /* Touch widths only need a taller row. The underline and the states are
     already doing the affordance work at every width. */
  .foot-nav a{padding:12px 0}

  /* The rail is the contact block, and on a phone it is the most likely
     thing to be tapped on the whole page. 25px of inline link is not a
     touch target. Underline moves to text-decoration so it still hugs the
     text once the box grows. */
  /* Three across needs about 250px a tile below this; stack instead.
     Two across would leave the third alone. */
  .tile-4{grid-column:span 12}
  .rail li{width:100%}
  .rail a{
    display:inline-block;padding-block:10px;border-bottom:0;
    text-decoration:underline;text-decoration-color:var(--line-2);
    text-underline-offset:3px;
  }
  .rail a:hover{text-decoration-color:var(--accent)}
  /* Single column. Paired short fields survive down to about 720px;
     below that a two-up row gives each field less than 45 characters. The
     three-up select row has to collapse with it, not independently. */
  .form-grid,.field-group{grid-template-columns:1fr}
  .matrix{grid-template-columns:1fr}
  .matrix>div:first-child{border-top-width:1px}
  .foot-in{grid-template-columns:1fr}
}

@media (max-width:620px){
  body{font-size:1rem}
  .tile-7,.tile-5,.tile-4{grid-column:span 12}
  .hero h1{font-size:clamp(2.3rem,9vw,3rem)}

  /* Three nav columns do not fit 335px of content. Two do. Contact spans
     both, because a 157px column breaks the sales address mid-word. */
  .foot-nav{grid-template-columns:repeat(2,1fr);gap:24px 20px}
  .foot-nav>div:last-child{grid-column:1 / -1}

  /* The button is the primary action on the section and should not share a
     row with the fine print at this width. */
  .form-foot{flex-direction:column;align-items:stretch;gap:16px}
  .form-foot .btn{width:100%}
}

/* ═══════════ reduced motion ═══════════ */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
  .js .reveal{opacity:1;transform:none}
  .track{scroll-snap-type:none}
  /* The pearl field draws one static frame and stops its loop in JS.
     Only the fade-in is suppressed here. */
  .hero-canvas{opacity:1;transition:none}
}

@media print{
  .masthead,.burger,.hero-stage,.hero-scrim,.btn,.form-panel,.track{display:none}
  body{background:#fff;color:#000}
  .js .reveal{opacity:1;transform:none}
}
