/* ═══════════════════════════════════════════════════════════════════════
   Packwide design system.

   Rebuilt on the architecture Packhelp uses, because it is the right
   architecture for this subject: physical packaging photographed on a
   near-neutral ground, one saturated blue reserved for action, generous
   rounding, and small tight type that lets the product hold the frame.

   ── What carries the rhythm ────────────────────────────────────────────
   Not section backgrounds. Ground-to-white measures 1.06:1, so alternating
   section grounds is invisible and was never doing the work, the page ran
   16 screens partly because it kept trying. Rhythm comes from rounded
   blocks sitting ON one continuous ground, which is why --r-block is 16px
   and why the section scopes below are surfaces rather than page grounds.

   ── The one colour law ────────────────────────────────────────────────
   Cobalt means Packwide acting, and nothing else. #2757FF sits on light
   grounds only (5.08:1 on ground, 5.39:1 on white). On ink it measures
   3.74:1 and fails AA for text, so --accent is redefined inside .on-ink
   rather than typed by hand anywhere.

   ── Two values deliberately not copied ─────────────────────────────────
   Packhelp's muted grey #86868B measures 3.41:1 on their own ground and
   fails AA; --fg-dim is the nearest passing value instead. Their body
   line-height is 1.16, below the 1.3 floor; body stays at 1.5.
   ═══════════════════════════════════════════════════════════════════════ */
:root {
  /* ---- Raw palette ---- */
  --ink:        #00061A;   /* text, and the one dark ground */
  --cobalt:      #2757FF;   /* Packwide acting, light grounds only */
  --cobalt-lift: #7C97FF;   /* the same role on a dark ground */
  --cobalt-deep: #1C46E8;   /* hover, and only hover */
  --ground-raw: #F8F8F8;   /* the single page ground */
  --white:      #FFFFFF;

  /* ---- Semantic layer ---- */
  --page:       #EDEDEE;   /* the ground the box sits on */
  --ground:     var(--ground-raw);
  --surface:    var(--white);      /* blocks sitting on the ground */
  --surface-2:  #F2F2F2;           /* a block on a white block */
  --fg:         var(--ink);
  --fg-dim:     #6B6B6F;   /* 5.00:1 on ground. Packhelp's own grey fails */
  --fg-faint:   #5D5D61;   /* 6.17:1; still a third tier, still passing */
  --rule:       #E4E4E6;
  --rule-soft:  #EFEFF1;
  --accent:     var(--cobalt);
  --accent-ink: var(--white);
  --ok:         #1F6A4C;
  --warn:       #8A5A0B;

  /* ---- Type ----
     Schibsted Grotesk stands in for ABCFavorit, which is licensed. Same
     neo-grotesque register: mixed case, weight 500 for display, tight
     negative tracking that only works at size. */
  --font: "Schibsted Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
  --t-micro:   12px;
  --t-caption: 13px;
  --t-label:   15px;
  --t-sub:     17px;
  --t-body:    20px;
  --t-head:    48px;
  --t-display: 72px;

  --t-body-f:    clamp(16px, 0.5vw + 14px, 20px);
  --t-head-f:    clamp(28px, 2.6vw + 16px, 48px);
  --t-display-f: clamp(38px, 4.4vw + 16px, 72px);

  --lh-body:    1.5;    /* not Packhelp's 1.16 */
  --lh-display: 1.04;
  --lh-head:    1.08;
  --ls-display: -0.045em;
  --ls-head:    -0.02em;

  /* ---- Spacing ---- */
  --sp-xs:  6px;
  --sp-sm:  12px;
  --sp-md:  20px;
  --sp-lg:  32px;
  --sp-xl:  56px;
  --sp-2xl: 88px;
  --sp-3xl: 120px;
  --sp-section: clamp(56px, 6vw, 104px);

  --card-pad:  clamp(22px, 2.4vw, 40px);
  --gap:       16px;
  --gutter:    clamp(16px, 3vw, 40px);
  --maxw:      1440px;

  /* ---- Radius ----
     16px is the system. Packaging is angular; the interface around it is
     not, and pretending otherwise produced a page of hard rectangles that
     read as severe rather than precise. */
  --r-block:   16px;
  --r-card:    16px;
  --r-outline: 12px;
  --r-input:   12px;
  --r-pill:    999px;

  --box-gap: clamp(0px, 1.2vw, 18px);
  --r-shell: clamp(0px, 2vw, 28px);
  --nav-h: 76px;
  /* Motion vocabulary, measured off the reference: reveals run 0.65s on
     an expo-out curve, hovers are transform-only at 0.4s, and colour
     changes are quick at 0.15s. Three durations, each with a job. */
  --ease:       cubic-bezier(0.16, 1, 0.3, 1);
  --dur-reveal: 650ms;
  --dur-hover:  400ms;
  --dur-tint:   150ms;

  /* Soft and low, never a halo. */
  --shadow-1: 0 1px 4px rgba(10, 10, 10, .10);
  --shadow-2: 0 2px 10px rgba(10, 10, 10, .13);
  --shadow-3: 0 12px 28px rgba(10, 10, 10, .13);
}

/* ── Surface scopes ─────────────────────────────────────────────────────
   These are blocks on the ground, not page grounds. Applying one re-points
   the semantic layer so anything inside inherits the right foreground,
   rules and accent without knowing where it landed. */
/* ── Tinted section ─────────────────────────────────────────────────────
   A coloured ground for a section that carries UI. Two things move with
   it: cards become white so they still read as surfaces on a tint, and the
   accent darkens, cobalt measures 4.15:1 on this ground and fails. That
   is the same law as .on-ink running the other way: the blue tracks the
   ground in both directions, not only downward. */
.on-tint {
  --ground:     #D8E3F0;
  --surface:    var(--white);
  --rule:       #BECBDC;
  --rule-soft:  #CBD6E4;
  /* Text tiers darken with the ground too. The page defaults are tuned for
     #F8F8F8 and land at 4.08:1 here, a tint is darker than the ground it
     replaces, so everything reading against it has to follow. */
  --fg-dim:     #59595D;   /* 5.37:1 here, 6.97:1 on the white cards */
  --fg-faint:   #4E4E51;   /* 6.38:1 here */
  --accent:     #2350EA;   /* 4.74:1 here, 6.16:1 on the white cards */
  --accent-ink: var(--white);
  background: var(--ground);
}

.on-white {
  --ground: var(--white);
  --surface: var(--surface-2);
  background: var(--ground);
}
.on-ink {
  --ground:     var(--ink);
  --surface:    #111A2E;
  --fg:         var(--white);
  --fg-dim:     #A7ADBC;
  --fg-faint:   #8F96A8;
  --rule:       #1E2740;
  --rule-soft:  #161E33;
  --accent:     var(--cobalt-lift);   /* the law, applied structurally */
  --accent-ink: var(--ink);
  --ok:         #4FBF8C;
  --warn:       #E0A33C;
  background: var(--ground);
  color: var(--fg);
}
.on-accent {
  --ground:     var(--cobalt);
  --surface:    #1C46E8;
  --fg:         var(--white);
  --fg-dim:     #E8ECFF;   /* 4.59:1 on cobalt */
  --fg-faint:   #E8ECFF;   /* cobalt is saturated enough that a third tier cannot clear AA */
  --rule:       #5570FF;
  --rule-soft:  #4463FF;
  --accent:     var(--white);
  --accent-ink: var(--cobalt);
  background: var(--ground);
  color: var(--fg);
}

/* A rounded block on the ground. This is the page's structural unit. */
.block {
  background: var(--surface);
  border-radius: var(--r-block);
  padding: var(--card-pad);
}

/* ---- Reset ---- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
/* ── The box ────────────────────────────────────────────────────────────
   The site sits in a rounded container with the page ground visible around
   it, rather than running edge to edge. Full-bleed made every section a
   band across the window; boxed, the whole site reads as one object and
   the sections inside it read as parts of that object. */
body {
  margin: 0;
  padding: var(--box-gap);
  background: var(--page);
  color: var(--fg);
  font-family: var(--font);
  font-size: var(--t-body-f);
  font-weight: 400;
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

/* No overflow clipping here. The nav's dropdown panels live inside the
   shell, and a clipping container cuts them off at the rounded edge,
   which is exactly the defect the detector names. The corners are rounded
   on the first and last children instead, which gives the same boxed
   silhouette and lets menus escape. */
.shell {
  background: var(--ground);
  border-radius: var(--r-shell);
  max-width: var(--maxw);
  margin-inline: auto;
}
.shell > .nav { border-start-start-radius: var(--r-shell); border-start-end-radius: var(--r-shell); }
.shell > .foot { border-end-start-radius: var(--r-shell); border-end-end-radius: var(--r-shell); }

img, video, svg { display: block; max-width: 100%; }
button, input { font: inherit; color: inherit; }
::selection { background: var(--fg); color: var(--ground); }
:focus-visible { outline: 1px solid var(--fg); outline-offset: 4px; }
a { color: inherit; text-decoration: none; }

/* ═══ Type primitives ═══════════════════════════════════════════════════
   Mixed case throughout. The old system set display and headings in
   uppercase at weight 500, which reads as a poster; this reads as a
   product. Tracking is negative and only works at size, so it is tied to
   the fluid scale rather than applied flat. */
.display {
  font-size: var(--t-display-f);
  font-weight: 500;
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  margin: 0;
  text-wrap: balance;
}
.heading {
  font-size: var(--t-head-f);
  font-weight: 500;
  line-height: var(--lh-head);
  letter-spacing: var(--ls-head);
  margin: 0;
  text-wrap: balance;
}
.subheading {
  font-size: var(--t-sub);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.011em;
  margin: 0;
}
.body {
  font-size: var(--t-body-f);
  font-weight: 400;
  line-height: var(--lh-body);
  letter-spacing: -0.011em;
  margin: 0;
  color: var(--fg-dim);
  max-width: 62ch;
}
/* Small, mixed case, weight 500, a UI label, not a tracked-out kicker. */
.label {
  font-size: var(--t-label);
  font-weight: 500;
  letter-spacing: -0.006em;
  color: var(--fg-dim);
  margin: 0;
}
.credit {
  font-size: var(--t-caption);
  font-weight: 500;
  letter-spacing: -0.004em;
  color: var(--fg-dim);
}
.micro {
  font-size: var(--t-micro);
  line-height: 1.5;
  color: var(--fg-dim);
}

/* ═══ Dividers: dashed only, 1px, cork ══════════════════════════════════ */
.rule {
  border: 0;
  border-top: 1px dashed var(--rule);
  margin: 0;
}
.rule--solid { border-top: 1px solid var(--rule); }
.rule--drift { border-top: 1px dashed var(--rule-soft); }

/* ═══ Chrome ════════════════════════════════════════════════════════════ */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px var(--gutter);
  /* Opaque, for the same reason the hero panel is: 12% of whatever
     scrolls under a glass bar decides the contrast of everything on it.
     Measured through the blur, the wordmark's accent half ran a 3.6:1
     median where it is 5.08:1 on the solid ground, and the nav links sit
     on the same bar. */
  background: var(--ground);
  border-bottom: 1px dashed var(--rule);
}
.nav__mark {
  font-size: var(--t-sub);
  font-weight: 600;
  letter-spacing: 0.14em;
}
.nav__mark em { color: var(--accent); font-style: normal; }
.nav__links { display: flex; align-items: center; gap: 32px; }
.nav__links a {
  font-size: var(--t-label);
  font-weight: 500;
  letter-spacing: -0.006em;
  color: var(--fg-faint);
  transition: color 200ms var(--ease);
}
.nav__links a:hover { color: var(--fg); }
@media (max-width: 820px) { .nav__links a:not(.btn) { display: none; } }

/* ═══ Buttons: three radii, no shadows ═════════════════════════════════ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--t-label);
  font-weight: 500;
  letter-spacing: -0.006em;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background 220ms var(--ease), color 220ms var(--ease),
              border-color 220ms var(--ease);
}
.btn--filled {
  background: var(--accent);
  color: var(--accent-ink);
  border-radius: var(--r-input);
  padding: 14px 32px;
}
.btn--filled:hover { background: var(--cobalt-deep); }
.btn--outline {
  background: transparent;
  color: var(--fg);
  border-color: var(--rule);
  border-radius: var(--r-outline);
  padding: 11px 26px;
}
.btn--outline:hover { border-color: var(--fg); }
.btn--lg { font-size: var(--t-sub); padding: 18px 44px; }

/* ═══ Section rhythm: full-bleed, each section a full viewport ═════════ */
/* 100vw includes the scrollbar and overflows by its width on every
   desktop browser that shows one; 100% is the container. */
.section {
  width: 100%;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 120px var(--gutter) 80px;
  position: relative;
}
.section--auto { min-height: auto; padding-block: clamp(80px, 12vh, 160px); }

/* ═══ The signature pattern: text / centered object / text ══════════════ */
.artifact-grid {
  display: grid;
  grid-template-columns: 1fr minmax(280px, 42vmin) 1fr;
  align-items: center;
  gap: clamp(24px, 5vw, 80px);
  width: 100%;
}
.artifact-grid__col { display: flex; flex-direction: column; gap: var(--gap); }
.artifact-grid__col--right { align-items: flex-end; text-align: right; }
.artifact-grid__col--right .body { text-align: right; }

