/* ============================================================
   KAROO KETTLE
   Kraft paper and fire. Field manual, not campaign site.
   Palette and type are client-locked. One easing curve.
   ============================================================ */

:root {
  --page:         #DCCDB4;
  --surface:      #E8DCC7;
  --ink:          #241B12;
  --muted:        #6B5945;
  --line:         #C6B393;
  --accent:       #9A3B14;
  --accent-hover: #7E2F0F;
  --on-accent:    #F6E8D8;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --t-fast: 140ms;
  --t-med: 240ms;

  --font-display: "Fraunces", "Iowan Old Style", Georgia, serif;
  --font-body: "Archivo", "Helvetica Neue", Arial, sans-serif;

  --wrap-max: 1240px;
  --wrap-pad: clamp(20px, 5vw, 64px);
  --section-pad: clamp(88px, 11vw, 150px);
  --nav-h: 68px;
}

/* ---------- Reset ---------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scrollbar-color: var(--muted) var(--page);
}

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.7;
  font-weight: 400;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, ul, dl, dd, figure { margin: 0; }
ul { padding: 0; list-style: none; }
img, video { display: block; max-width: 100%; height: auto; }
button { font: inherit; }

/* Removes the 300ms double-tap zoom delay on touch. Applied to controls only, so
   pinch-zoom on the photographs is untouched. */
a, button, input, textarea, label, summary { touch-action: manipulation; }

/* ---------- Browser surfaces ---------- */

::selection { background: var(--accent); color: var(--on-accent); }

::-webkit-scrollbar { width: 12px; }
::-webkit-scrollbar-track { background: var(--page); }
::-webkit-scrollbar-thumb { background: var(--line); border: 3px solid var(--page); }
::-webkit-scrollbar-thumb:hover { background: var(--muted); }

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

input, textarea { caret-color: var(--accent); }

/* Body links stay ink for AA contrast on kraft; the accent lives in the underline. */
a { color: inherit; text-decoration-color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }

/* ---------- Type roles ---------- */

h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-optical-sizing: auto;
  font-size: clamp(2.1rem, 4.2vw, 3.4rem);
  line-height: 1.05;
  letter-spacing: -0.01em;
  color: var(--accent);
  text-wrap: balance;
}

.statement {
  font-family: var(--font-display);
  font-weight: 400;
  font-optical-sizing: auto;
  line-height: 1.35;
  letter-spacing: -0.005em;
}

/* Captions are ink, not muted: #6B5945 misses AA on the kraft page ground at caption sizes. */
figcaption {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--ink);
  line-height: 1.5;
}

/* ---------- Layout primitives ---------- */

.wrap {
  max-width: var(--wrap-max);
  margin-inline: auto;
  padding-inline: var(--wrap-pad);
}

section { scroll-margin-top: 88px; }

/* Studio frames and line art shot on white: multiply prints them onto the
   page like ink on the kraft, no white plate, no border. Real environments
   (lifestyle photography, video) never take this. */
.img-print { mix-blend-mode: multiply; }

/* The back-to-top marker: in normal flow, no box of its own, so #top always
   resolves to document y=0. Never move this id onto the sticky nav. */
#top { display: block; height: 0; }

.skip-link {
  position: absolute;
  left: 16px;
  top: -72px;
  z-index: 100;
  background: var(--ink);
  color: var(--on-accent);
  padding: 10px 18px;
  font-weight: 600;
  text-decoration: none;
  transition: top var(--t-med) var(--ease);
}
.skip-link:focus-visible { top: 12px; }

/* ---------- Buttons ---------- */

.btn {
  display: inline-block;
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 0.02em;
  line-height: 1;
  padding: 14px 30px;
  border: 0;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.btn:active { transform: scale(0.98); }

@media (hover: hover) and (pointer: fine) {
  .btn:hover { background: var(--accent-hover); }
}

/* ============================================================
   NAV
   ============================================================ */

.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--page);
  border-bottom: 1px solid var(--line);
  transition: box-shadow var(--t-med) var(--ease);
}
.nav.is-scrolled { box-shadow: 0 10px 30px rgba(36, 27, 18, 0.10); }

.nav-inner {
  max-width: var(--wrap-max);
  margin-inline: auto;
  padding-inline: var(--wrap-pad);
  height: var(--nav-h);
  display: flex;
  align-items: center;
  gap: 32px;
}

.lockup {
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  margin-right: auto;
  /* Lifts the hit area from 32px to 44px tall. The nav is 68px, so nothing moves. */
  padding-block: 6px;
}
.lockup-mark { height: 32px; width: auto; }
.lockup-word {
  font-family: var(--font-display);
  font-weight: 600;
  font-optical-sizing: auto;
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  /* --accent-hover, not --accent: at 17px this is body text and accent measures 4.46 on the
     kraft ground, under the 4.5 AA threshold. Same burnt orange family, 5.84. */
  color: var(--accent-hover);
  white-space: nowrap;
}