/* ── The floating objects ───────────────────────────────────────────────
   Cut-out PNGs with real alpha, sitting directly on the page ground. No
   container, no frame, no video bed, the walnut canvas IS the background,
   which is what makes them read as suspended rather than as pictures of
   objects. Each drifts on its own cycle so the group never pulses in sync. */
.artifact {
  position: relative;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
}
.artifact img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* The system forbids shadows on surfaces; this is a light source on an
     object in a void, which is what sells the float. */
  filter: drop-shadow(0 40px 60px rgba(0, 0, 0, 0.55));
}

.float { animation: drift 9s ease-in-out infinite; }
.float--a { animation-duration: 11s;  animation-delay: -2s; }
.float--b { animation-duration: 8.5s; animation-delay: -5s; }
.float--c { animation-duration: 13s;  animation-delay: -1s; }
.float--d { animation-duration: 10s;  animation-delay: -7s; }
.float--e { animation-duration: 12s;  animation-delay: -3.5s; }

@keyframes drift {
  0%, 100% { transform: translateY(0)      rotate(0deg); }
  50%      { transform: translateY(-22px)  rotate(2.2deg); }
}
@media (prefers-reduced-motion: reduce) {
  .float { animation: none; }
}

/* ── Constellation: the hero's supporting objects ──────────────────────
   Smaller boxes scattered around the primary artifact, scaled down and
   dimmed so the hierarchy stays intact and nothing competes with the copy. */
.constellation {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
}
.constellation img {
  position: absolute;
  /* The width/height attributes reserve space against layout shift, but a CSS
     width alone leaves the 760px attribute height in force, which stretched
     every box into a tall smear. height:auto restores the aspect ratio. */
  height: auto;
  opacity: 0.5;
  filter: drop-shadow(0 30px 45px rgba(0, 0, 0, 0.6));
}
@media (max-width: 900px) { .constellation { display: none; } }

/* ── Specimen row: the full range, each object floating on the ground ── */
.specimens {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: clamp(20px, 4vw, 56px);
  width: 100%;
  align-items: end;
}
.specimen { display: flex; flex-direction: column; align-items: center; gap: 18px; text-align: center; }
.specimen img {
  width: 100%;
  max-width: 190px;
  height: auto;
  filter: drop-shadow(0 30px 44px rgba(0, 0, 0, 0.55));
}
.specimen__name {
  font-size: var(--t-label);
  font-weight: 500;
  letter-spacing: -0.006em;
  color: var(--fg);
}
.specimen__meta { font-size: var(--t-caption); letter-spacing: -0.006em; color: var(--fg-faint); }

@media (max-width: 900px) {
  .artifact-grid { grid-template-columns: 1fr; }
  .artifact-grid__col--right { align-items: flex-start; text-align: left; }
  .artifact-grid__col--right .body { text-align: left; }
  .artifact-grid__col { order: 2; }
  .artifact { order: 1; max-width: 78vw; margin-inline: auto; }
}

/* ═══ Cards: 12px radius, 24px padding, bark surface ═══════════════════ */
/* Not a card any more. A heading and a list do not need a filled box
   around them when a rule and consistent alignment already group them,
   and 27 of these across 12 pages was the site's remaining "collection of
   floating rectangles" problem. The content is unchanged; only the
   container goes, which is why this is one rule rather than twelve files
   of markup edits. */
.card {
  background: transparent;
  border-top: 1px solid var(--rule);
  border-radius: 0;
  padding: var(--sp-lg) 0 0;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}
.card--outline { border-top: 1px solid var(--rule); }

/* ═══ Reveal on entry ══════════════════════════════════════════════════ */
/* Gated on `.js`, set by an inline script in the head. Without scripting
   the page renders at its finished state instead of a blank column of
   opacity-0 blocks waiting on an observer that will never run. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--dur-reveal) var(--ease), transform var(--dur-reveal) var(--ease);
}
.js [data-reveal].in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
}

/* ═══ Hero ═════════════════════════════════════════════════════════════ */
.hero { padding-top: 140px; }
/* The pulsing status dot is gone. It simulated liveness decoratively, which
   is a poor trade on a site whose actual claim is live monitoring, a
   decorative indicator standing beside a real one devalues both. */
.hero__actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: var(--sp-md); }

/* ═══ Numbered argument rows ═══════════════════════════════════════════ */
.rows { display: flex; flex-direction: column; width: 100%; }
.row {
  display: grid;
  grid-template-columns: 64px 1fr minmax(0, 38ch);
  gap: clamp(16px, 4vw, 56px);
  align-items: start;
  padding: clamp(28px, 4vh, 48px) 0;
  border-top: 1px dashed var(--rule);
}
.row:last-child { border-bottom: 1px dashed var(--rule); }
.row__n { font-size: var(--t-label); font-weight: 500; letter-spacing: -0.006em; color: var(--fg-faint); padding-top: .35em; }
@media (max-width: 820px) {
  .row { grid-template-columns: 40px 1fr; }
  .row .body { grid-column: 2; }
}

/* ═══ Spec table: the "museum placard" ════════════════════════════════ */
.spec { width: 100%; border-collapse: collapse; }
.spec tr { border-top: 1px dashed var(--rule); }
.spec tr:last-child { border-bottom: 1px dashed var(--rule); }
.spec th, .spec td {
  text-align: left;
  padding: 18px 0;
  font-size: var(--t-sub);
  font-weight: 500;
  letter-spacing: -0.006em;
  vertical-align: top;
}
.spec th { color: var(--fg-faint); width: 42%; font-weight: 500; }
.spec td { color: var(--fg); }

/* ═══ Two-up member cards ══════════════════════════════════════════════ */
.duo { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-xl); width: 100%; }
@media (max-width: 820px) { .duo { grid-template-columns: 1fr; } }
/* min-height forced equal box heights, which only mattered while these
   were boxes. Content sets the height now. */
.duo .card { min-height: 0; }
.duo ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.duo li {
  font-size: var(--t-label);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--fg-dim);
  padding-left: 18px;
  position: relative;
  line-height: 1.4;
}
.duo li::before { content: "\2022"; position: absolute; left: 0; color: var(--fg-faint); }

/* ═══ Close ════════════════════════════════════════════════════════════ */
.close { align-items: center; text-align: center; }
.close__inner { display: flex; flex-direction: column; align-items: center; gap: 24px; max-width: 22ch; }

.foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap;
  padding: 28px var(--gutter);
  border-top: 1px dashed var(--rule);
}
.foot__links { display: flex; gap: 28px; flex-wrap: wrap; }

/* ═══════════════════════════════════════════════════════════════════════
   NAVIGATION, added for the new information architecture.
   Uses only existing tokens (cream, walnut, bark, cork, ember, the radius
   vocabulary and the Minor Third type scale). No new colours, no new fonts.
   ═══════════════════════════════════════════════════════════════════════ */

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--surface); color: var(--fg);
  padding: 12px 20px; border-radius: var(--r-card);
  font-size: var(--t-label); letter-spacing: -0.006em;
}
.skip:focus { left: var(--gutter); top: 12px; }

/* The header was `position: fixed`; sticky keeps it in flow so an open
   dropdown can push nothing and the mobile sheet can sit beneath it. */
.nav { position: sticky; gap: var(--gap); }

.nav__links { flex: 1; justify-content: flex-start; margin-left: clamp(20px, 3vw, 48px); }
.nav__actions { display: flex; align-items: center; gap: 12px; }

.nav__signin {
  font-size: var(--t-label); font-weight: 500; letter-spacing: -0.006em;
  color: var(--fg-faint);
  padding: 8px 4px;
  transition: color 200ms var(--ease);
}
.nav__signin:hover { color: var(--fg); }

/* Get Started carries the emphasis: filled, against Sign In's plain text. */
.btn--cta {
  /* Cobalt, matching the hero's primary action: one colour means "act".
     The hover was previously hard-coded to #fff, which was correct while
     the label was dark, after the ground inverted it left ivory text on
     white at 1.1:1. Hover now derives from the accent, so it cannot
     desynchronise from the label again. */
  background: var(--accent); color: var(--accent-ink);
  border-radius: var(--r-input);
  padding: 11px 22px;
  white-space: nowrap;
}
.btn--cta:hover { background: var(--cobalt-deep); }

.nav__links a[aria-current="page"],
.menu__trigger[aria-current="page"] { color: var(--fg); }

/* ── Desktop dropdowns ───────────────────────────────────────────────── */
.menu { position: relative; }

.menu__trigger {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 0; cursor: pointer;
  font-family: inherit;
  font-size: var(--t-label); font-weight: 500; letter-spacing: -0.006em;
  color: var(--fg-faint);
  padding: 8px 0;
  transition: color 200ms var(--ease);
}
.menu__trigger:hover, .menu__trigger[aria-expanded="true"] { color: var(--fg); }

.menu__chev {
  width: 7px; height: 7px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 200ms var(--ease);
}
[aria-expanded="true"] > .menu__chev { transform: rotate(-135deg) translate(-2px, -2px); }

.menu__panel {
  position: absolute; top: calc(100% + 14px); left: -16px;
  min-width: 300px;
  background: var(--ground);
  border: 1px solid var(--rule);
  border-radius: var(--r-card);
  padding: 10px;
  display: flex; flex-direction: column;
  z-index: 120;
}
.menu__panel[hidden] { display: none; }
.menu__panel--cols {
  display: grid; grid-template-columns: 1fr 1fr; gap: 2px; min-width: 420px;
}

.menu__panel a {
  display: flex; flex-direction: column; gap: 3px;
  padding: 11px 14px;
  border-radius: var(--r-card);
  transition: background 160ms var(--ease);
}
.menu__panel a:hover, .menu__panel a:focus-visible { background: var(--surface); }

.menu__title {
  font-size: var(--t-label); font-weight: 500; letter-spacing: -0.006em;
  color: var(--fg);
}
.menu__desc {
  font-size: var(--t-caption);
  text-transform: none; letter-spacing: 0;
  color: var(--fg-faint);
  line-height: 1.45;
}

/* ── Burger + mobile sheet ───────────────────────────────────────────── */
.burger {
  display: none;
  width: 44px; height: 44px;
  flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  background: none; border: 1px solid var(--rule); border-radius: var(--r-card);
  cursor: pointer;
}
.burger span { display: block; width: 17px; height: 1.5px; background: var(--fg); transition: transform 200ms var(--ease), opacity 200ms var(--ease); }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

.msheet {
  position: fixed; inset: 64px 0 0 0; z-index: 90;
  background: var(--ground);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.msheet[hidden] { display: none; }
.msheet__inner {
  display: flex; flex-direction: column;
  padding: var(--gap) var(--gutter) calc(var(--gap) + env(safe-area-inset-bottom));
  min-height: 100%;
}

.msheet__link, .macc__trigger {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%;
  min-height: 56px;                 /* generous one-handed tap target */
  padding: 0;
  background: none; border: 0; border-bottom: 1px dashed var(--rule);
  font-family: inherit;
  font-size: var(--t-sub); font-weight: 500; letter-spacing: -0.006em;
  color: var(--fg);
  cursor: pointer;
  text-align: left;
}
.macc__panel { display: flex; flex-direction: column; padding: 4px 0 12px; }
.macc__panel[hidden] { display: none; }
.macc__panel a {
  min-height: 48px;
  display: flex; align-items: center;
  padding-left: 16px;
  font-size: var(--t-label); letter-spacing: -0.006em;
  color: var(--fg-dim);
}
.macc__panel a:active { color: var(--fg); }

.msheet__actions {
  display: flex; flex-direction: column; gap: 10px;
  margin-top: auto; padding-top: var(--gap);
}
.msheet__actions .btn { width: 100%; padding-block: 15px; }

/* Below 900px the inline nav is replaced wholesale by the sheet. */
@media (max-width: 900px) {
  .nav__links { display: none; }
  .nav__signin { display: none; }
  .burger { display: inline-flex; }
}
body.menu-open { overflow: hidden; }

/* ═══════════════════════════════════════════════════════════════════════
   PAGE FURNITURE for the new routes. Same tokens throughout.
   ═══════════════════════════════════════════════════════════════════════ */

/* Interior pages are documents, not full-viewport acts, so they opt out of
   the homepage's 100vh section rhythm. */
.page { padding: clamp(96px, 12vh, 150px) var(--gutter) clamp(64px, 9vh, 110px); }
/* The shell caps the width and the gutter sets the inset. Nothing inside
   re-centres: a second max-width here put every section's content 7px to
   the right of the header mark, and the narrowed prose sections 150px to
   the right of it. */
.page__inner { max-width: var(--sc-maxw, 100%); margin-inline: 0; }
.measure { max-width: 68ch; }

.crumb {
  display: flex; gap: 8px; align-items: center;
  font-size: var(--t-caption); letter-spacing: -0.006em;
  color: var(--fg-faint);
  margin-bottom: var(--gap);
}
.crumb a:hover { color: var(--fg); }

.grid-3 { display: grid; gap: var(--gap); grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); }

.step {
  display: grid; grid-template-columns: 40px 1fr; gap: 16px;
  padding: 20px 0; border-top: 1px dashed var(--rule);
  align-items: start;
}
.steps .step:last-child { border-bottom: 1px dashed var(--rule); }
.step__n {
  font-size: var(--t-caption); letter-spacing: -0.006em;
  color: var(--accent); padding-top: 4px;
}

.chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 14px;
  border: 1px solid var(--rule); border-radius: var(--r-pill);
  font-size: var(--t-caption); letter-spacing: -0.006em;
  color: var(--fg-dim);
}
.chip--soon { opacity: .55; }

.faq { border-top: 1px dashed var(--rule); }
.faq:last-of-type { border-bottom: 1px dashed var(--rule); }
.faq summary {
  cursor: pointer; list-style: none;
  padding: 20px 0;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  font-size: var(--t-sub); font-weight: 500; letter-spacing: -0.006em;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex-shrink: 0;
  width: 9px; height: 9px;
  border-right: 1.5px solid var(--fg-faint); border-bottom: 1.5px solid var(--fg-faint);
  transform: rotate(45deg);
  transition: transform 200ms var(--ease);
}
.faq[open] summary::after { transform: rotate(-135deg); }
.faq__body { padding-bottom: 22px; }

.cat-card {
  display: flex; flex-direction: column; gap: 10px;
  padding: var(--card-pad);
  border: 1px solid var(--rule); border-radius: var(--r-card);
  background: var(--surface);
  transition: border-color 200ms var(--ease);
}
.cat-card:hover { border-color: var(--rule-soft); }
.cat-card img { width: 84px; height: auto; }

/* ═══ Footer ═════════════════════════════════════════════════════════ */
.foot {
  display: block;
  padding: clamp(48px, 7vw, 80px) var(--gutter) 28px;
  border-top: 1px dashed var(--rule);
}
.foot__top { margin: 0 0 clamp(36px, 5vw, 56px); }
.foot__cols {
  display: grid; gap: var(--gap) 24px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
}
.foot__col { display: flex; flex-direction: column; gap: 9px; }
.foot__head {
  font-size: var(--t-caption); font-weight: 500; letter-spacing: -0.006em;
  color: var(--fg); margin: 0 0 3px;
}
.foot__col a {
  font-size: var(--t-label);
  color: var(--fg-faint);
  transition: color 180ms var(--ease);
}
.foot__col a:hover { color: var(--fg); }
.foot__base {
  margin: clamp(36px, 5vw, 56px) 0 0;
  padding-top: 22px; border-top: 1px dashed var(--rule);
  display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between; align-items: center;
}

/* ═══════════════════════════════════════════════════════════════════════
   PRODUCT UI EXAMPLES + MONEY FLOW
   Built from the existing card/pill vocabulary and tokens. No new colours
   beyond a green/amber state pair, which the dashboard already uses.
   ═══════════════════════════════════════════════════════════════════════ */

.ui-card {
  display: flex; flex-direction: column; gap: 14px;
  padding: var(--card-pad);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-card);
}
.ui-card__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.ui-card__title {
  margin: 0; font-size: var(--t-sub); font-weight: 500; letter-spacing: -0.006em; color: var(--fg);
}
.ui-card__sub {
  margin: 3px 0 0; font-size: var(--t-caption);
  color: var(--fg-faint); font-variant-numeric: tabular-nums;
}

.ui-card__rows { margin: 0; display: flex; flex-direction: column; }
.ui-card__rows > div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 11px 0; border-top: 1px dashed var(--rule);
}
.ui-card__rows dt {
  font-size: var(--t-caption);
  letter-spacing: -0.006em; color: var(--fg-faint);
}
.ui-card__rows dd {
  margin: 0; font-size: var(--t-sub); color: var(--fg);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

.ui-card__steps { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; }
.ui-card__steps li {
  position: relative; padding: 9px 0 9px 26px;
  font-size: var(--t-label); color: var(--fg-faint);
}
.ui-card__steps li::before {
  content: ""; position: absolute; left: 0; top: 50%;
  width: 9px; height: 9px; margin-top: -4.5px;
  border-radius: 50%; border: 1.5px solid var(--rule);
}
.ui-card__steps li.is-done { color: var(--fg-dim); }
.ui-card__steps li.is-done::before { background: var(--ok); border-color: var(--ok); }
.ui-card__steps li.is-active { color: var(--fg); }
.ui-card__steps li.is-active::before { background: var(--accent); border-color: var(--accent); }

/* Pills reuse the app's state vocabulary. */
.pill {
  display: inline-flex; align-items: center; flex-shrink: 0;
  padding: 4px 11px; border-radius: var(--r-pill);
  font-size: var(--t-caption); font-weight: 500; letter-spacing: -0.006em;
  border: 1px solid;
}
.pill--ok    { color: var(--ok); border-color: color-mix(in oklab, var(--ok) 40%, transparent); background: color-mix(in oklab, var(--ok) 10%, transparent); }
.pill--warn  { color: var(--warn); border-color: color-mix(in oklab, var(--warn) 40%, transparent); background: color-mix(in oklab, var(--warn) 10%, transparent); }
.pill--live  { color: var(--accent); border-color: color-mix(in oklab, var(--accent) 45%, transparent); background: color-mix(in oklab, var(--accent) 12%, transparent); }
.pill--muted { color: var(--fg-faint); border-color: var(--rule); }

/* ── Money flow ──────────────────────────────────────────────────────── */
.flow { display: grid; gap: var(--gap); grid-template-columns: 1fr; }
@media (min-width: 800px) { .flow { grid-template-columns: 1fr 1fr; } }

.flow__lane {
  display: flex; flex-direction: column; gap: 14px;
  padding: var(--card-pad);
  border: 1px solid var(--rule); border-radius: var(--r-card);
}
.flow__tag {
  align-self: flex-start;
  font-size: var(--t-caption);
  letter-spacing: -0.006em; color: var(--fg-faint);
}
.flow__row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.flow__node {
  padding: 11px 18px;
  border: 1px solid var(--rule); border-radius: var(--r-pill);
  font-size: var(--t-label); font-weight: 500; letter-spacing: -0.006em;
  color: var(--fg);
}
.flow__node--alt { background: var(--surface); }
.flow__arrow {
  flex: 1 0 28px; height: 1px; min-width: 28px;
  background: var(--rule-soft); position: relative;
}
.flow__arrow::after {
  content: ""; position: absolute; right: 0; top: 50%;
  width: 6px; height: 6px; margin-top: -3.5px;
  border-top: 1.5px solid var(--rule-soft); border-right: 1.5px solid var(--rule-soft);
  transform: rotate(45deg);
}
.flow__note { margin: 0; font-size: var(--t-caption); color: var(--fg-faint); line-height: 1.5; max-width: 62ch; }

/* Specimen tiles became links; keep them looking like figures. */
a.specimen { color: inherit; text-decoration: none; }
a.specimen:hover .specimen__name { color: var(--fg); }

/* ═══════════════════════════════════════════════════════════════════════
   HERO ON SMALL SCREENS

   The stacking order put the product image first, which pushed the headline
   roughly 640px down, below the fold on a phone, so the first screenful
   said nothing. Copy leads on mobile; the image follows it.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .hero .artifact-grid__col { order: 1; }
  .hero .artifact { order: 2; max-width: 62vw; }

  /* The hero no longer needs a full viewport once the copy is at the top,
     and forcing one only creates dead space above the fold. */
  .hero.section { min-height: auto; padding-block: 96px 56px; justify-content: flex-start; }

  /* The trailing support column reads as a footnote here, not a second
     column, so it sits under the CTAs with a little separation. */
  .hero .artifact-grid__col--right { order: 3; margin-top: 4px; }
}

/* Very small phones: keep the artifact from eating the screen. */
@media (max-width: 420px) {
  .hero .artifact { max-width: 54vw; }
}

/* ═══════════════════════════════════════════════════════════════════════
   HERO v2, asymmetric, scroll-driven.

   The old hero was three equal columns: text | object | text. Nothing
   dominated, so nothing led the eye. This gives the composition a clear
   hierarchy, copy, then one dominant object, then supporting objects at
   reduced weight, and binds the packaging to live UI so the physical and
   software halves are never shown apart.
   ═══════════════════════════════════════════════════════════════════════ */

.hero2 {
  position: relative;
  /* No scroll travel any more. The cycling moved onto its own clock, so
     the hero is the height of what it holds, the reference's is 333px,
     and reserving 1.5 screens of runway to advance six stages was the
     single largest thing separating this page from it. */
  height: auto;
  padding: 0;
  display: block;
}
.hero2__sticky {
  position: relative;
  min-height: 0;
  display: grid;
  align-items: center;
  grid-template-columns: 1fr;
  gap: var(--gap);
  padding: 88px var(--gutter) 40px;
  overflow: hidden;
}

/* ── Desktop: one overlaid frame, not two columns ────────────────────
   The previous hero was a refined version of "text left, image right",
   type in one column, objects in the other, never touching. Here the
   stage covers the whole frame and the layers interleave: satellites
   read behind the headline, the headline sits above them, and the
   dominant object crosses in front of its right edge. Depth comes from
   occlusion rather than from opacity, which is what stops it reading as
   a flat collage. */
@media (min-width: 900px) {
  .hero2__sticky {
    display: block;
    padding-block: var(--sp-xl) var(--sp-lg);
    /* The header is sticky, not fixed, so it occupies 83px of flow. A
       full 100svh hero therefore overflows the viewport by exactly that
       much and clips its own reading panel off the bottom of the first
       frame. Pin below the header and subtract its height. */
    min-height: min(72vh, 660px);
  }
  .hero2__copy {
    position: absolute;
    left: var(--gutter);
    top: 50%;
    transform: translateY(-50%);
    width: min(56%, 660px);
    z-index: 2;
  }
  .hstage { position: absolute; inset: 0; }
}

/* The stage precedes the copy in the DOM so the desktop overlay can layer
   objects behind and in front of the headline. On mobile that source order
   would stack the packaging first and push the h1 to ~497px, below the
   fold on a 812px screen. `order` restores copy-first without disturbing
   the desktop z-stack. */
.hero2__copy { display: flex; flex-direction: column; gap: var(--sp-md); align-items: flex-start; z-index: 2; }
@media (max-width: 899px) {
  .hero2__copy  { order: -1; }
  .hstage       { order: 0; min-height: 260px; }
  .hui          { order: 1; position: static; width: 100%; margin-top: var(--sp-md); }
}
.hero2__h1 { max-width: 11ch; }
.hero2__sub { max-width: 42ch; }
.hero2__terms {
  margin: 0;
  font-size: var(--t-caption);
  letter-spacing: -0.006em;
  color: var(--fg-dim);
}

/* ── Stage: one dominant object, others reduced ─────────────────────── */
.hstage { position: relative; height: 100%; min-height: 300px; }

.hstage__obj {
  position: absolute;
  inset: 0;
  margin: auto;
  height: auto;
  object-fit: contain;
  opacity: 0;
  /* Out of the accessibility tree while it is invisible, and back in one
     frame before it fades up. Without this a screen reader announced all
     six packaging objects for a hero that shows one. */
  visibility: hidden;
  transform: translateY(14px) scale(.965);
  transition: opacity 620ms var(--ease), transform 620ms var(--ease),
              visibility 0s linear 620ms;
  will-change: opacity, transform;
  /* Contact shadow, retuned for a paper ground. The old value was
     rgba(0,0,0,.55), correct against near-black walnut, but on ivory a
     shadow that dense reads as a smudge under the object rather than as
     light falling past it. */
  filter: drop-shadow(0 26px 38px rgba(12, 24, 36, .20));
  pointer-events: none;
}
.hstage__obj.is-active { opacity: 1; visibility: visible; transform: translateY(0) scale(1); transition-delay: 0s; }

/* Dominant object. */
/* The dominant object sits forward of the headline (z-index 3 against the
   copy's 2) and is pulled left far enough to cross it. Scale raised from
   460px: at editorial scale the object has to hold the frame. */
.hstage__obj--primary { width: min(74%, 460px); max-width: none; z-index: 3; }
@media (min-width: 900px) {
  .hstage__obj--primary {
    width: min(46%, 560px);
    inset: auto 3% auto auto;
    top: 50%;
    margin: 0;
    transform: translateY(-50%) translateY(14px) scale(.965);
  }
  .hstage__obj--primary.is-active { transform: translateY(-50%) scale(1); }
}

/* Supporting objects sit behind the headline at reduced weight, giving
   depth without competing. They persist across stages rather than
   cycling, so the frame never empties. */
.hstage__sat {
  position: absolute;
  height: auto;
  opacity: .30;
  filter: drop-shadow(0 14px 22px rgba(12, 24, 36, .16));
  pointer-events: none;
  z-index: 1;
}
.hstage__sat--a { width: 20%; top: -5%;  left: -4%; opacity: .22; }
.hstage__sat--b { width: 14%; bottom: 5%; left: 1%;  opacity: .20; }
.hstage__sat--c { width: 17%; top: 7%;   right: 36%; opacity: .26; }

/* ── Live UI panel, built in HTML so figures stay sharp and accurate ── */
.hui {
  position: absolute;
  left: 0; bottom: 0;
  width: min(300px, 82%);
  padding: 16px 18px;
  /* This was a 90% ground over a 12px backdrop blur, so every figure in
     it was reading against whatever the photograph happened to put
     behind it. Measured on the rendered page, the labels ran as low as
     1.9:1 and even the ink figures sat near 4.8:1, against the 19:1 the
     tokens promise on an opaque surface. A panel carrying live numbers
     cannot have its contrast decided by the image behind it, so it is
     now a solid card that lifts off the photograph with a shadow
     instead of dissolving into it. */
  background: var(--surface);
  border: 0;
  border-radius: var(--r-card);
  box-shadow: 0 12px 28px rgba(10, 10, 10, .13), 0 1px 3px rgba(10, 10, 10, .12);
  z-index: 3;
}
@media (min-width: 900px) { .hui { left: auto; right: 0; bottom: 6%; } }