.nav-links { display: flex; gap: 28px; }
.nav-links a {
  color: var(--ink);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  padding-block: 6px;
  border-bottom: 2px solid transparent;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
/* Text moves to --accent-hover for AA at 15px; the rule underneath stays --accent, which
   clears the 3:1 non-text threshold comfortably. */
.nav-links a.is-current,
.nav-links a[aria-current="page"] { border-bottom-color: var(--accent); color: var(--accent-hover); }

@media (hover: hover) and (pointer: fine) {
  .nav-links a:hover { color: var(--accent-hover); }
}

.nav-order { padding: 11px 24px; }

/* Mobile menu */

.nav-toggle {
  display: none;
  background: none;
  border: 0;
  /* 44x44. This is the only route into navigation on a phone and it measured 42x30,
     under the 44px touch target the rest of the site is held to. The negative margin
     keeps the visual position identical while the hit area grows. */
  width: 44px;
  height: 44px;
  padding: 0;
  margin-inline: -11px;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--ink);
  transition: transform var(--t-med) var(--ease);
}
.nav-toggle span + span { margin-top: 6px; }
.nav-toggle.is-open span:first-child { transform: translateY(4px) rotate(45deg); }
.nav-toggle.is-open span:last-child { transform: translateY(-4px) rotate(-45deg); }

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: var(--page);
  /* Scrolling the menu must not chain through to the page behind it. */
  overscroll-behavior: contain;
  overflow-y: auto;
  padding: max(120px, calc(96px + env(safe-area-inset-top))) var(--wrap-pad)
           max(48px, calc(24px + env(safe-area-inset-bottom)));
  opacity: 0;
  transition: opacity var(--t-med) var(--ease);
}
.mobile-menu.is-open { opacity: 1; }
.mobile-menu nav { display: grid; gap: 8px; }
.mobile-menu a {
  font-family: var(--font-display);
  font-weight: 600;
  font-optical-sizing: auto;
  font-size: 2rem;
  line-height: 1.2;
  color: var(--accent);
  text-decoration: none;
  padding-block: 10px;
  border-bottom: 1px solid var(--line);
  transform: translateY(16px);
  opacity: 0;
  transition: transform var(--t-med) var(--ease), opacity var(--t-med) var(--ease);
}
.mobile-menu.is-open a { transform: none; opacity: 1; }
.mobile-menu.is-open a:nth-child(2) { transition-delay: 40ms; }
.mobile-menu.is-open a:nth-child(3) { transition-delay: 80ms; }
.mobile-menu.is-open a:nth-child(4) { transition-delay: 120ms; }
.mobile-menu.is-open a:nth-child(5) { transition-delay: 160ms; }
.mobile-menu.is-open a:nth-child(6) { transition-delay: 200ms; }

body.menu-open { overflow: hidden; }

/* ============================================================
   HERO
   ============================================================ */

/* The sticky nav sits in normal flow above the hero, so the hero fills
   the rest of the viewport rather than pushing its CTA below the fold. */
.hero {
  position: relative;
  min-height: calc(100svh - var(--nav-h));
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--ink);
}

.hero-video,
.hero-still-wrap,
.hero-still {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The still is the hero's floor, not its fallback. It paints at once at the right crop for
   the width, and the loop fades in over it only once it is genuinely running. Autoplay can be
   refused outright, iOS Low Power Mode being the everyday case, and a frozen black rectangle
   where a photograph should be is the worse failure. Changed 8 Sept, when both loops were
   ungated for phones on Nina's note. */
.hero-video {
  opacity: 0;
  transition: opacity 600ms var(--ease);
}
.hero-video.is-playing { opacity: 1; }

.hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(36, 27, 18, 0.38) 0%,
    rgba(36, 27, 18, 0.12) 42%,
    rgba(36, 27, 18, 0.66) 100%
  );
}

.hero-content {
  position: relative;
  width: 100%;
  max-width: var(--wrap-max);
  margin-inline: auto;
  padding: 120px var(--wrap-pad) clamp(56px, 9vh, 104px);
}

.hero-heading {
  font-family: var(--font-display);
  font-weight: 600;
  font-optical-sizing: auto;
  font-size: clamp(2.15rem, 6vw, 5.1rem);
  line-height: 1.04;
  letter-spacing: -0.015em;
  color: var(--on-accent);
  max-width: 14em;
}

/* Each headline line rises out of its own mask; the padding guards Fraunces descenders. */
.hh-mask { display: block; overflow: hidden; padding-bottom: 0.09em; margin-bottom: -0.09em; }
.hh-line { display: block; }

/* Claim words are staggered in by JS; inline-block so they can carry a transform. */
.claim-line .cw { display: inline-block; }

.hero-actions {
  display: flex;
  align-items: center;
  gap: 28px;
  margin-top: 36px;
}

.btn-hero { font-size: 16px; padding: 16px 38px; }

/* ============================================================
   CLAIM STRIP
   ============================================================ */

.claim {
  background: var(--surface);
  padding-block: var(--section-pad);
}

.claim-grid {
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: clamp(40px, 6vw, 96px);
  align-items: center;
}

.claim-line {
  font-family: var(--font-display);
  font-weight: 400;
  font-optical-sizing: auto;
  font-size: clamp(1.55rem, 2.7vw, 2.35rem);
  line-height: 1.38;
  letter-spacing: -0.005em;
  max-width: 21em;
}
.claim-line strong { color: var(--accent); font-weight: 600; }

.claim-figure img {
  max-width: min(100%, 400px);
  margin-inline: auto;
}

/* Real-environment photographs sit framed on the paper; printed (blended)
   imagery never takes a frame. */
.claim-figure img:not(.img-print),
.mussels-video-frame,
.mussels-side img,
.craft-figure img {
  border: 1px solid var(--line);
}

/* ============================================================
   HOW IT WORKS
   ============================================================ */

.how { padding-block: var(--section-pad); }