.hui__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.hui__name { margin: 0; font-size: var(--t-label); font-weight: 500; letter-spacing: -0.006em; color: var(--fg); }
.hui__dims { margin: 3px 0 0; font-size: var(--t-micro); color: var(--fg-faint); font-variant-numeric: tabular-nums; }

.hui__rows { margin: 0; display: flex; flex-direction: column; }
.hui__rows > div { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 7px 0; border-top: 1px dashed var(--rule); }
.hui__rows dt { font-size: var(--t-micro); letter-spacing: -0.006em; color: var(--fg-faint); }
.hui__rows dd { margin: 0; font-size: var(--t-label); color: var(--fg); font-variant-numeric: tabular-nums; white-space: nowrap; }

.hui__steps { margin: 0; padding: 0; list-style: none; }
.hui__steps li { position: relative; padding: 7px 0 7px 22px; font-size: var(--t-micro); color: var(--fg-faint); }
.hui__steps li::before { content:""; position:absolute; left:0; top:50%; width:7px; height:7px; margin-top:-3.5px; border-radius:50%; border:1.5px solid var(--rule); }
.hui__steps li.is-done::before { background: var(--ok); border-color: var(--ok); }
.hui__steps li.is-done { color: var(--fg-dim); }

/* Scroll affordance, tells the visitor the hero has more to give. */
.hcue {
  position: absolute; left: var(--gutter); bottom: 22px;
  display: flex; align-items: center; gap: 9px;
  font-size: var(--t-micro); letter-spacing: -0.006em;
  color: var(--fg-faint);
  /* Fades out as soon as they start, so it never nags. */
  opacity: calc(1 - min(var(--p, 0) * 6, 1));
  transition: opacity 200ms linear;
}
.hcue__line { width: 34px; height: 1px; background: var(--rule-soft); position: relative; overflow: hidden; }
.hcue__line::after { content:""; position:absolute; inset:0; background: var(--fg); transform: translateX(-40%); }
@keyframes cue { 0% { transform: translateX(-100%);} 55%,100% { transform: translateX(100%);} }

/* Progress through the six stages. */
.hbar { position: absolute; right: var(--gutter); bottom: 24px; display: flex; gap: 5px; z-index: 3; }
.hbar span { width: 20px; height: 2px; background: var(--rule); transition: background 300ms var(--ease); }
.hstage[data-stage="mailer"]  ~ .hbar span:nth-child(1),
.hstage[data-stage="carton"]  ~ .hbar span:nth-child(-n+2),
.hstage[data-stage="rigid"]   ~ .hbar span:nth-child(-n+3),
.hstage[data-stage="tube"]    ~ .hbar span:nth-child(-n+4),
.hstage[data-stage="padded"]  ~ .hbar span:nth-child(-n+5),
.hstage[data-stage="folding"] ~ .hbar span { background: var(--fg); }

/* ═══ STICKY STORY: How Packwide Works ═══════════════════════════════ */
.story { position: relative; }
.story__grid { display: grid; grid-template-columns: 1fr; gap: var(--gap); }
@media (min-width: 900px) {
  .story__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(32px, 5vw, 80px); align-items: start; }
}

.story__steps { display: flex; flex-direction: column; }
.story__step {
  /* was clamp(28px,7vh,64px): 8 steps at up to 128px of vertical padding
     each is most of a screen spent on gaps alone. */
  padding: clamp(18px, 3.2vh, 34px) 0;
  border-top: 1px solid var(--rule);
  opacity: .38;
  transition: opacity 400ms var(--ease);
}
.story__step.is-active { opacity: 1; }
.story__step:last-child { border-bottom: 1px solid var(--rule); }
.story__n { font-size: var(--t-caption); letter-spacing: -0.006em; color: var(--accent); }

/* The visual half sticks while the copy scrolls past it. */
.story__visual { display: none; }
@media (min-width: 900px) {
  .story__visual {
    display: block;
    position: sticky;
    top: calc(50vh - 150px);
    height: 300px;
  }
}
.story__panel {
  position: absolute; inset: 0;
  padding: var(--card-pad);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-card);
  opacity: 0; transform: translateY(10px);
  transition: opacity 420ms var(--ease), transform 420ms var(--ease);
  display: flex; flex-direction: column; gap: 12px;
  overflow: hidden;
}
.story__panel.is-active { opacity: 1; transform: none; }

.srow { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; padding: 8px 0; border-top: 1px dashed var(--rule); }
.srow:first-of-type { border-top: 0; }
/* 10.5px here, and in .hui__rows and .hcue, was below the 11px floor for
   functional text: these are the labels naming every figure in the
   interface panels, on a scale that already has a 12px bottom rung. Being
   inside a mock panel does not make a label decorative. */
.srow dt, .srow__k { font-size: var(--t-micro); letter-spacing: -0.006em; color: var(--fg-faint); }
.srow dd, .srow__v { margin: 0; font-size: var(--t-sub); color: var(--fg); font-variant-numeric: tabular-nums; }

/* Falling stock, shown as a sequence rather than described in prose. */
.sfall { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-variant-numeric: tabular-nums; }
.sfall span { font-size: var(--t-sub); color: var(--fg-faint); }
.sfall span:last-child { color: var(--fg); font-size: var(--t-head-f); line-height: 1; }
.sfall i { font-style: normal; color: var(--fg-faint); }

/* ═══ EDITORIAL SCENES: business + manufacturer ══════════════════════ */
.scene { position: relative; border-radius: var(--r-card); overflow: hidden; min-height: 320px; }
.scene img { width: 100%; height: 100%; object-fit: cover; display: block; }
.scene__veil { position: absolute; inset: 0; background: linear-gradient(to top, color-mix(in oklab, var(--ground) 92%, transparent), transparent 62%); }
.scene__ui { position: absolute; left: 18px; right: 18px; bottom: 18px; z-index: 2; }

/* `align-items: center` with columns of very different heights was the
   bug: the photograph ran 418px against 719px of copy, so the image
   floated at mid-height and the button at the foot of the copy had three
   hundred pixels of empty column beside it, reading as detached from its
   own section. Stretching makes both columns the same height, so the
   image is beside the button rather than above nothing. */
.editorial { display: grid; grid-template-columns: 1fr; gap: var(--gap); align-items: stretch; }
@media (min-width: 900px) {
  .editorial { grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: clamp(28px, 4vw, 64px); }
  .editorial__media { display: flex; }
  .editorial__media .scene { flex: 1; min-height: 100%; }
  /* The copy column distributes: heading and list at the top, action at
     the foot, so the CTA lands on the same baseline as the image edge. */
  .editorial > div:not(.editorial__media) { display: flex; flex-direction: column; }
  .editorial > div:not(.editorial__media) > .btn { margin-top: auto; align-self: flex-start; }
  /* Reversed on the manufacturer side so the two audience sections do not
     mirror each other exactly. */
  .editorial--flip .editorial__media { order: 2; }
}

/* ═══ SECTION RHYTHM ═════════════════════════════════════════════════
   The page previously ran 13 sections at near-identical height, so nothing
   read as a moment. These give supporting sections less weight and let the
   hero and closing CTA carry more. */
.section--tight { padding-block: clamp(48px, 7vh, 80px); }
.section--wide  { padding-block: clamp(88px, 14vh, 180px); }

@media (max-width: 900px) {
  /* No pinning on phones, a 440vh sticky hero is a trap on a small screen.
     The hero becomes a normal block and the story steps all show. */
  .hero2 { height: auto; }
  .hero2__sticky { position: static; height: auto; min-height: 0; padding: 84px var(--gutter) 48px; }
  .hstage { height: 300px; margin-top: 12px; }
  .hstage__obj--primary { width: min(58%, 260px); }
  .hstage__sat { display: none; }
  .hui { position: static; width: 100%; margin-top: 18px; }
  .hcue, .hbar { display: none; }
  .story__step { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  /* No scroll-driven storytelling: show the first hero state complete and
     let every story step stand on its own. */
  .hero2 { height: auto; }
  .hero2__sticky { position: static; height: auto; }
  .hstage__obj, .story__panel { transition: none; }
  .hcue__line::after { animation: none; }
  .story__step { opacity: 1; }
}

/* The stage was sized by its content, leaving the lower half of the sticky
   viewport empty. Let it claim real height so the packaging holds the frame. */
@media (min-width: 900px) {
  .hero2__sticky { align-items: center; }
  .hstage { min-height: min(66vh, 620px); }
}

/* ═══════════════════════════════════════════════════════════════════════
   REDESIGN COMPONENTS
   Added for the ten-section homepage. Everything here reads the semantic
   token layer, so each component renders correctly on ivory, sand, ink or
   cobalt without knowing which ground it landed on.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Section openers ──────────────────────────────────────────────────
   Replaces the eyebrow-plus-heading pattern used 23 times on the old
   homepage. The heading opens the section on its own; the space above it
   does the work the kicker was pretending to do. */
.sec-open { margin-bottom: var(--sp-xl); }
.sec-open .heading { max-width: 22ch; }
.sec-open .body { margin-top: var(--sp-md); }
.pk-open { margin-bottom: var(--sp-xl); }
.pk-open .heading { max-width: 18ch; }
.pk-open .body { margin-top: var(--sp-md); }

/* More space above a heading than below it. */
.tension-line-h { margin-bottom: var(--sp-sm); }
.claim { max-width: 24ch; }

.ulink { text-decoration: underline; text-underline-offset: 3px; }

/* ── Packaging, at editorial scale ────────────────────────────────────
   The mailer leads at roughly twice the weight of the rest, so the block
   reads as a composition rather than as a product grid. */
.pkgrid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-lg) var(--sp-md);
  align-items: end;
}
@media (min-width: 700px)  { .pkgrid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1000px) {
  .pkgrid { grid-template-columns: repeat(4, 1fr); gap: var(--sp-lg) var(--sp-md); }
  .pk--lead { grid-column: span 2; grid-row: span 2; }
}
.pk { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.pk img {
  width: 100%; height: auto; margin-bottom: var(--sp-sm);
  filter: drop-shadow(0 18px 26px rgba(12, 24, 36, .16));
  transition: transform 420ms var(--ease);
}
.pk:hover img, .pk:focus-visible img { transform: translateY(-6px); }
.pk__name {
  font-size: var(--t-sub); font-weight: 600; color: var(--fg);
}
.pk__meta {
  font-size: var(--t-caption); color: var(--fg-dim);
  letter-spacing: .02em;
}

/* ── Annotated object ─────────────────────────────────────────────────
   Every label, figure and connector is real HTML and CSS. These are
   exactly the elements that must stay sharp, correct and translatable,
   so none of it is generated imagery.

   Laid out as a three-column grid rather than absolutely-positioned
   percentages. The first attempt placed six 210px callouts around a
   420px object inside an 804px stage and every one of them overlapped
   the box; a grid cannot overlap by construction, and it reflows to a
   stack on small screens for free. */
.anat {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-lg);
  align-items: center;
}
.anat__stage {
  position: relative;
  display: grid;
  place-items: center;
  padding: var(--sp-md) 0;
}
.anat__obj {
  width: min(100%, 380px); height: auto;
  filter: drop-shadow(0 26px 38px rgba(12, 24, 36, .18));
}
.anat__cal {
  display: flex; flex-direction: column; gap: 3px;
  position: relative;
  padding-top: var(--sp-sm);
  border-top: 1px solid var(--rule);
}
.anat__k {
  font-size: var(--t-caption);
  letter-spacing: -0.006em; color: var(--fg-dim);
}
.anat__v { font-size: var(--t-label); color: var(--fg); font-variant-numeric: tabular-nums; }
.anat__v--live { color: var(--accent); font-weight: 500; }

@media (min-width: 620px) {
  .anat { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .anat__stage { grid-column: 1 / -1; }
}

@media (min-width: 1000px) {
  .anat {
    grid-template-columns: minmax(150px, 1fr) minmax(300px, 1.25fr) minmax(150px, 1fr);
    grid-template-rows: repeat(3, auto);
    column-gap: clamp(28px, 5vw, 86px);
    row-gap: var(--sp-xl);
  }
  .anat__stage { grid-column: 2; grid-row: 1 / 4; padding: 0; }

  /* Leader lines run from each callout toward the object. They are drawn
     rather than generated so they stay crisp at any zoom. */
  .anat__cal { border-top: 0; padding-top: 0; }
  .anat__cal::after {
    content: ""; position: absolute; top: 8px;
    width: clamp(16px, 3vw, 52px); height: 1px; background: var(--rule);
  }
  .anat__cal--tl, .anat__cal--ml, .anat__cal--bl { text-align: right; align-items: flex-end; }
  .anat__cal--tl::after, .anat__cal--ml::after, .anat__cal--bl::after { left: 100%; }
  .anat__cal--tr::after, .anat__cal--mr::after, .anat__cal--br::after { right: 100%; }

  .anat__cal--tl { grid-column: 1; grid-row: 1; }
  .anat__cal--ml { grid-column: 1; grid-row: 2; }
  .anat__cal--bl { grid-column: 1; grid-row: 3; }
  .anat__cal--tr { grid-column: 3; grid-row: 1; }
  .anat__cal--mr { grid-column: 3; grid-row: 2; }
  .anat__cal--br { grid-column: 3; grid-row: 3; }
}

/* ── Replenishment curve ──────────────────────────────────────────────
   One scale places every mark and label, and each label names a value the
   chart actually reaches. Chart text takes its colour from the token
   layer so it reads on ink as well as on paper. */
.engine { display: grid; gap: var(--sp-xl); }
@media (min-width: 1000px) {
  .engine { grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: var(--sp-xl); align-items: center; }
}
.engine__chart { width: 100%; }
/* Text inside a viewBox scales with the drawing, so a chart that is free
   to shrink takes its labels down with it: measured, these ran 14.7px at
   1600, 9.0px in the two-column band around 900, and 6.2px on a 360px
   phone. The drawing now has a floor and scrolls inside its figure below
   it, the same way the packaging and step rails already do, so the
   labels never render below 12px. */
.curve { width: 100%; min-width: 620px; max-width: 780px; height: auto; overflow: visible; margin-inline: auto; }
.engine__chart { overflow-x: auto; overflow-y: hidden; padding-block: 2px; }
.engine__chart::-webkit-scrollbar { height: 8px; }
.engine__chart::-webkit-scrollbar-thumb { background: var(--rule); border-radius: 999px; }
.engine__chart::-webkit-scrollbar-track { background: transparent; }
.curve__grid  { stroke: var(--rule); stroke-width: 1; stroke-dasharray: 3 5; }
.curve__grid--mark { stroke: var(--accent); opacity: .45; stroke-dasharray: 4 4; }
.curve__axis  { stroke: var(--rule); stroke-width: 1; }
.curve__band  { fill: var(--accent); opacity: .08; }
.curve__line  { fill: none; stroke: var(--fg); stroke-width: 2.25; stroke-linejoin: round; stroke-linecap: round; }
.curve__line--after { stroke: var(--accent); }
.curve__dot   { fill: var(--accent); }
.curve__dot--sm { fill: var(--fg-dim); }
.curve__t {
  font-family: var(--font); font-size: 12.5px; fill: var(--fg-dim);
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
}
.curve__t--r { text-anchor: end; }
.curve__t--c { text-anchor: middle; }
.curve__t--accent { fill: var(--accent); font-weight: 500; }
.curve__t--band { fill: var(--fg-faint); font-size: 12px; letter-spacing: -0.006em; }
.engine__spec .micro { margin-top: var(--sp-md); }

/* ── Gains list ───────────────────────────────────────────────────────
   Replaces two six-card grids. A definition list carries the same
   content with alignment and rules doing the grouping, which is what the
   cards were being spent on. */
.gains { margin: 0; display: grid; gap: 0; }
.gains > div {
  display: grid; gap: 2px;
  padding: var(--sp-sm) 0;
  border-top: 1px solid var(--rule-soft);
}
.gains > div:last-child { border-bottom: 1px solid var(--rule-soft); }
@media (min-width: 560px) {
  .gains > div { grid-template-columns: minmax(0, 13rem) minmax(0, 1fr); gap: var(--sp-md); align-items: baseline; }
}
.gains dt { font-weight: 600; color: var(--fg); }
.gains dd { margin: 0; color: var(--fg-dim); }

/* ── Assurances ───────────────────────────────────────────────────── */
.assure { margin-top: var(--sp-xl); }
.assure__h { margin-bottom: var(--sp-lg); }
.assure__list { margin: 0; display: grid; gap: 0; }
.assure__list > div {
  display: grid; gap: 3px;
  padding: var(--sp-sm) 0;
  border-top: 1px solid var(--rule-soft);
}
.assure__list > div:last-child { border-bottom: 1px solid var(--rule-soft); }
@media (min-width: 700px) {
  .assure__list { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--sp-xl); }
}
.assure__list dt { font-weight: 600; color: var(--fg); }
.assure__list dd { max-width: 62ch; }
.assure__list dd { margin: 0; color: var(--fg-dim); font-size: var(--t-label); line-height: 1.55; }

.chips { display: flex; flex-wrap: wrap; gap: var(--sp-sm); margin-top: var(--sp-lg); }

/* ── Hero leader line ─────────────────────────────────────────────────
   Ties the reading panel to the object it describes. Without it the panel
   floats as an unrelated card; with it, the panel is visibly about that
   specific box. */
.hui__leader { display: none; }
@media (min-width: 900px) {
  .hui__leader {
    display: block; position: absolute;
    right: 100%; top: 28px;
    width: clamp(20px, 4vw, 64px); height: 1px;
    background: var(--rule);
  }
  .hui__leader::after {
    content: ""; position: absolute; right: 0; top: -2px;
    width: 5px; height: 5px; border-radius: 50%; background: var(--accent);
  }
}

.close-sub { text-align: center; max-width: 46ch; margin-top: var(--sp-md); }
.close .body { color: var(--fg-dim); }

/* ═══ Motion ════════════════════════════════════════════════════════════
   Two new authored moments, both entrance-only, both driven by the
   existing IntersectionObserver that already sets `.in` on [data-reveal].

   No animation library. The plan proposed GSAP ScrollTrigger for hero
   choreography, but the hero's scrub already works in ~4KB of hand-rolled
   code, and these two moments are entrances rather than scrubs, a
   timeline engine would have been 70KB buying nothing.
   ═══════════════════════════════════════════════════════════════════════ */

/* The stock curve draws itself along its own length. This is the one
   place on the page where motion carries information no static frame
   can: you watch stock fall to the threshold and the order go out. */
.js .curve__line {
  stroke-dasharray: var(--len, 900);
  stroke-dashoffset: var(--len, 900);
}
[data-reveal].in .curve__line {
  animation: draw 1100ms var(--ease) forwards;
}
[data-reveal].in .curve__line--after { animation-delay: 780ms; }
@keyframes draw { to { stroke-dashoffset: 0; } }

.js .curve__dot, .js .curve__t--accent, .js .curve__band {
  opacity: 0;
  transition: opacity 500ms var(--ease) 1200ms;
}
[data-reveal].in .curve__dot,
[data-reveal].in .curve__t--accent { opacity: 1; }
[data-reveal].in .curve__band { opacity: .08; }

/* Leader lines extend from each callout toward the object, in reading
   order, so the annotation reads as being drawn onto the box. */
@media (min-width: 1000px) {
  .js .anat__cal::after { transform: scaleX(0); transition: transform 600ms var(--ease); }
  .anat__cal--tl::after, .anat__cal--ml::after, .anat__cal--bl::after { transform-origin: left center; }
  .anat__cal--tr::after, .anat__cal--mr::after, .anat__cal--br::after { transform-origin: right center; }
  [data-reveal].in .anat__cal::after { transform: scaleX(1); }
  [data-reveal].in .anat__cal--tl::after, [data-reveal].in .anat__cal--tr::after { transition-delay: 180ms; }
  [data-reveal].in .anat__cal--ml::after, [data-reveal].in .anat__cal--mr::after { transition-delay: 320ms; }
  [data-reveal].in .anat__cal--bl::after, [data-reveal].in .anat__cal--br::after { transition-delay: 460ms; }
}

/* Everything above is an enhancement over a complete static composition.
   With motion disabled the curve is fully drawn, the leaders are fully
   extended, and every figure is present and legible. */
@media (prefers-reduced-motion: reduce) {
  .curve__line { stroke-dasharray: none; stroke-dashoffset: 0; animation: none !important; }
  .curve__dot, .curve__t--accent { opacity: 1; transition: none; }
  .curve__band { opacity: .08; transition: none; }
  .anat__cal::after { transform: scaleX(1) !important; transition: none; }
  .pk img { transition: none; }
}

/* ═══ Story photography ═════════════════════════════════════════════════
   Three beats the page previously argued in words but never showed.
   ═══════════════════════════════════════════════════════════════════════ */

/* Packaging: the range, in the real colours a manufacturer can print. The
   six cutouts below are all kraft, which under-sold what is actually
   available. */
.pkhead { display: grid; gap: var(--sp-lg); margin-bottom: var(--sp-lg); align-items: center; }
@media (min-width: 900px) {
  .pkhead { grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr); gap: clamp(36px, 5vw, 90px); }
  .pk-open { margin-bottom: 0; }
}
.pkhero { margin: 0; }
/* Cut out to true alpha, so it sits on the section's own ground instead
   of carrying a second beige rectangle that never quite matched --sand.
   Removing the ground also removed the baked contact shadow, so the
   objects get the same drop-shadow the other cutouts use. */
.pkhero img {
  width: 100%; height: auto;
  filter: drop-shadow(0 24px 34px rgba(12, 24, 36, .17));
}

/* The close: the delivery itself. */
.closegrid { display: grid; gap: var(--sp-xl); align-items: center; width: 100%; }
@media (min-width: 900px) {
  .closegrid { grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr); gap: clamp(40px, 6vw, 100px); }
}
.close { align-items: center; }
.close-copy { display: flex; flex-direction: column; align-items: flex-start; text-align: left; }
.close-copy .display { max-width: 12ch; }
.close-sub { text-align: left; max-width: 44ch; margin-top: var(--sp-md); }
.closefig { margin: 0; }
.closefig img { width: 100%; height: auto; border-radius: var(--r-card); }
.closefig__cap {
  margin-top: var(--sp-sm);
  font-size: var(--t-caption);
  color: var(--fg-dim);
  max-width: 46ch;
}

/* The closing clip. Sized by its poster so there is no layout shift when
   the video loads, and it degrades to that poster wherever motion is
   unwanted or the file is never fetched. */
.closefig__v { width: 100%; height: auto; display: block; border-radius: var(--r-card); background: var(--surface); }
@media (prefers-reduced-motion: reduce) { .closefig__v { pointer-events: none; } }

/* ═══ Linked rows ═══════════════════════════════════════════════════════
   Replaces link cards. A title and a description do not need a bordered
   box around them when a rule and consistent alignment already group
   them, and the whole row stays a single large target. */
.lrows { display: grid; border-top: 1px solid var(--rule-soft); }
.lrow {
  display: grid; gap: 4px;
  padding: var(--sp-md) 0;
  border-bottom: 1px solid var(--rule-soft);
  /* transform, not padding: animating padding relayouts the whole list on
     every frame, where a translate is composited. */
  transition: transform 260ms var(--ease);
}
@media (min-width: 640px) {
  .lrow { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); gap: var(--sp-lg); align-items: baseline; }
}
.lrow:hover, .lrow:focus-visible { transform: translateX(var(--sp-sm)); }
.lrow__t { font-weight: 600; color: var(--fg); }
.lrow:hover .lrow__t { color: var(--accent); }
.lrow__d { color: var(--fg-dim); font-size: var(--t-label); line-height: 1.55; }

/* The category index shows all six at equal weight, unlike the homepage,
   where the mailer leads, because here none of them is the subject. */
.pkgrid--even .pk--lead,
.pkgrid--even .pk { grid-column: auto; grid-row: auto; }
.pkgrid--even .pk__meta { line-height: 1.5; }

/* ═══ Packaging index film ══════════════════════════════════════════════
   The six formats falling and settling. This is a different page from the
   home hero, so it does not compete with the scroll-cycling; it is this
   page's one authored moment. Same guards as the closing clip: desktop
   only, on-white only, and preload="none" so the file is never fetched
   otherwise. */
.pkfilm { margin: 0 0 var(--sp-xl); }
.pkfilm video, .pkfilm img {
  width: 100%; display: block;
  /* Pinned rather than left to height:auto. A <video> with auto height
     takes its intrinsic ratio from whatever has loaded, with no clip
     fetched yet that is the poster, so a square poster produced a square
     box and the 16:9 clip then letterboxed inside it and shifted the
     page on load. */
  aspect-ratio: 16 / 9;
  height: auto;
  object-fit: cover;
  border-radius: var(--r-card);
  background: var(--surface);
}
.pkfilm__cap { margin-top: var(--sp-sm); font-size: var(--t-caption); color: var(--fg-dim); }
@media (prefers-reduced-motion: reduce) { .lrow { transition: none; } .lrow:hover { transform: none; } }

/* ═══ Pricing ═══════════════════════════════════════════════════════════
   Packwide has two propositions, not a matrix, so this is two figures at
   display scale rather than a pricing table with feature checkmarks. The
   number is the first thing read on each side; everything else supports
   it. No cards, a rule and alignment do the grouping.
   ═══════════════════════════════════════════════════════════════════════ */
.plans { display: grid; gap: var(--sp-2xl); }
@media (min-width: 860px) {
  .plans { grid-template-columns: 1fr 1fr; gap: clamp(48px, 7vw, 120px); }
}
.plan { display: flex; flex-direction: column; align-items: flex-start; border-top: 2px solid var(--fg); padding-top: var(--sp-lg); }
.plan__who { color: var(--fg-dim); font-weight: 500; }
.plan__fig {
  font-size: clamp(64px, 9vw, 128px);
  font-weight: 500;
  line-height: 0.88;
  letter-spacing: -0.03em;
  margin: var(--sp-md) 0 0;
  font-variant-numeric: tabular-nums;
}
.plan__unit { margin: var(--sp-sm) 0 0; font-size: var(--t-label); color: var(--fg-dim); letter-spacing: .01em; }
.plan__body { margin-top: var(--sp-lg); max-width: 42ch; }
.plan__list { list-style: none; margin: var(--sp-lg) 0 0; padding: 0; display: grid; gap: 0; width: 100%; }
.plan__list li {
  padding: var(--sp-sm) 0;
  border-top: 1px solid var(--rule-soft);
  font-size: var(--t-label);
  color: var(--fg-dim);
}
.plan__list li:last-child { border-bottom: 1px solid var(--rule-soft); }
.plan__note { margin: var(--sp-lg) 0 0; font-size: var(--t-label); color: var(--fg); max-width: 40ch; }
.plan__cta { margin-top: var(--sp-lg); }