.how h2 { margin-bottom: clamp(28px, 4vw, 48px); }

.how-lede {
  font-family: var(--font-display);
  font-weight: 400;
  font-optical-sizing: auto;
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  line-height: 1.4;
  max-width: 25em;
}

.how-explain {
  margin-top: clamp(48px, 7vw, 88px);
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 6fr);
  gap: clamp(32px, 5vw, 80px);
  align-items: center;
}

.how-figure video,
.how-figure img { width: 100%; }

/* The loop and the diagram carry their own studio kraft ground (measured a few
   steps off the page tone), so they sit framed on the paper like the other
   own-ground media. Only one of the pair renders at a time: the loop where
   motion is available, the diagram under 768px and under reduced motion. */
.how-video,
.how-diagram { border: 1px solid var(--line); }
.how-diagram { display: none; }

.how-body p { max-width: 58ch; }

/* The five parts read as one calm column; the real cut kettle stands beside
   them as the plate for the anatomy they describe. */
.parts {
  margin-top: clamp(48px, 7vw, 80px);
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}
.parts-list {
  display: grid;
  gap: 26px;
  max-width: 68ch;
}
.part {
  border-top: 1px solid var(--line);
  padding-top: 22px;
}
.part strong { font-weight: 600; }

.parts-figure { max-width: 460px; }
.parts-figure img { width: 100%; }
.parts-figure figcaption { padding-top: 16px; max-width: 46ch; }

/* Nina's callouts: hairline leaders and small Archivo labels over the plate.
   The wrapper takes no transform and no z-index, so the print blend beneath
   stays live (the standing stacking-context rule). */
.cutaway-plate { position: relative; }
.callout-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.callout-lines line { stroke: var(--ink); stroke-width: 0.35; }
.callout-lines circle { fill: var(--ink); }
.callout {
  position: absolute;
  transform: translateY(-100%);
  padding-bottom: 2px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
}

/* Legend numbers follow the heat's path up the kettle: 01 fire pot to 04
   chimney, the same order the draw-on animation plays. Deep burnt orange, not
   the accent: 12px on the page ground needs the darker step to clear AA. */
.co-num {
  color: var(--accent-hover);
  margin-right: 6px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
}
.co-chimney { left: 70%; top: 7.5%; }
.co-jacket  { left: 1%;  top: 25.5%; }
/* Nina's note: the label's letters sat on the cut wall. There is no single-line
   white on that side, so it wraps to two lines in the true right margin and its
   leader crosses the wall, exactly as the water jacket's does on the left. */
.co-core {
  left: 76.5%;
  top: 47%;
  white-space: normal;
  width: 23%;
  line-height: 1.4;
}
.co-pot     { left: 74%; top: 73.5%; }

/* Below the wide band the plate narrows and the inline legend number pushed
   the water jacket's text onto the cut wall, so the number stacks above its
   label instead, restoring the label widths the plate was mapped for. */
@media (max-width: 1023.98px) {
  .co-num { display: block; margin-bottom: 1px; }
}

/* In the two-column band the plate narrows enough for the long labels to
   overhang, so they shrink and anchor flush inside the plate's right edge. */
@media (min-width: 768px) and (max-width: 1023.98px) {
  .callout { font-size: 10px; letter-spacing: 0.05em; }
  .co-pot  { left: auto; right: 2%; }
}

/* ============================================================
   KEY FEATURES
   ============================================================ */

.features {
  background: var(--surface);
  padding-block: var(--section-pad);
}

.features h2 { margin-bottom: clamp(36px, 5vw, 64px); }

/* The six capability lines as a serif index: the same list voice as the uses
   index, so the two sections speak one language (restructured 1 Sept, Jo). */
.features-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px clamp(32px, 4vw, 64px);
}
.features-grid li {
  border-top: 1px solid var(--line);
  padding-block: 14px 6px;
  font-family: var(--font-display);
  font-weight: 400;
  font-optical-sizing: auto;
  font-size: clamp(1.15rem, 1.5vw, 1.35rem);
  line-height: 1.35;
}

/* Four detail macros, one fixed row inside the wrap. Each plate pairs with its
   own feature line as the caption, hairline between, so text and image are one
   unit and the four square prints share a baseline by construction. The
   scroll-snap strip went 1 Sept on Nina's note: four tiles need no scrollbar,
   and the full-bleed padding read as everything shifted right. */
.detail-strip {
  max-width: var(--wrap-max);
  margin-inline: auto;
  padding: clamp(48px, 6vw, 80px) var(--wrap-pad) 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(16px, 2vw, 28px);
  align-items: start;
}
/* Short labels in the range-caption register (Jo, 1 Sept evening): hairline
   entry, serif name, same voice as the finish names further down the page. */
.detail-strip figcaption {
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
  font-family: var(--font-display);
  font-weight: 400;
  font-optical-sizing: auto;
  font-size: clamp(1.25rem, 1.7vw, 1.6rem);
  line-height: 1.25;
}

/* The wipe cover for each plate. The prints blend (multiply), so their reveal
   animates this surface-coloured sibling, never the img or an ancestor: the
   cover clips away and the plate appears printed in place. JS arms it only
   when the animation will actually run; without JS or with reduced motion it
   never renders. */
.plate { position: relative; }
.plate-cover {
  position: absolute;
  inset: 0;
  background: var(--surface);
  pointer-events: none;
  display: none;
}
.plate-cover.is-armed { display: block; }