/* The three zeroes. This is the claim competitors cannot copy, so it is
   set at figure scale rather than buried in a paragraph. */
.zeroes { display: grid; gap: var(--sp-lg); margin: var(--sp-xl) 0 0; }
@media (min-width: 700px) { .zeroes { grid-template-columns: repeat(3, 1fr); } }
.zeroes > div { border-top: 1px solid var(--rule); padding-top: var(--sp-md); }
.zeroes dt { font-size: clamp(34px, 4vw, 56px); font-weight: 500; line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.zeroes dd { margin: var(--sp-sm) 0 0; font-size: var(--t-label); color: var(--fg-dim); }

/* Store-count table. Real tabular data, so it is a real table. */
.ptable { width: 100%; border-collapse: collapse; margin-top: var(--sp-lg); font-size: var(--t-label); }
.ptable th {
  text-align: left; font-weight: 500; font-size: var(--t-caption); letter-spacing: -0.006em; color: var(--fg-dim);
  padding: 0 var(--sp-md) var(--sp-sm) 0; border-bottom: 1.5px solid var(--fg);
}
.ptable td { padding: var(--sp-md) var(--sp-md) var(--sp-md) 0; border-bottom: 1px solid var(--rule-soft); font-variant-numeric: tabular-nums; }
.ptable__fee { font-size: var(--t-sub); color: var(--fg); white-space: nowrap; }
.ptable tbody tr:last-child td { border-bottom: 1.5px solid var(--fg); }
.u-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* VAT qualifier. Set apart from the unit line so the figure reads clean,
   but never smaller than the caption size, a price qualifier is exactly
   the text that must not become fine print. */
.plan__vat {
  display: inline-block;
  margin-left: var(--sp-xs);
  padding: 2px 7px;
  border: 1px solid var(--rule);
  border-radius: var(--r-input);
  font-size: var(--t-caption);
  letter-spacing: -0.006em;
  color: var(--fg-dim);
  vertical-align: 1px;
}

/* ═══ Block architecture ════════════════════════════════════════════════
   Packhelp runs one continuous ground and lets rounded blocks carry the
   rhythm. That is not a style preference, ground-to-white measures
   1.06:1, so a full-bleed section-background change is close to invisible
   and the page ends up relying on length instead of contrast to separate
   ideas. A block has an edge you can actually see.

   Any section carrying a surface scope becomes an inset block. Sections
   without one sit directly on the ground and read as the connective
   tissue between blocks. */
/* One inset for the whole site. These were inset rounded blocks, which
   gave the page two competing left edges: the header, the footer and any
   section without a surface scope started at the gutter, while every
   scoped section started 43px further in, and the difference showed as
   soon as you scrolled or changed page. They are bands now, full width
   inside the shell, on the same gutter as everything else. The 88px of
   ground between consecutive sections is what separates them, which
   works even for a white band on the near-white ground. */
.section.on-white,
.section.on-ink,
.section.on-accent {
  width: 100%;
  border-block: 0;
  padding-inline: var(--gutter);
}

/* Consecutive blocks sit closer than a block sits to open ground, so a
   run of blocks reads as one passage rather than three separate ones. */
.section.on-white + .section.on-white,
.section.on-white + .section.on-ink,
.section.on-ink + .section.on-white { margin-top: var(--gap); }

/* Section rhythm, retuned. The old scale ran to 150px of padding on every
   section and pushed the page past 16 screens; Packhelp holds a whole
   homepage in 7.8. */
/* The 100vh on .section above is a leftover from the original "each
   section is a full viewport" structure. Every variant that came out of
   the rebuild sets `min-height: auto`, but `.section--tight` and
   `.section--wide` never did, so the problem block and the closing CTA
   were still stretched to a whole screen with their content floated in
   the middle, which read as ~400px of dead space on the homepage. The
   height of a section is the height of what is in it. */
.section          { padding-block: var(--sp-section); min-height: auto; }
.section--tight   { padding-block: clamp(40px, 4.5vw, 72px); }
.section--auto    { padding-block: var(--sp-section); min-height: auto; }
.section--wide    { padding-block: clamp(64px, 7vw, 112px); }

/* Openers are tighter too: the old 60px gap under a heading was sized for
   a page with far more room to spend. */
.sec-open  { margin-bottom: var(--sp-lg); }
.pk-open   { margin-bottom: var(--sp-lg); }
.sec-open .body,
.pk-open .body { margin-top: var(--sp-sm); }

/* ═══ Hover ═════════════════════════════════════════════════════════════
   Transform-only, 400ms, on the same expo-out curve as the reveals. The
   reference moves things rather than recolouring them, which is why its
   hovers read as physical; it also composites, where animating a box
   shadow or a size does not. */
.pk, .lrow, .specimen, .plan, .closefig, .pkhero, .anat, .ui-card {
  transition: transform var(--dur-hover) var(--ease),
              box-shadow var(--dur-hover) var(--ease);
}
.pk:hover, .pk:focus-visible,
.specimen:hover, .specimen:focus-visible { transform: translateY(-4px); }

/* Blocks lift very slightly and gain a soft shadow, so the surface reads
   as sitting on the ground rather than printed into it. */
.plan:hover, .ui-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }

.btn { transition: background-color var(--dur-tint) ease, border-color var(--dur-tint) ease, transform var(--dur-hover) var(--ease); }
.btn:hover { transform: translateY(-1px); }
.btn--filled:hover { box-shadow: var(--shadow-2); }

/* Photography lifts on hover where it is a link; static figures do not. */
a .scene img, .pk img { transition: transform var(--dur-hover) var(--ease); }
a:hover .scene img { transform: scale(1.02); }

/* ═══ Section flow ══════════════════════════════════════════════════════
   The reference does not cut between sections; each one arrives. Blocks
   settle in from slightly below with the same expo-out curve, so the page
   reads as continuous rather than as a stack of panels. */
.section.on-white,
.section.on-ink,
.section.on-accent {
  transition: transform var(--dur-reveal) var(--ease), opacity var(--dur-reveal) var(--ease);
}
.js .section.on-white:not(.in-view),
.js .section.on-ink:not(.in-view),
.js .section.on-accent:not(.in-view) {
  opacity: 0;
  transform: translateY(24px) scale(.994);
}

@media (prefers-reduced-motion: reduce) {
  .pk, .lrow, .specimen, .plan, .closefig, .pkhero, .anat, .ui-card, .btn,
  a .scene img, .pk img,
  .section.on-white, .section.on-ink, .section.on-accent { transition: none !important; }
  .pk:hover, .specimen:hover, .plan:hover, .ui-card:hover, .btn:hover,
  a:hover .scene img { transform: none !important; box-shadow: none !important; }
  .js .section.on-white:not(.in-view),
  .js .section.on-ink:not(.in-view),
  .js .section.on-accent:not(.in-view) { opacity: 1; transform: none; }
}

/* ═══ Problem, with a picture of the problem ════════════════════════════
   The section argued three costs in words and showed nothing. One box left
   on a shelf is the whole argument. */
.probhead { display: grid; gap: var(--sp-lg); align-items: center; margin-bottom: var(--sp-xl); }
@media (min-width: 900px) {
  .probhead { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); gap: clamp(32px, 5vw, 72px); }
}
.probfig { margin: 0; }
.probfig img, .probfig video {
  width: 100%; height: auto; display: block;
  border-radius: var(--r-block);
  background: var(--surface);
  transition: transform var(--dur-hover) var(--ease);
}
.probfig__cap { margin-top: var(--sp-sm); font-size: var(--t-caption); color: var(--fg-dim); }

/* A full-width band. The grid below names the formats; this shows them
   together at one scale, which the six separate cutouts never do. */
.pkband { margin: 0 0 var(--sp-xl); }
.pkband img {
  width: 100%; height: auto; display: block;
  border-radius: var(--r-block);
}


/* ═══ Formats, in one row ═══════════════════════════════════════════════
   The section previously showed the same six formats three times, a band
   photograph, a cutout group, and a grid, and ran 2,432px of content.
   The reference fits an entire box catalogue, thirty-four items, into
   277px by laying it out across rather than down.

   Six items fit a desktop row outright, so this is a row that becomes a
   scroller only when it has to. On a touch device that is the native
   gesture; on desktop nothing is ever hidden. */
.pkrow {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(148px, 1fr);
  gap: var(--sp-md);
  /* Without this a column-flow grid takes its content's width as its
     minimum and pushes the page wide instead of scrolling inside itself,
     six 148px cells overflowed the viewport by 644px on a phone. */
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  padding-bottom: var(--sp-sm);
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.pkrow > .pk { scroll-snap-align: start; }
.pkrow .pk img { width: 100%; height: auto; }
@media (min-width: 1000px) {
  /* Everything fits; no scrolling, no hidden content. */
  .pkrow { grid-auto-flow: row; grid-template-columns: repeat(6, 1fr); overflow-x: visible; }
}
.pkband { margin: 0 0 var(--sp-lg); }

/* ═══ Section rhythm ════════════════════════════════════════════════════
   The reference does not pad each section; it puts a fixed 96px spacer
   between them. The difference matters: padding on both sides doubles at
   every boundary, so a 104px scale produced 208px gaps that were never
   designed, only arrived at. One margin between siblings collapses to a
   single, predictable interval.

   Blocks keep their own inner padding, they are surfaces and need it,
   but the gap between sections is now one number. */
main > section + section { margin-top: var(--sp-2xl); }
main > section { padding-block: 0; }

/* A block's padding is its own inset, not page rhythm. */
.section.on-white,
.section.on-ink,
.section.on-accent { padding-block: clamp(40px, 4.5vw, 72px); }

/* The close keeps a little more air beneath it before the footer. */
.section.close { margin-bottom: var(--sp-xl); }

/* A flex item's automatic minimum size is its content's min-content width,
   so `.page__inner` refused to shrink below the widest thing inside it and
   pushed the page 644px wide on a phone. `min-width: 0` restores normal
   shrinking, which is what lets an inner scroller actually scroll. */
/* A definite width down the chain. Without it the inner box sizes to its
   widest content, `max-width: 100%` on a scroller inside resolves against
   a parent that is itself overflowing, and the page grows instead of the
   scroller scrolling, 644px of horizontal overflow on a phone. */
.section > .page__inner { width: 100%; min-width: 0; }

/* ═══ Flow rail ═════════════════════════════════════════════════════════
   The eight steps, across. Each card carries its own panel, so a step and
   the system state it produces travel together, which the sticky version
   only managed by keeping one shared panel and swapping its contents.

   This is the reference's collection pattern, and here it earns the
   scroller: eight cards never fit a line, so sideways is the only honest
   option short of stacking them down a second screen. */
.flow-rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(268px, 300px);
  gap: var(--sp-md);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  padding-bottom: var(--sp-md);
  min-width: 0;
  max-width: 100%;
  scrollbar-width: thin;
}
.flow-card {
  scroll-snap-align: start;
  display: flex; flex-direction: column;
  /* --surface, not --ground: on a tinted section a card painted with the
     ground colour disappears into it. */
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-block);
  padding: var(--sp-md);
}
.flow-card__n {
  font-size: var(--t-caption); font-weight: 500; color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.flow-card__h { margin: var(--sp-xs) 0 var(--sp-xs); }
.flow-card__b { font-size: var(--t-label); line-height: 1.5; margin-bottom: var(--sp-md); }
/* The panel sits at the foot of every card, so the eight line up. */
.flow-card__panel {
  margin-top: auto;
  background: var(--ground);
  border-radius: var(--r-outline);
  padding: var(--sp-sm) var(--sp-md);
  display: flex; flex-direction: column; gap: 2px;
}
.flow-card__panel .label { font-size: var(--t-caption); margin-bottom: var(--sp-xs); }
.flow-card__panel .srow { padding: 5px 0; }
.flow-card__panel .sfall { font-size: var(--t-label); }
.flow-card__panel .hui__steps li { padding: 5px 0 5px 20px; font-size: var(--t-caption); }

/* The rail's scrollbar, themed rather than left to the browser. */
.flow-rail::-webkit-scrollbar, .pkrow::-webkit-scrollbar { height: 8px; }
.flow-rail::-webkit-scrollbar-thumb, .pkrow::-webkit-scrollbar-thumb {
  background: var(--rule); border-radius: 999px;
}
.flow-rail::-webkit-scrollbar-track, .pkrow::-webkit-scrollbar-track { background: transparent; }

/* The band is atmosphere, not a subject. At 21:9 across a 1312px column it
   rendered 558px tall, a third of a screen for a decorative strip. Capped
   and cropped to the centre, where the objects are. */
.pkband img, .pkband video {
  width: 100%; height: auto; display: block;
  max-height: 340px; object-fit: cover; object-position: center;
  border-radius: var(--r-block);
  background: var(--surface);
}

/* Problem and money were the last two sections carrying more air than
   content: the reference's are 277-672px and these were 900 and 1110. */
.probhead { margin-bottom: var(--sp-lg); }
.probfig img, .probfig video { max-height: 320px; object-fit: cover; }
.tension-line { padding-block: var(--sp-sm); }
.assure { margin-top: var(--sp-lg); }
.assure__h { margin-bottom: var(--sp-md); }
.flow { gap: var(--sp-md); }

/* Three costs, three columns. They are siblings of equal weight, not a
   sequence, so stacking them spent a screen saying so. */
@media (min-width: 820px) {
  .tension-lines { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-lg); }
  .tension-line { padding-block: 0; border: 0; }
  .tension-line + .tension-line { border-top: 0; }
}
/* Two gains columns rather than one long list. Hiding items to save height
   was the wrong trade, "wholesale pricing" and "no minimum order" are two
   of the strongest things on the page. */
@media (min-width: 1100px) {
  .gains { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--sp-lg); }
  .gains > div { grid-template-columns: 1fr; }
  .gains > div:nth-child(-n+2) { border-top: 1px solid var(--rule-soft); }
}

/* ═══ Both sides ════════════════════════════════════════════════════════
   Two audiences, side by side. As mirrored full sections they cost two
   screens to say one thing, that this has two ends, and the mirroring
   read as repetition. Together the symmetry is the argument. */
.sides { display: grid; gap: var(--sp-xl); }
@media (min-width: 900px) { .sides { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-lg); } }
.side { display: flex; flex-direction: column; }
.side__media { margin-bottom: var(--sp-md); }
.side__media .scene { min-height: 0; aspect-ratio: 16 / 10; }
.side__h { margin-bottom: var(--sp-md); }
.side .gains { margin-bottom: var(--sp-md); }
.side .gains > div { padding: var(--sp-sm) 0; }
@media (min-width: 1100px) { .side .gains { grid-template-columns: 1fr; } }
.side > .btn { margin-top: auto; align-self: flex-start; }

/* The curve and the sequence in one section: the rail is what Packwide
   does, the curve is what it produces. They were two sections making one
   point. */
.howlead { display: grid; gap: var(--sp-lg); margin-bottom: var(--sp-xl); align-items: center; }
@media (min-width: 1200px) { .howlead { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); gap: var(--sp-xl); } }
.howlead__spec .spec { margin-top: var(--sp-sm); }
.howlead__spec .micro { margin-top: var(--sp-sm); }

/* The two audience photographs are supporting, not subjects. */
.side__media .scene { aspect-ratio: 16 / 9; }

/* ═══ Hero bar as a control ═════════════════════════════════════════════
   Six segments that already tracked the active format are now the way you
   choose it, so they need a real target and a visible focus state. */
.hbar { position: static; display: flex; gap: 6px; margin-top: var(--sp-md); }
.hbar span {
  /* Full width always; the inactive state is a scaleX, not a narrower box.
     Animating width relayouts the bar on every frame, the detector is
     right about that, where a transform composites. */
  width: 44px; height: 3px; border-radius: 999px;
  background: var(--rule); cursor: pointer;
  transform: scaleX(.64); transform-origin: left center;
  transition: background-color var(--dur-tint) ease, transform var(--dur-hover) var(--ease);
}
.hbar span:hover { background: var(--fg-faint); }
.hbar span:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
@media (min-width: 900px) { .hbar { margin-top: var(--sp-lg); } }

/* The active segment widens rather than only changing colour, so the state
   survives for anyone who cannot separate the two greys. */
.hstage[data-stage="mailer"]  ~ .hbar span:nth-child(1),
.hstage[data-stage="carton"]  ~ .hbar span:nth-child(2),
.hstage[data-stage="rigid"]   ~ .hbar span:nth-child(3),
.hstage[data-stage="tube"]    ~ .hbar span:nth-child(4),
.hstage[data-stage="padded"]  ~ .hbar span:nth-child(5),
.hstage[data-stage="folding"] ~ .hbar span:nth-child(6) { background: var(--accent); transform: scaleX(1); }

/* The scroll cue is gone with the scrolling it cued. */
.hcue { display: none; }

/* The visual bar is 3px tall, which is nowhere near a touch target. The
   pseudo-element extends the hit area to 44px without changing what is
   drawn, a 28x3px control is unusable on a phone and fails the minimum
   target size outright. */
.hbar span { position: relative; }
.hbar span::after {
  content: ""; position: absolute;
  left: 0; right: 0; top: 50%;
  height: 44px; transform: translateY(-50%);
}
.hbar { gap: 10px; }

@media (prefers-reduced-motion: reduce) { .hbar span { transition: none; } }

/* ═══ Tinted tiles ══════════════════════════════════════════════════════
   Each format sits on its own ground rather than all six sharing one. The
   colours are desaturated enough that ink clears 14.7:1 on every one, so
   the tint is decoration the labels never have to fight.

   Photography of kraft on six different grounds is also the honest way to
   show what printed packaging looks like, the alternative was six brown
   objects on one grey. */