/* ============================================================
   KETTLE USES
   ============================================================ */

.uses { padding-block: var(--section-pad); }

.uses h2 { margin-bottom: clamp(36px, 5vw, 64px); }

/* One stage beside the full index of Nina's nine uses, with the seven-frame
   contact strip running the full width beneath both. The index, the strip and
   the stage all drive the same swap, so the whole interaction lives inside a
   single view. */
.uses-lead {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: 18px clamp(32px, 5vw, 80px);
  align-items: end;
}
.uses-gallery { grid-column: 1; grid-row: 1; }
.uses-index   { grid-column: 2; grid-row: 1; }
/* min-width: 0 lets the strip's own overflow-x scroll instead of the fixed-basis
   thumbs forcing the grid track (and the page) wider on small screens. */
.uses-rail    { grid-column: 1 / -1; grid-row: 2; min-width: 0; }

.uses-stage {
  position: relative;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--line);
  overflow: hidden;
}
.uses-stage img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 320ms var(--ease);
}
.uses-stage img.is-active { opacity: 1; }

.uses-rail { display: flex; gap: 12px; }
.uses-thumb {
  flex: 1 1 0;
  padding: 0;
  border: 1px solid var(--line);
  background: none;
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 200ms var(--ease), border-color 200ms var(--ease);
}
.uses-thumb img { width: 100%; display: block; }
.uses-thumb.is-active { opacity: 1; border-color: var(--accent); }

@media (hover: hover) and (pointer: fine) {
  .uses-thumb:hover { opacity: 1; }
}

.uses-index { display: grid; align-content: end; }
.uses-index li {
  border-top: 1px solid var(--line);
  padding-block: 11px;
  font-family: var(--font-display);
  font-weight: 400;
  font-optical-sizing: auto;
  font-size: clamp(1.15rem, 1.5vw, 1.35rem);
  line-height: 1.3;
  transition: color 160ms var(--ease), border-color 160ms var(--ease);
}
.uses-index li[data-use] { cursor: pointer; }
.uses-index li.is-hot { color: var(--accent-hover); border-top-color: var(--accent); }

/* The mussels moment */

.mussels { margin-top: clamp(72px, 10vw, 130px); }

.mussels-grid {
  display: grid;
  grid-template-columns: 8fr 4fr;
  gap: clamp(20px, 3vw, 40px);
  align-items: start;
}

.mussels-video-frame { background: var(--surface); }
.mussels-video { width: 100%; }

.mussels-side { margin-top: clamp(32px, 6vw, 88px); }
.mussels-side figcaption { margin-top: 14px; max-width: 24ch; }

/* The stand band (9 Sept) is the mussels moment's sibling, so it sits close under it
   rather than a full section gap away. Its side column is caption only: the stand macro
   already prints in the feature strip and the page does not repeat imagery. */
.stand-band { margin-top: clamp(28px, 4vw, 56px); }
.stand-band .mussels-side figcaption { margin-top: 0; }

/* ============================================================
   HAND CRAFTED
   Quiet. Read-mode inside a Persuade page. No CTA here.
   ============================================================ */

.craft {
  background: var(--surface);
  padding-block: clamp(112px, 14vw, 190px);
}

.craft h2 { margin-bottom: clamp(24px, 3vw, 40px); }

/* One spread, not three corners: the words and their seal hold the left column,
   the photograph of the making carries the right. */
.craft-grid {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(40px, 7vw, 110px);
  /* The copy column stretches to the figure's height so the stamp can anchor
     to the composition's baseline, level with the photograph's foot. */
  align-items: stretch;
}
.craft-copy { display: flex; flex-direction: column; align-items: flex-start; }

.craft-line {
  font-family: var(--font-display);
  font-weight: 400;
  font-optical-sizing: auto;
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  line-height: 1.4;
  max-width: 17em;
}

/* Ink, pressed at the foot of the column it certifies, level with the
   photograph's base. Nina's note 1 Sept: better placed, a little bigger. */
.craft-stamp {
  width: clamp(168px, 15vw, 204px);
  color: var(--ink);
  margin-top: auto;
  padding-top: clamp(40px, 5vw, 64px);
  /* Centred in the copy column (Jo, 1 Sept evening); the words above stay
     left-set, the seal sits on the column's axis. */
  align-self: center;
}
.craft-stamp svg { display: block; width: 100%; height: auto; }

/* Two frames since 8 Sept, so the column holds a pair rather than a single plate. The second
   drops off the shared baseline, the same offset language the range trio uses. */
.craft-figures {
  max-width: 660px;
  justify-self: end;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(14px, 1.8vw, 24px);
  align-items: start;
}
.craft-figures figure:nth-child(2) { margin-top: clamp(28px, 4vw, 64px); }
.craft-figure img { width: 100%; }

/* ============================================================
   SPECIFICATIONS
   ============================================================ */

.specs { padding-block: var(--section-pad); }

.specs-grid {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}

/* Not sticky: position sticky forms a stacking context, which isolates the
   kit frame's multiply blend and brings its white ground back. */
.specs-head { position: static; }
.specs-head h2 { margin-bottom: clamp(28px, 4vw, 44px); }
.specs-figure figcaption { margin-top: 12px; }

.spec-cluster + .spec-cluster { margin-top: clamp(36px, 5vw, 56px); }

.spec-cluster h3 {
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
  border-top: 1px solid var(--line);
  padding-top: 14px;
  margin-bottom: 18px;
}

.spec-cluster dl { display: grid; gap: 10px; }
.spec-cluster dl > div {
  display: grid;
  grid-template-columns: minmax(120px, 170px) 1fr;
  gap: 24px;
}
.spec-cluster dt { font-weight: 600; font-size: 15px; }
.spec-cluster dd { line-height: 1.55; font-variant-numeric: tabular-nums; }

/* ============================================================
   THE RANGE
   Three finishes, one quiet row. Names stay minimal until the
   client sends their own wording.
   ============================================================ */

.range { padding-block: 0 var(--section-pad); }

.range > .wrap {
  border-top: 1px solid var(--line);
  padding-top: clamp(56px, 8vw, 96px);
}

.range h2 { margin-bottom: clamp(12px, 2vw, 20px); }

.range-lede { max-width: 52ch; }

.range-grid {
  margin-top: clamp(36px, 5vw, 56px);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(24px, 3.5vw, 48px);
  align-items: start;
}
/* The middle frame drops off the shared baseline, the site's offset language,
   so the trio reads as a composed spread rather than a card row. */
.range-grid li:nth-child(2) { margin-top: clamp(36px, 5vw, 72px); }

/* Square since 10 Sept, and printed since the same night: three cut-outs (two studio, the black
   kettle cut from its dune shot) blended onto the kraft with img-print, no frame, no white box.
   They shipped as white cards first and Jo called it live: "the images with the white aren't cut
   out like they were in the past". The feature plates are the precedent. No reveal on the li,
   because a blended image must never sit under an animated ancestor; the caption reveals alone.
   contain, not cover, so a future non-square cut-out degrades safely instead of being sliced. */
.range-frame { overflow: hidden; }
.range-frame img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  display: block;
  transition: transform 600ms var(--ease);
}

/* The finish names take the serif register of the uses index: each caption is
   its own hairline entry, the name large, the note quiet beneath it. */
.range-grid figcaption {
  margin-top: 14px;
  border-top: 1px solid var(--line);
  padding-top: 10px;
}
.range-name {
  display: block;
  font-family: var(--font-display);
  font-weight: 400;
  font-optical-sizing: auto;
  font-size: clamp(1.25rem, 1.7vw, 1.6rem);
  line-height: 1.25;
  transition: color 200ms var(--ease);
}
/* Sampled off the client's own range photographs. These are not brand tokens and must not be
   used anywhere else: they are the products' colours, the way a paint chip is. Burnt orange is
   the brand accent itself, which was chosen off this very leather on 26 Aug. Nina asked for the
   stamps on 8 Sept because the two leathers photograph too close together in hard sun to tell
   apart on a phone. Square, because nothing else on this page is round. */
.range-swatch {
  display: inline-block;
  width: 0.62em;
  height: 0.62em;
  margin-right: 0.42em;
}
.swatch-brown  { background: #6E441F; }
.swatch-orange { background: var(--accent); }
.swatch-black  { background: #24282D; }

.range-note {
  display: block;
  margin-top: 3px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
}

@media (hover: hover) and (pointer: fine) {
  .range-grid li:hover .range-frame img { transform: scale(1.035); }
  .range-grid li:hover .range-name { color: var(--accent); }
}

/* ============================================================
   THE STORY
   Read-mode moment: the only section about people, not the
   object. Type alone. No CTA, no imagery, Nina's words as sent.
   ============================================================ */

.story { padding-block: 0 var(--section-pad); }

/* The hairline marks the turn from argument to story; the gap
   above it is the spec section's own closing padding. */
.story > .wrap {
  border-top: 1px solid var(--line);
  padding-top: var(--section-pad);
}

.story h2 { margin-bottom: clamp(36px, 5vw, 60px); }

/* Retyped 1 Sept (Jo): the story now speaks the page's own voice, a serif lede
   then Archivo body, the same shape How it works uses. The Sentinel keeps its
   serif paragraph as the one remaining stretch of Fraunces prose. */
.sentinel-story {
  font-family: var(--font-display);
  font-weight: 400;
  font-optical-sizing: auto;
  font-size: clamp(1.2rem, 1.7vw, 1.45rem);
  line-height: 1.65;
  letter-spacing: -0.003em;
}

.story-lede {
  font-family: var(--font-display);
  font-weight: 400;
  font-optical-sizing: auto;
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  line-height: 1.4;
  max-width: 25em;
}
.story-prose p:not(.story-lede) { max-width: 58ch; }
.story-prose p + p { margin-top: 1.2em; }
.story-prose .story-lede + p { margin-top: clamp(28px, 4vw, 44px); }

/* ============================================================
   SENTINEL
   ============================================================ */

.sentinel {
  background: var(--surface);
  padding-block: var(--section-pad);
}

.sentinel-grid {
  display: grid;
  grid-template-columns: 4fr 8fr;
  gap: clamp(40px, 6vw, 96px);
  align-items: center;
}

.sentinel-mark img {
  width: clamp(140px, 16vw, 238px);
  margin-inline: auto;
}

.sentinel-body h2 { margin-bottom: clamp(24px, 3vw, 36px); }

.sentinel-story { max-width: 30em; }

/* ============================================================
   ORDER
   ============================================================ */

.order { padding-block: var(--section-pad); }

.order-grid {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}

.order-intro h2 { margin-bottom: clamp(24px, 3vw, 36px); }
.order-intro > p { max-width: 34ch; }

.order-facts { margin-top: clamp(28px, 4vw, 44px); display: grid; gap: 10px; }
.order-facts > div {
  display: grid;
  grid-template-columns: minmax(120px, 170px) 1fr;
  gap: 24px;
  border-top: 1px solid var(--line);
  padding-top: 10px;
}
.order-facts dt { font-weight: 600; font-size: 15px; }

.order-form {
  background: var(--surface);
  border: 1px solid var(--line);
  padding: clamp(28px, 4vw, 48px);
}

.field-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
}

.field { margin: 0 0 20px; }

.field label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 8px;
}