.pk__tile {
  display: block;
  border-radius: var(--r-block);
  padding: var(--sp-md);
  overflow: clip;
  transition: transform var(--dur-hover) var(--ease);
}
.pk:nth-child(6n+1) .pk__tile { background: #DCE5D5; }  /* sage  */
.pk:nth-child(6n+2) .pk__tile { background: #F2DED6; }  /* blush */
.pk:nth-child(6n+3) .pk__tile { background: #EFE3CE; }  /* sand  */
.pk:nth-child(6n+4) .pk__tile { background: #D8E3F0; }  /* sky   */
.pk:nth-child(6n+5) .pk__tile { background: #E8DAD2; }  /* clay  */
.pk:nth-child(6n+6) .pk__tile { background: #DFE4E4; }  /* mist  */
.pk__tile img { width: 100%; height: auto; margin: 0; filter: none; }

/* ═══ Hover, extended ═══════════════════════════════════════════════════
   The reference moves things and lifts them; it does not recolour them. */
.pk:hover .pk__tile,
.pk:focus-visible .pk__tile { transform: translateY(-6px) scale(1.015); }
.pk:hover .pk__name { color: var(--accent); }

.flow-card { transition: transform var(--dur-hover) var(--ease), border-color var(--dur-tint) ease; }
.flow-card:hover { transform: translateY(-3px); border-color: var(--accent); }

.lrow__t, .pk__name { transition: color var(--dur-tint) ease; }

.probfig img, .pkband img, .closefig img, .side__media img {
  transition: transform var(--dur-hover) var(--ease);
}
figure:hover > img { transform: scale(1.015); }

/* Nav and footer links get the same treatment rather than none. */
.nav__links a, .menu__trigger, .foot__col a {
  transition: color var(--dur-tint) ease;
}
.foot__col a:hover { color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  .pk__tile, .flow-card, .probfig img, .pkband img, .closefig img, .side__media img { transition: none !important; }
  .pk:hover .pk__tile, .flow-card:hover, figure:hover > img { transform: none !important; }
}

/* ═══ At any volume ═════════════════════════════════════════════════════
   A near-black block carrying the capability list, then three cards that
   each demonstrate one thing instead of asserting it. */
.scale {
  position: relative;
  overflow: clip;
  isolation: isolate;
  background: #0B0D12;
  color: #FFFFFF;
  width: 100%;
  padding-block: clamp(44px, 5vw, 80px);
  --fg: #FFFFFF;
  --fg-dim: #A9AFBC;      /* 8.6:1 on #0B0D12 */
  --rule: #232733;
  --accent: #7C97FF;      /* the law: lighter blue on a dark ground */
  --accent-ink: #0B0D12;
}
/* The film and its veil. Everything else in the section sits above both. */
.scale__film {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: .55;
}
.scale__veil {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(to right, rgba(11,13,18,.97) 0%, rgba(11,13,18,.88) 46%, rgba(11,13,18,.72) 100%),
    linear-gradient(to bottom, rgba(11,13,18,.80), rgba(11,13,18,.92));
}
.scale > .page__inner { position: relative; z-index: 2; }

.scale__head { max-width: 62rem; }
.scale__h { margin: var(--sp-md) 0 var(--sp-lg); max-width: 30ch; }
@media (min-width: 900px) { .scale__h { max-width: 44ch; } }

/* The pill label. Reinstated deliberately because the reference uses it
   and it was asked for, the craft floor bans eyebrows, and this is an
   explicit override of that rule, not an oversight. */
.pill-label {
  display: inline-block;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  background: rgba(255,255,255,.09);
  color: #D5DAE5;
  font-size: var(--t-caption);
  font-weight: 500;
}

.ticks {
  list-style: none; margin: 0 0 var(--sp-lg); padding: 0;
  display: grid; gap: var(--sp-sm) var(--sp-lg);
  grid-template-columns: 1fr;
}
@media (min-width: 620px) { .ticks { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .ticks { grid-template-columns: repeat(4, 1fr); } }
.ticks li {
  position: relative; padding-left: 22px;
  font-size: var(--t-label); color: var(--fg-dim);
}
.ticks li::before {
  content: ""; position: absolute; left: 0; top: .45em;
  width: 11px; height: 6px;
  border-left: 1.5px solid var(--accent); border-bottom: 1.5px solid var(--accent);
  transform: rotate(-45deg);
}
.scale__cta { margin-bottom: var(--sp-xl); }
.scale__note { margin-top: var(--sp-md); color: #7E8598; }

/* ── The three cards ────────────────────────────────────────────────── */
.scale__cards { display: grid; gap: var(--gap); }
@media (min-width: 760px)  { .scale__cards { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .scale__cards { grid-template-columns: repeat(3, 1fr); } }

/* Each card is its own world: a saturated ground, a photograph sunk into
   it, soft shapes behind the content and floating elements that cast real
   shadows. Three grounds rather than two photos and a colour. */
.scard {
  position: relative; overflow: clip; isolation: isolate;
  border-radius: var(--r-block);
  min-height: 400px;
  display: flex; flex-direction: column;
  padding: var(--sp-md);
  background: var(--card-bg, #242F80);
  transition: transform var(--dur-hover) var(--ease), box-shadow var(--dur-hover) var(--ease);
}
.scard:nth-child(1) { --card-bg: #242F80; }   /* indigo, white reads 11.71:1 */
.scard:nth-child(2) { --card-bg: #9C3D1E; }   /* rust, white reads  6.77:1 */
.scard:nth-child(3) { --card-bg: #2AA391; }   /* teal, ink   reads  6.48:1 */

.scale__cards .scard:hover {
  transform: translateY(-8px);
  box-shadow: 0 22px 44px rgba(0,0,0,.34), 0 4px 10px rgba(0,0,0,.20);
}

/* The photograph sinks into the ground rather than sitting on it, so the
   card reads as one colour with an image in it. */
.scard__bg {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: .38;
  mix-blend-mode: luminosity;
}
.scard__veil {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(to top,
    color-mix(in srgb, var(--card-bg) 88%, transparent) 16%,
    color-mix(in srgb, var(--card-bg) 34%, transparent) 60%,
    color-mix(in srgb, var(--card-bg) 62%, transparent));
}

/* Shapes. Two soft discs per card, offset and blurred, so the ground has
   depth instead of being flat colour. Purely decorative and behind
   everything, so they never touch legibility. */
.scard::before,
.scard::after {
  content: ""; position: absolute; z-index: 0;
  border-radius: 50%; pointer-events: none;
  filter: blur(28px);
}
.scard::before {
  width: 58%; aspect-ratio: 1;
  top: -14%; right: -16%;
  background: rgba(255,255,255,.16);
}
.scard::after {
  width: 44%; aspect-ratio: 1;
  bottom: -12%; left: -14%;
  background: rgba(0,0,0,.22);
}

.scard__body { position: relative; z-index: 2; display: flex; flex-direction: column; height: 100%; }
.scard__h { color: #FFFFFF; max-width: 18ch; }

/* Floating chips and bubbles, each casting a real shadow so they read as
   lifted off the card rather than printed onto it. */
.chips-float { margin-top: auto; display: flex; flex-wrap: wrap; gap: 7px; }
.chipf {
  background: #FFFFFF; color: #0B0D12;
  font-size: var(--t-caption); font-weight: 500;
  padding: 8px 13px; border-radius: var(--r-pill);
  box-shadow: 0 6px 16px rgba(0,0,0,.26), 0 1px 3px rgba(0,0,0,.18);
  transition: transform var(--dur-hover) var(--ease);
}
.scard:hover .chipf { transform: translateY(-2px); }
.scard:hover .chipf:nth-child(2n) { transform: translateY(-4px); }
.chipf--go { background: #2757FF; color: #FFFFFF; }

.bubbles { margin-top: auto; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.bub {
  background: #FFFFFF; color: #0B0D12;
  font-size: var(--t-caption); line-height: 1.4;
  padding: 10px 14px; border-radius: 16px 16px 16px 5px;
  max-width: 92%;
  box-shadow: 0 6px 16px rgba(0,0,0,.26), 0 1px 3px rgba(0,0,0,.18);
}
.bub--me {
  background: #2757FF; color: #FFFFFF;
  align-self: flex-end; border-radius: 16px 16px 5px 16px;
}

/* The claim card takes ink rather than white, 6.48:1 on the teal, where
   white manages only 3.11 and fails. */
.scard--claim { color: #06231F; justify-content: flex-start; }
.scard--claim .scard__h { color: #06231F; }
.scard--claim::before { background: rgba(255,255,255,.26); }
.scard--claim::after  { background: rgba(0,60,50,.20); }
.scard__quote {
  position: relative; z-index: 2; margin: 0 0 var(--sp-md);
  font-size: var(--t-sub); font-weight: 500; line-height: 1.35;
  letter-spacing: -0.012em; max-width: 26ch;
}
.zeroes--card { display: flex; gap: var(--sp-lg); position: relative; z-index: 2; margin: 0; }
.zeroes--card dt { font-size: 34px; font-weight: 500; letter-spacing: -0.03em; line-height: 1; color: #06231F; }
.zeroes--card dd { margin: 4px 0 0; font-size: var(--t-caption); color: #06231F; opacity: 1; }
.scard__obj {
  position: absolute; right: -14%; bottom: -12%;
  width: 68%; height: auto; z-index: 1;
  filter: drop-shadow(0 22px 36px rgba(0,0,0,.32));
  transition: transform var(--dur-hover) var(--ease);
}
.scard--claim:hover .scard__obj { transform: translate(-8px,-8px) rotate(-3deg); }

@media (prefers-reduced-motion: reduce) {
  .scard, .scard__obj { transition: none !important; }
  .scale__cards .scard:hover, .scard--claim:hover .scard__obj { transform: none !important; }
}

/* ═══ Packaging tabs and rail control ═══════════════════════════════════
   Filter tabs and a next control, as the reference has. The tabs filter
   something real, every format carries a category, rather than being
   chrome that reorders nothing. */
.pkhead2 { display: grid; gap: var(--sp-md); }
.pill-label--light {
  background: rgba(0,6,26,.06);
  color: var(--fg-dim);
}

.pktabs {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: var(--sp-sm);
  margin-bottom: var(--sp-lg);
}
.pktabs__set {
  display: flex; gap: 4px; flex-wrap: wrap;
  background: var(--ground); border-radius: var(--r-pill); padding: 4px;
}
.pktab {
  border: 0; background: transparent; cursor: pointer;
  font: inherit; font-size: var(--t-label); font-weight: 500;
  color: var(--fg-dim); padding: 9px 16px; border-radius: var(--r-pill);
  transition: background-color var(--dur-tint) ease, color var(--dur-tint) ease;
}
.pktab:hover { color: var(--fg); }
.pktab[aria-selected="true"] {
  background: var(--surface); color: var(--fg);
  box-shadow: var(--shadow-1);
}
.pktab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn--sm { padding: 9px 16px; font-size: var(--t-label); }

.pkrail { position: relative; }
.railnext {
  position: absolute; right: -6px; top: 38%;
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface); color: var(--fg);
  border: 1px solid var(--rule); cursor: pointer;
  box-shadow: var(--shadow-2);
  transition: transform var(--dur-hover) var(--ease), background-color var(--dur-tint) ease;
}
.railnext:hover { transform: translateX(2px); background: var(--ground); }
.railnext:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Nothing to advance to once every format is on screen. */
@media (min-width: 1000px) { .railnext { display: none; } }

/* A filtered-out format leaves the row rather than dimming in place. */
.pk[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
  .pktab, .railnext { transition: none; }
  .railnext:hover { transform: none; }
}

/* ═══ Page heroes ═══════════════════════════════════════════════════════
   Every page opens on its own coloured band rather than a breadcrumb and
   a bare headline. The colour is per-page, so moving through the site
   feels like moving between rooms rather than scrolling one long document.

   Each tint is the same family as the packaging tiles and every one clears
   14.7:1 for ink, so the headline never fights its ground. */
.section.page {
  padding-block: clamp(44px, 6vw, 92px);
  padding-inline: var(--gutter);
  min-height: 0;
}
.page .crumb { margin-bottom: var(--sp-md); }
.page .display { max-width: 20ch; }
.page > .page__inner > .body { margin-top: var(--sp-md); }

/* The tinted heroes carry the same darker text tiers as the tinted body
   sections. They were setting only a background, so body copy kept the
   page default and landed at 4.1:1 on every one of them. A tint is darker
   than the ground it replaces; everything reading against it follows. */
.hero--sage, .hero--blush, .hero--sand,
.hero--sky, .hero--clay, .hero--mist {
  --surface:    var(--white);
  --fg-dim:     #59595D;
  --fg-faint:   #4E4E51;
  --accent:     #2350EA;
  --accent-ink: var(--white);
}
.hero--sage  { --ground: #DCE5D5; --rule: #C4D1BB; background: var(--ground); }
.hero--blush { --ground: #F2DED6; --rule: #E0C6BB; background: var(--ground); }
.hero--sand  { --ground: #EFE3CE; --rule: #DCCDB3; background: var(--ground); }
.hero--sky   { --ground: #D8E3F0; --rule: #BECBDC; background: var(--ground); }
.hero--clay  { --ground: #E8DAD2; --rule: #D5C2B7; background: var(--ground); }
.hero--mist  { --ground: #DFE4E4; --rule: #C8CFCF; background: var(--ground); }

/* Two darker rooms, for the two pages that are about the company rather
   than the product. Tokens are re-pointed so anything inside inherits. */
.hero--ink {
  background: #0B0D12; color: #FFFFFF;
  --fg: #FFFFFF; --fg-dim: #A9AFBC; --rule: #232733;
  --accent: #7C97FF; --accent-ink: #0B0D12;
}
.hero--accent {
  background: var(--cobalt); color: #FFFFFF;
  --fg: #FFFFFF; --fg-dim: #E8ECFF; --rule: #5570FF;
  --accent: #FFFFFF; --accent-ink: var(--cobalt);
}
.hero--ink .crumb a, .hero--accent .crumb a,
.hero--ink .crumb, .hero--accent .crumb { color: var(--fg-dim); }

/* ═══ Page hero, two columns ════════════════════════════════════════════
   Copy left, image right, matching the homepage's shape. Every page but
   the homepage opened on a headline over empty space; the right half was
   simply unused. */
.page__grid { display: grid; gap: var(--sp-lg); align-items: center; }
@media (min-width: 900px) {
  .page__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr); gap: clamp(32px, 5vw, 72px); }
}
.phero__media { margin: 0; }
.phero__media img {
  width: 100%; height: auto; display: block;
  border-radius: var(--r-block);
  transition: transform var(--dur-hover) var(--ease);
}
.page:hover .phero__media img { transform: translateY(-4px); }
@media (prefers-reduced-motion: reduce) {
  .phero__media img { transition: none; }
  .page:hover .phero__media img { transform: none; }
}

/* ═══ Body-section grounds ══════════════════════════════════════════════
   Pages ran white all the way down after their hero. These rotate through
   the same surfaces the homepage uses, so a page reads as a sequence of
   rooms rather than one long sheet. Applied as blocks, inset and rounded,
   exactly like the homepage's. */
.section.on-mist,
.section.on-sand,
.section.on-sage,
.section.on-blush,
.section.on-clay,
.section.on-sky {
  width: 100%;
  padding-inline: var(--gutter);
  padding-block: clamp(40px, 4.5vw, 72px);
}
/* Each carries the darker text tiers a tint needs, the page defaults are
   tuned for #F8F8F8 and fail on anything darker. */
.on-mist, .on-sand, .on-sage, .on-blush, .on-clay, .on-sky {
  --surface:    var(--white);
  --fg-dim:     #59595D;
  --fg-faint:   #4E4E51;
  --accent:     #2350EA;
  --accent-ink: var(--white);
}
.on-mist  { --ground: #DFE4E4; --rule: #C8CFCF; --rule-soft: #D4DADA; background: var(--ground); }
.on-sand  { --ground: #EFE3CE; --rule: #DCCDB3; --rule-soft: #E5D8C1; background: var(--ground); }
.on-sage  { --ground: #DCE5D5; --rule: #C4D1BB; --rule-soft: #D0DBC8; background: var(--ground); }
.on-blush { --ground: #F2DED6; --rule: #E0C6BB; --rule-soft: #E9D3C9; background: var(--ground); }
.on-clay  { --ground: #E8DAD2; --rule: #D5C2B7; --rule-soft: #DFCEC5; background: var(--ground); }
.on-sky   { --ground: #D8E3F0; --rule: #BECBDC; --rule-soft: #CBD6E4; background: var(--ground); }

/* ═══ Flow cards: colour, shapes, shadow, slide ═════════════════════════
   Eight steps, eight saturated worlds, the same treatment as the cards in
   the At-any-volume block, rather than eight pale tints.

   Every ground carries white at 6.77:1 or better and body copy at 4.92:1
   or better; the data panel inside each stays white, where ink reads at
   20:1. Nothing on these cards depends on a colour being light. */
.flow-card:nth-child(8n+1) { --card: #242F80; }  /* indigo */
.flow-card:nth-child(8n+2) { --card: #14655A; }  /* teal   */
.flow-card:nth-child(8n+3) { --card: #9C3D1E; }  /* rust   */
.flow-card:nth-child(8n+4) { --card: #1C3FBF; }  /* cobalt */
.flow-card:nth-child(8n+5) { --card: #5B2A6E; }  /* plum   */
.flow-card:nth-child(8n+6) { --card: #1B5E43; }  /* forest */
.flow-card:nth-child(8n+7) { --card: #2B3A55; }  /* slate  */
.flow-card:nth-child(8n+8) { --card: #7A4E08; }  /* ochre  */

.flow-card {
  position: relative;
  overflow: clip;
  isolation: isolate;
  scroll-snap-align: start;
  display: flex; flex-direction: column;
  background: var(--card, #242F80);
  border: 0;
  border-radius: var(--r-block);
  padding: var(--sp-md);
  will-change: transform;
  /* Text tiers for a dark card. The page defaults are tuned for a light
     ground and would be unreadable on every one of these. */
  --fg:       #FFFFFF;
  --fg-dim:   #D6DCE6;
  --fg-faint: #D6DCE6;
  color: var(--fg);
  transition: transform var(--dur-hover) var(--ease),
              box-shadow var(--dur-hover) var(--ease);
}

/* Two soft discs behind the content, giving the ground depth rather than
   flat fill. Decorative, behind everything, never touching legibility. */
.flow-card::before,
.flow-card::after {
  content: ""; position: absolute; z-index: 0;
  border-radius: 50%; pointer-events: none; filter: blur(26px);
}
.flow-card::before {
  width: 62%; aspect-ratio: 1; top: -16%; right: -18%;
  background: rgba(255,255,255,.15);
}
.flow-card::after {
  width: 48%; aspect-ratio: 1; bottom: -14%; left: -16%;
  background: rgba(0,0,0,.24);
}
.flow-card > * { position: relative; z-index: 1; }

.flow-card__n { color: var(--fg-dim); font-variant-numeric: tabular-nums; font-size: var(--t-caption); font-weight: 500; }
.flow-card__h { margin: var(--sp-xs) 0; color: #FFFFFF; }
.flow-card__b { font-size: var(--t-label); line-height: 1.5; margin-bottom: var(--sp-md); color: var(--fg-dim); }

/* The panel stays white and keeps the page's own dark text, so the data
   inside reads exactly as it does everywhere else on the site. */
.flow-card__panel {
  margin-top: auto;
  background: #FFFFFF;
  border-radius: var(--r-outline);
  padding: var(--sp-sm) var(--sp-md);
  display: flex; flex-direction: column; gap: 2px;
  box-shadow: 0 8px 20px rgba(0,0,0,.24), 0 1px 3px rgba(0,0,0,.16);
  --fg: #00061A; --fg-dim: #566069; --fg-faint: #626A72;
  --rule: #E4E4E6; --rule-soft: #EFEFF1; --accent: #2350EA;
  color: var(--fg);
  transition: transform var(--dur-hover) var(--ease);
}
.flow-card__panel .label { font-size: var(--t-caption); margin-bottom: var(--sp-xs); color: var(--fg-dim); }
.flow-card__panel .srow {
  padding: 5px 0;
  /* The panel is 228px wide at its narrowest; a label and a status pill
     side by side crushed the label to 42px and clipped it. Let the row
     wrap instead of squeezing. */
  flex-wrap: wrap; gap: 4px 10px;
}
.flow-card__panel .sfall { font-size: var(--t-label); }
.flow-card__panel .hui__steps li { padding: 5px 0 5px 20px; font-size: var(--t-caption); }

/* Rise, with the shadow arriving as it lifts and the panel lifting a
   little further so the card gains depth rather than moving as one slab. */
.flow-card:hover,
.flow-card:focus-within {
  transform: translateY(-10px);
  box-shadow: 0 22px 40px rgba(11, 20, 40, .30), 0 4px 10px rgba(11, 20, 40, .18);
  z-index: 2;
}
.flow-card:hover .flow-card__panel { transform: translateY(-3px); }

.flow-rail { scroll-behavior: auto; }
.flow-rail::-webkit-scrollbar, .pkrow::-webkit-scrollbar { height: 8px; }
.flow-rail::-webkit-scrollbar-thumb, .pkrow::-webkit-scrollbar-thumb { background: var(--rule); border-radius: 999px; }
.flow-rail::-webkit-scrollbar-track, .pkrow::-webkit-scrollbar-track { background: transparent; }

@media (prefers-reduced-motion: reduce) {
  .flow-card, .flow-card__panel { transition: none !important; }
  .flow-card:hover, .flow-card:focus-within,
  .flow-card:hover .flow-card__panel { transform: none !important; box-shadow: none !important; }
}