.field input,
.field textarea {
  width: 100%;
  background: var(--page);
  border: 1px solid var(--line);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  padding: 12px 14px;
  transition: border-color var(--t-fast) var(--ease);
}
.field textarea { resize: vertical; min-height: 120px; }

.field input:focus-visible,
.field textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 0;
  border-color: var(--accent);
}

.form-error {
  color: var(--accent);
  font-weight: 500;
  font-size: 15px;
  margin-bottom: 16px;
}

/* Web3Forms honeypot. Never shown, never focusable, never announced: only a bot
   fills it, and Web3Forms discards any submission that arrives with it ticked. */
.hp-field { display: none !important; }

.form-error:focus { outline: 2px solid var(--accent); outline-offset: 4px; }

.btn-submit { padding: 15px 34px; font-size: 16px; }
.btn-submit[disabled] { opacity: 0.6; cursor: progress; }

.order-success {
  grid-column: 2;
  background: var(--surface);
  border: 1px solid var(--line);
  padding: clamp(28px, 4vw, 48px);
}
.order-success h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-optical-sizing: auto;
  font-size: 1.75rem;
  color: var(--accent);
  margin-bottom: 12px;
}
.order-success p { max-width: 44ch; }

/* ============================================================
   FOOTER
   ============================================================ */

.footer {
  background: var(--ink);
  color: var(--page);
  padding-block: clamp(56px, 8vw, 88px);
}

.footer-grid {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: clamp(32px, 5vw, 80px);
  align-items: start;
}

.lockup-footer .lockup-word { color: var(--on-accent); }

.footer p { font-size: 15px; line-height: 2; }

.footer a {
  color: var(--page);
  text-decoration-color: rgba(220, 205, 180, 0.45);
  text-underline-offset: 4px;
  transition: color var(--t-fast) var(--ease);
}
.footer a:focus-visible { outline-color: var(--on-accent); }

@media (hover: hover) and (pointer: fine) {
  .footer a:hover { color: var(--on-accent); }
}


/* ============================================================
   GUIDE PAGE
   ============================================================ */

.guide-warning {
  background: var(--accent);
  color: var(--on-accent);
  padding-block: clamp(28px, 4vw, 44px);
}
.guide-warning p {
  font-family: var(--font-display);
  font-weight: 600;
  font-optical-sizing: auto;
  font-size: clamp(1.3rem, 2.4vw, 1.9rem);
  line-height: 1.3;
}

.guide-header { padding-block: clamp(56px, 8vw, 96px) clamp(24px, 4vw, 40px); }
.guide-header h1 {
  font-family: var(--font-display);
  font-weight: 600;
  font-optical-sizing: auto;
  font-size: clamp(2.2rem, 5vw, 3.8rem);
  line-height: 1.05;
  letter-spacing: -0.01em;
  color: var(--accent);
}

.guide-section { padding-block: clamp(40px, 6vw, 72px); }
.guide-section + .guide-section { border-top: 1px solid var(--line); }

.guide-section h2 { margin-bottom: clamp(28px, 4vw, 44px); font-size: clamp(1.8rem, 3.4vw, 2.6rem); }

.guide-note { max-width: 62ch; margin-bottom: 28px; }

/* A grid of step tiles: the diagram leads each tile at full readable width,
   the number and instruction sit under it. Three across cuts the scroll to a
   third; the numbers keep the reading order unambiguous. */
.steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(28px, 4vw, 44px) clamp(22px, 3vw, 36px);
}

.step {
  display: grid;
  grid-template-areas: "d" "n" "t";
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  gap: 0;
  border-top: 1px solid var(--line);
  padding-top: 16px;
}
.step > p { margin-top: 4px; }

.step-diagram {
  grid-area: d;
  width: 100%;
  height: auto;
  margin-bottom: 14px;
  /* Line art on white, printed onto the page: no plate, no border. */
  mix-blend-mode: multiply;
}

/* Same diagram, standing on its own beside a note rather than inside a step. */
.step-diagram-loose { width: min(100%, 320px); margin-top: 30px; }

.step-num {
  grid-area: n;
  font-family: var(--font-display);
  font-weight: 600;
  font-optical-sizing: auto;
  font-size: 1.35rem;
  line-height: 1;
  color: var(--accent-hover);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.step p { grid-area: t; max-width: 46ch; font-size: 15.5px; line-height: 1.6; }
.step strong { font-weight: 600; }



/* Large-text size so the accent passes contrast while staying loud. */
.step-warning {
  color: var(--accent);
  font-weight: 700;
  font-size: 1.2rem;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.guide-bullets { display: grid; gap: 12px; max-width: 62ch; margin-top: 28px; }
.guide-bullets li {
  padding-left: 22px;
  position: relative;
}
.guide-bullets li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.7em;
  width: 10px;
  height: 1px;
  background: var(--accent);
}

.caution .guide-bullets li { font-weight: 500; }

.guide-back { padding-block: clamp(48px, 7vw, 80px); border-top: 1px solid var(--line); }
.guide-back p { max-width: 40ch; margin-bottom: 24px; }

/* ============================================================
   GALLERY PAGE
   A static photo wall for Mark: three columns of mixed aspects,
   prints on the paper, real environments framed. No motion.
   ============================================================ */

.gallery-header { padding-block: clamp(56px, 8vw, 96px) clamp(28px, 4vw, 48px); }
.gallery-header h1 {
  font-family: var(--font-display);
  font-weight: 600;
  font-optical-sizing: auto;
  font-size: clamp(2.2rem, 5vw, 3.8rem);
  line-height: 1.05;
  letter-spacing: -0.01em;
  color: var(--accent);
}

.gallery { padding-bottom: clamp(64px, 9vw, 104px); }

.gallery-lede {
  max-width: 56ch;
  /* ink, not muted: #6B5945 on the kraft ground is 4.28, under the 4.5 AA bar at this
     size. Same reason figcaption is ink. */
  color: var(--ink);
  margin-top: 14px;
}

/* Section headings inside the wall. Fraunces, but a step down from the page h1 so the
   photographs stay the loudest thing on the page. */
.g-heading {
  font-family: var(--font-display);
  font-weight: 600;
  font-optical-sizing: auto;
  font-size: clamp(1.4rem, 2.4vw, 1.9rem);
  line-height: 1.1;
  color: var(--accent-hover);
  margin: clamp(56px, 7vw, 88px) 0 clamp(20px, 2.4vw, 28px);
  padding-top: clamp(20px, 2.4vw, 28px);
  border-top: 1px solid var(--line);
}

/* A real grid, not CSS multi-column. Columns flowed items 1 to 7 down the first column
   before starting the second, so reading order was wrong and rows never aligned. */
.g-grid {
  display: grid;
  gap: clamp(18px, 2.2vw, 32px);
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* Each block holds one aspect ratio, so every row lines up and nothing is cropped
   meaningfully: the ratio below matches the source files in that group exactly. */
.g-grid-portrait .g-tile img { aspect-ratio: 4 / 5; }
.g-grid-wide     .g-tile img { aspect-ratio: 4 / 3; }
.g-grid-square   .g-tile img { aspect-ratio: 1 / 1; }

.g-tile { margin: 0; }

.g-tile img {
  width: 100%;
  height: auto;
  object-fit: cover;
  display: block;
}

/* The button is the click target and carries no chrome of its own. */
.g-open {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  -webkit-tap-highlight-color: transparent;
}

/* Real environments are framed with a hairline. */
.g-tile img:not(.img-print) { border: 1px solid var(--line); }

/* Studio cut-outs were shot on white and print onto the page (multiply). Grouped together
   on their own surface plate they read as a set instead of floating between photographs. */
.g-tile-plate .g-open { background: var(--surface); }
/* contain, not cover: these are product cut-outs, so a crop would slice the object.
   The sources are square and the cell is square, so nothing letterboxes today; this
   just means a future non-square studio shot degrades safely instead of being cut. */
.g-tile-plate img { mix-blend-mode: multiply; object-fit: contain; }

.g-tile figcaption {
  margin-top: 10px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--ink);
  line-height: 1.4;
}

.g-open { transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease); }
/* Subtle: the tile is a large photograph, so a hard press scale would look like a glitch. */
.g-open:active { transform: scale(0.995); }

@media (hover: hover) and (pointer: fine) {
  .g-open:hover { opacity: 0.86; }
}

@media (max-width: 900px) {
  .g-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .g-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- Lightbox ---------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(36, 27, 18, 0.92);
  display: grid;
  place-items: center;
  overscroll-behavior: contain;
  opacity: 0;
  transition: opacity 200ms var(--ease);
  padding: max(clamp(16px, 4vw, 48px), env(safe-area-inset-top))
           max(clamp(16px, 4vw, 48px), env(safe-area-inset-right))
           max(clamp(16px, 4vw, 48px), env(safe-area-inset-bottom))
           max(clamp(16px, 4vw, 48px), env(safe-area-inset-left));
}
.lightbox[hidden] { display: none; }
.lightbox.is-open .lightbox-inner { transform: scale(1); }

.lightbox.is-open { opacity: 1; }

.lightbox-inner {
  position: relative;
  transform: scale(0.97);
  transition: transform 200ms var(--ease);
  max-width: min(1100px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.lightbox-img {
  max-width: 100%;
  max-height: 78vh;
  width: auto;
  height: auto;
  object-fit: contain;
  background: var(--page);
}

.lightbox-cap {
  color: var(--on-accent);
  font-size: 14px;
  text-align: center;
  margin: 0;
}

.lightbox button {
  background: none;
  border: 1px solid rgba(246, 232, 216, 0.45);
  color: var(--on-accent);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  padding: 9px 18px;
  min-height: 44px;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease);
}
.lightbox button:hover { background: rgba(246, 232, 216, 0.14); }
.lightbox button { transition: background-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease); }
.lightbox-close:active { transform: scale(0.97); }
/* These two already carry a translate, so the press scale has to compose with it. */
.lightbox-prev:active, .lightbox-next:active { transform: translateY(-50%) scale(0.97); }
.lightbox :focus-visible { outline: 2px solid var(--on-accent); outline-offset: 3px; }

.lightbox-close { position: absolute; top: 0; right: 0; }
.lightbox-prev, .lightbox-next { position: absolute; top: 50%; transform: translateY(-50%); }
.lightbox-prev { left: 0; }
.lightbox-next { right: 0; }

@media (max-width: 700px) {
  .lightbox-inner { gap: 10px; }
  .lightbox-close { position: static; }
  .lightbox-prev, .lightbox-next { position: static; transform: none; }
  .lightbox-inner { flex-wrap: wrap; }
  .lightbox-img { max-height: 62vh; }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */

@media (max-width: 1024px) {
  .uses-lead { grid-template-columns: minmax(0, 6fr) minmax(0, 6fr); }
}

@media (max-width: 1023.98px) {
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .nav-links { display: none; }
  .nav-toggle { display: flex; }
  .nav-order { display: none; }
  .mobile-order { color: var(--accent); }

  /* The 5fr text column gets too narrow for the heading here, so the spread
     stacks: words, seal, then the photograph. The stamp's baseline anchor only
     means something beside the figure, so it reverts to a plain gap here. */
  .craft-grid { grid-template-columns: 1fr; gap: clamp(44px, 7vw, 64px); }
  .craft-copy { display: block; }
  .craft-stamp { margin-top: 32px; padding-top: 0; width: 160px; margin-inline: auto; }
  .craft-figures { justify-self: start; max-width: 100%; }
}

/* 767.98 keeps the CSS boundary aligned with main.js's (min-width: 768px):
   at exactly 768 the video both loads and shows. */
@media (max-width: 767.98px) {

  .steps { grid-template-columns: 1fr; gap: 20px; }
  .step {
    grid-template-areas: "d n" "d t";
    grid-template-columns: 138px minmax(0, 1fr);
    gap: 4px 16px;
    align-content: start;
    padding-top: 14px;
  }
  .step-diagram { margin-bottom: 0; }
  .step-warning { white-space: normal; }

  section { scroll-margin-top: 76px; }

  :root { --nav-h: 60px; }

  .hero-content { padding-bottom: 48px; }
  .hero-actions { margin-top: 28px; gap: 20px; }

  .claim-grid { grid-template-columns: 1fr; }
  .claim-figure img { margin-inline: 0; max-width: min(100%, 320px); }

  .how-lede { margin-left: 0; margin-right: 0; }

  .parts { grid-template-columns: 1fr; gap: 40px; }
  .parts-list { gap: 32px; }
  .parts-figure { max-width: 420px; }

  .features-grid { grid-template-columns: 1fr; gap: 22px; }

  .uses-lead { grid-template-columns: 1fr; gap: 20px; }
  .uses-gallery, .uses-rail, .uses-index { grid-column: auto; grid-row: auto; }
  .uses-index { margin-top: 8px; }

  /* Seven equal-split thumbs fall under touch size here, so the strip scrolls,
     the same idiom as the feature detail strip. */
  .uses-rail { overflow-x: auto; scroll-snap-type: x proximity; scrollbar-width: thin; padding-bottom: 6px; }
  .uses-thumb { flex: 0 0 96px; scroll-snap-align: start; }

  .how-explain { grid-template-columns: 1fr; gap: 24px; }

  .mussels-grid { grid-template-columns: 1fr; }
  .mussels-side { margin-top: 0; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; align-items: end; }

  .craft-grid { gap: 40px; }
  .craft-stamp { width: 120px; margin-top: 28px; }
  /* Stacked on a phone: side by side these two would land near 150px each, which is not
     seeing a photograph. */
  .craft-figures { max-width: 100%; grid-template-columns: 1fr; gap: clamp(20px, 5vw, 32px); }
  .craft-figures figure:nth-child(2) { margin-top: 0; }


  .specs-grid { grid-template-columns: 1fr; }

  .range-grid { grid-template-columns: 1fr; gap: 36px; }
  .range-grid li:nth-child(2) { margin-top: 0; }
  .detail-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .sentinel-grid { grid-template-columns: 1fr; }
  .sentinel-mark img { width: 120px; margin-inline: 0; }

  .order-grid { grid-template-columns: 1fr; }
  .order-success { grid-column: 1; }

  .footer-grid { grid-template-columns: 1fr; gap: 28px; }
}

@media (max-width: 560px) {
  .field-row { grid-template-columns: 1fr; gap: 0; }
  .mussels-side { grid-template-columns: 1fr; }
  .callout { font-size: 10px; letter-spacing: 0.05em; }
}

/* ============================================================
   MOTION
   Reveals are driven by GSAP in main.js. Without JS, or with
   reduced motion, everything renders statically visible.
   ============================================================ */

/* Lenis owns the scroll while active (it stamps .lenis on <html>).
   Without this override the browser's own smooth scrolling re-animates
   every frame Lenis writes, and the page drifts behind the wheel. The
   override binds to the bare .lenis class, not .lenis-smooth, because
   Lenis only adds the latter mid-gesture and the first frames of every
   gesture would still fight. CSS scroll-behavior stays as the no-JS
   fallback only. */
html.lenis { scroll-behavior: auto !important; }
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-stopped { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

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

  .reveal { opacity: 1 !important; transform: none !important; }

  /* Neither loop arms under reduced motion, at any width, so the stills take both slots:
     the hero photograph and the blue-water diagram, which is the same information held still.
     Since 8 Sept this is the only condition that swaps them; width no longer does. */
  .hero-video { display: none; }
  .how-video { display: none; }
  .how-diagram { display: block; }
}
