/* ==========================================================================
   Takumi Ceremonial Matcha Soft Serve — Majors Group
   Mobile-first. Fluid type and spacing via clamp(); layout via grid auto-fit
   so every section reflows without breakpoint gaps.
   ========================================================================== */

/* ---------- tokens ---------- */
:root {
  /* palette sampled from the Majors / Rubicone artwork */
  --forest:      #0d4612;
  --forest-mid:  #1b5423;
  --forest-soft: #2f6a33;
  --olive:       #758339;
  /* Darker olive for small text: --olive is only 3.3:1 on the cream ground,
     which is fine for large display type and icons but under AA below ~24px. */
  --olive-text:  #5a6429;
  --matcha:      #8ca83c;
  --matcha-lite: #b7cd6a;

  --paper:       #ece5db;
  --paper-lite:  #f4efe7;
  --paper-warm:  #e1d9d0;
  --band:        #d2cdb3;
  --stamp-red:   #b8392c;

  --ink:         #24331f;
  --ink-soft:    #4d5b46;
  --on-dark:     #eef3e6;
  --on-dark-dim: #bccdb0;

  /* type */
  --font-display: "Playfair Display", "Iowan Old Style", Georgia, serif;
  --font-sans: "Jost", "Avenir Next", "Segoe UI", system-ui, sans-serif;

  --step--1: clamp(0.82rem, 0.79rem + 0.15vw, 0.9rem);
  --step-0:  clamp(1rem, 0.96rem + 0.2vw, 1.09rem);
  --step-1:  clamp(1.1rem, 1.03rem + 0.35vw, 1.3rem);
  --step-2:  clamp(1.3rem, 1.16rem + 0.7vw, 1.75rem);
  --step-3:  clamp(1.65rem, 1.35rem + 1.5vw, 2.6rem);
  --step-4:  clamp(2.1rem, 1.5rem + 3vw, 4rem);
  --step-5:  clamp(2.5rem, 1.5rem + 5vw, 5.5rem);

  /* rhythm */
  --gutter: clamp(1.15rem, 4vw, 3rem);
  --section-y: clamp(3.5rem, 8vw, 7.5rem);
  --shell: 1200px;

  --radius: 14px;
  --radius-lg: 26px;
  --shadow-sm: 0 2px 10px rgba(13, 70, 18, 0.07);
  --shadow-md: 0 14px 34px -14px rgba(13, 70, 18, 0.28);
  --shadow-lg: 0 30px 70px -28px rgba(13, 70, 18, 0.42);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --header-h: 68px;
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 12px);
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--step-0);
  font-weight: 300;
  line-height: 1.65;
  color: var(--ink);
  background-color: var(--paper);
  background-image: url("assets/paper.jpg");
  background-size: 620px auto;
  background-repeat: repeat;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; height: auto; }
ul, ol { margin: 0; padding: 0; list-style: none; }
p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }
a { color: inherit; text-decoration: none; }

h1, h2, h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.1;
  color: var(--forest);
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

.skip-link {
  position: fixed; top: 0; left: 50%;
  transform: translate(-50%, -120%);
  z-index: 200;
  padding: 0.7em 1.4em;
  background: var(--forest); color: var(--on-dark);
  border-radius: 0 0 10px 10px;
  font-size: var(--step--1); letter-spacing: 0.06em; text-transform: uppercase;
  transition: transform 0.2s var(--ease);
}
.skip-link:focus { transform: translate(-50%, 0); }

:focus-visible {
  outline: 2px solid var(--olive);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- layout primitives ---------- */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  position: relative;
  padding-block: var(--section-y);
  overflow: clip;
}

.section--tint {
  background: linear-gradient(180deg, rgba(210, 205, 179, 0.34), rgba(210, 205, 179, 0.14));
}

.section--dark {
  background: var(--forest);
  color: var(--on-dark);
}
.section--dark h2, .section--dark h3 { color: var(--on-dark); }

.section__head {
  max-width: 46ch;
  margin-bottom: clamp(2.2rem, 5vw, 3.75rem);
}
.section__title { font-size: var(--step-3); }
.section__title span { display: block; color: var(--olive); }
.section--dark .section__title span { color: var(--matcha-lite); }
.section__sub {
  margin-top: 0.85em;
  color: var(--ink-soft);
  font-size: var(--step-1);
  font-weight: 300;
}
.section__head--light .section__sub { color: var(--on-dark-dim); }

/* Title on the left, one action on the right. The head keeps its own max-width
   so the CTA is pushed by the bar, not by a long heading. */
.section__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: clamp(1.2rem, 3vw, 2.5rem);
  margin-bottom: clamp(2.2rem, 5vw, 3.75rem);
}
.section__head--flush { margin-bottom: 0; }
.section__bar-cta { flex: none; }
.section__bar-cta svg { flex: none; }

.eyebrow {
  margin: 0 0 0.6em;
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--olive-text);
}
.eyebrow::after {
  content: "";
  display: block;
  width: 44px; height: 1px;
  margin-top: 0.9em;
  background: currentColor;
  opacity: 0.5;
}
.section--dark .eyebrow { color: var(--matcha-lite); }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 0.5em;
  padding: 0.85em 1.6em;
  border: 1px solid transparent;
  border-radius: 100px;
  font-family: var(--font-sans);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease),
              transform 0.25s var(--ease), box-shadow 0.25s var(--ease),
              border-color 0.25s var(--ease);
}
.btn--lg { padding: 1.05em 2.1em; }

.btn--primary {
  background: var(--forest);
  color: var(--on-dark);
  box-shadow: var(--shadow-md);
}
.btn--primary:hover { background: var(--forest-soft); transform: translateY(-2px); }

.btn--ghost {
  border-color: rgba(13, 70, 18, 0.28);
  color: var(--forest);
}
.btn--ghost:hover { border-color: var(--forest); background: rgba(13, 70, 18, 0.06); }

/* For use on the green bands, where btn--primary would disappear. */
.btn--light {
  background: var(--paper-lite);
  color: var(--forest);
  box-shadow: 0 14px 30px -14px rgba(0, 0, 0, 0.45);
}
.btn--light:hover { background: #fff; transform: translateY(-2px); }

/* ---------- header ---------- */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: rgba(236, 229, 219, 0.82);
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  border-bottom: 1px solid rgba(13, 70, 18, 0.09);
  transition: box-shadow 0.3s var(--ease), background-color 0.3s var(--ease);
}
.site-header.is-stuck {
  background: rgba(240, 234, 225, 0.95);
  box-shadow: 0 6px 22px -12px rgba(13, 70, 18, 0.35);
}

.header-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem;
  min-height: var(--header-h);
}

.brand { display: flex; align-items: center; gap: 0.75rem; min-width: 0; }
.brand__home { display: block; flex: none; }
.brand__logo { width: clamp(78px, 11vw, 104px); height: auto; }
.brand__home .brand__logo,
.footer__home .footer__logo { transition: opacity 0.25s var(--ease); }
.brand__home:hover .brand__logo,
.footer__home:hover .footer__logo { opacity: 0.7; }
.brand__divider {
  width: 1px; height: 30px;
  background: rgba(13, 70, 18, 0.2);
}
.brand__text { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.brand__eyebrow {
  font-size: 0.6rem; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--olive-text);
}
/* Below ~380px the two-line brand lockup crowds the hamburger. */
@media (max-width: 380px) {
  .brand__eyebrow { display: none; }
}
.brand__name {
  font-family: var(--font-display);
  font-size: clamp(0.95rem, 2.4vw, 1.1rem);
  font-weight: 600;
  color: var(--forest);
  white-space: nowrap;
}

.nav__list { display: flex; }
.nav__list a {
  position: relative;
  display: block;
  padding: 0.4em 0;
  font-size: var(--step--1);
  font-weight: 400;
  letter-spacing: 0.04em;
  color: var(--ink);
}
.nav__list a::after {
  content: "";
  position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1.5px;
  background: var(--olive);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.28s var(--ease);
}
.nav__list a:hover::after,
.nav__list a[aria-current="true"]::after { transform: scaleX(1); }
.nav__list a[aria-current="true"] { color: var(--forest); font-weight: 500; }

.nav-toggle {
  display: grid; place-items: center;
  width: 44px; height: 44px;
  padding: 0; margin-right: -6px;
  background: transparent;
  border: 1px solid rgba(13, 70, 18, 0.2);
  border-radius: 10px;
  color: var(--forest);
  cursor: pointer;
}
.nav-toggle__bars { display: grid; gap: 4px; width: 19px; }
.nav-toggle__bars i {
  display: block; height: 1.5px;
  background: currentColor;
  transition: transform 0.28s var(--ease), opacity 0.2s var(--ease);
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

/* mobile nav panel */
@media (max-width: 900px) {
  .nav {
    position: fixed; inset: var(--header-h) 0 auto 0;
    display: grid; gap: 0.35rem;
    padding: 1.25rem var(--gutter) 1.75rem;
    background: var(--paper-lite);
    border-bottom: 1px solid rgba(13, 70, 18, 0.12);
    box-shadow: 0 24px 40px -24px rgba(13, 70, 18, 0.45);
    transform: translateY(-105%);
    visibility: hidden;
    transition: transform 0.36s var(--ease), visibility 0.36s;
  }
  .nav.is-open { transform: translateY(0); visibility: visible; }
  .nav__list { flex-direction: column; }
  .nav__list a {
    padding: 0.7em 0;
    font-size: var(--step-1);
    border-bottom: 1px solid rgba(13, 70, 18, 0.08);
  }
  .nav__list a::after { display: none; }
  .nav__cta { margin-top: 0.9rem; justify-self: start; }
}

@media (min-width: 901px) {
  .nav { display: flex; align-items: center; gap: clamp(1.1rem, 2.4vw, 2.1rem); }
  .nav__list { gap: clamp(1.1rem, 2.2vw, 2rem); }
  .nav-toggle { display: none; }
  /* Longer CTA label than the nav links can spare — tighten it so the header
     row never wraps between 901px and ~1150px. */
  .nav__cta { padding: 0.8em 1.25em; letter-spacing: 0.07em; white-space: nowrap; }
}

/* ---------- section photo grounds ---------- */
/* Every band keeps its own background colour; the photo rides above that colour
   at low opacity and below the content. Photos are used uncut — their own
   backdrop (cream marble, dark green) is part of the wash, so light photos go
   on the paper sections and dark ones on the green bands.
   Stacking inside a section: colour -> accent gradient -> .sec-bg -> .shell. */
.sec-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  /* Sized off the file's own width rather than cover: cover blew a 1400px photo
     up to whatever the band measured, which is where the softness came from.
     --bgw caps it near native pixels and the band colour fills the rest. */
  --bgw: 820px;
  --bgpos: center;
  background-position: var(--bgpos);
  background-size: min(100%, var(--bgw)) auto;
  background-repeat: no-repeat;
  pointer-events: none;
  user-select: none;
  /* The mask is sized and placed like the photo, not like the band, so the
     feather always lands on the photo's own edges — otherwise a shrunk photo
     ends mid-band and shows a slab edge. */
  mask-image: radial-gradient(ellipse closest-side, #000 42%, rgba(0, 0, 0, 0.4) 76%, transparent 100%);
  mask-size: min(100%, var(--bgw)) auto;
  mask-position: var(--bgpos);
  mask-repeat: no-repeat;
  -webkit-mask-image: radial-gradient(ellipse closest-side, #000 42%, rgba(0, 0, 0, 0.4) 76%, transparent 100%);
  -webkit-mask-size: min(100%, var(--bgw)) auto;
  -webkit-mask-position: var(--bgpos);
  -webkit-mask-repeat: no-repeat;
}

/* The light sections leave .shell static, so it needs its own layer to sit
   above the photo. The dark ones already do this a few rules down. */
.section > .shell { position: relative; z-index: 1; }

.sec-bg--hero      { background-image: url("assets/bg-powder-arc.webp"); --bgpos: 18% 55%; --bgw: 700px; opacity: 0.16; }
.sec-bg--statement { background-image: url("assets/bg-whisk-drip.webp"); --bgpos: 72% 40%; --bgw: 880px; opacity: 0.24; }
.sec-bg--benefits  { background-image: url("assets/bg-bowl-powder.webp"); --bgpos: 85% 50%; --bgw: 760px; opacity: 0.15; }
.sec-bg--journey   { background-image: url("assets/bg-whisk-powder.webp"); --bgpos: 50% 60%; --bgw: 900px; opacity: 0.15; }
.sec-bg--serving   { background-image: url("assets/bg-powder-streak.webp"); --bgpos: 30% 45%; --bgw: 900px; opacity: 0.16; }
.sec-bg--offer     { background-image: url("assets/bg-foam-whisk.webp"); --bgpos: 60% 50%; --bgw: 820px; opacity: 0.18; }
.sec-bg--order     { background-image: url("assets/bg-tea-sprig.webp"); --bgpos: 25% 50%; --bgw: 880px; opacity: 0.22; }

/* A phone band is narrow enough that the photo fills it edge to edge, so the
   wash competes with the copy — ease it back. */
@media (max-width: 780px) {
  .sec-bg { opacity: 0.1; }
}

/* ---------- hero ---------- */
.hero {
  position: relative;
  padding-block: clamp(2.5rem, 7vw, 5.5rem) clamp(3rem, 8vw, 6rem);
  overflow: clip;
}
.hero::before {
  content: "";
  position: absolute; inset: 0;
  background:
    radial-gradient(60% 55% at 78% 32%, rgba(140, 168, 60, 0.2), transparent 70%),
    radial-gradient(50% 45% at 8% 88%, rgba(117, 131, 57, 0.14), transparent 70%);
  pointer-events: none;
}

/* On narrow screens the product shot sits between the headline and the CTAs so
   it lands above the fold; on wide screens it moves into a second column and
   spans both text rows. */
.hero__inner {
  position: relative; z-index: 1;
  display: grid;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
  grid-template-areas: "lede" "media" "cta";
}

.hero__lede { grid-area: lede; text-align: center; }
.hero__media { grid-area: media; }
.hero__cta   { grid-area: cta; }

/* Brand lockup, not type: the wrapper only carries the rhythm, the logo carries
   the size. Floored at 148px — below that the "gelato & pastry est. 1959" line
   in the artwork stops resolving. */
.hero__brand {
  margin: 0;
  line-height: 0;
}
.hero__brand img {
  width: clamp(148px, 16vw, 224px);
  height: auto;
}

/* "Ceremonial Takumi" is the longest line in the block, so the scale is tuned to
   hold that line — not the shorter "Matcha" — inside the lede column. */
.hero__title {
  margin-top: 0.3em;
  font-size: clamp(2rem, 0.4rem + 3.35vw, 3.7rem);
  font-weight: 700;
  line-height: 1.02;
  text-transform: uppercase;
  letter-spacing: -0.015em;
}
.hero__title-line { display: block; white-space: nowrap; }
.hero__title-sub {
  display: block;
  font-size: 0.66em;
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--olive);
  /* em-based, so the gap tracks the larger size rather than growing with it */
  margin-top: 0.3em;
}

/* Divider between the title block and the supporting copy. */
.hero__rule {
  display: block;
  width: 72px; height: 2px;
  margin: 1.25em auto;
  background: linear-gradient(to right, var(--olive), rgba(117, 131, 57, 0));
  border-radius: 2px;
}

.hero__sub {
  margin: 0 auto;
  max-width: 48ch;
  font-size: var(--step-1);
  color: var(--ink-soft);
  text-wrap: pretty;
}

.hero__origin {
  display: flex; flex-wrap: wrap;
  justify-content: center;
  gap: 0.3em 0.75em;
  margin-top: 1.15em;
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--olive-text);
}
/* Separator trails its own item so a wrap never starts a line with a dot. */
.hero__origin li { display: flex; align-items: center; gap: 0.75em; }
.hero__origin li:not(:last-child)::after {
  content: "";
  width: 4px; height: 4px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
}

.hero__actions {
  display: flex; flex-wrap: wrap; gap: 0.75rem;
  justify-content: center;
}

.hero__stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(0.5rem, 2vw, 1.5rem);
  margin-top: clamp(1.5rem, 4vw, 2.25rem);
  padding-top: clamp(1.25rem, 3vw, 1.75rem);
  border-top: 1px solid rgba(13, 70, 18, 0.14);
  text-align: center;
}
.hero__stats li { display: flex; flex-direction: column; gap: 0.15em; }
.hero__stats strong {
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 600;
  line-height: 1;
  color: var(--forest);
}
.hero__stats small { font-size: 0.46em; font-weight: 500; letter-spacing: 0.04em; }
.hero__stats-pre { margin-right: 0.3em; letter-spacing: 0.06em; }
.hero__stats span {
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.hero__media {
  position: relative;
  display: grid;
  place-items: center;
  isolation: isolate;
}
.hero__glow {
  position: absolute;
  z-index: -1;
  width: 82%; aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0) 68%);
}
/* Container queries so the stamps and kanji scale with the bowl, not the
   viewport — sized off vw they swallowed the product in the 860–1100 band. */
/* Sized in vw, not %: the frame sits in a shrink-to-fit grid track, where a
   percentage resolves against a track that is itself content-sized. */
.hero__frame {
  position: relative;
  container-type: inline-size;
  width: min(88vw, 540px);
}
.hero__product {
  position: relative; z-index: 2;
  display: block;
  width: 100%; height: auto;
  filter: drop-shadow(0 34px 42px rgba(13, 70, 18, 0.26));
  animation: float-y 7s ease-in-out infinite;
}

/* Still life around the product, laid out like the reference shot: dusted
   powder as the ground plane, bowl of powder set behind on the right, leaves
   and dosing spoon in front. All sized in cqw so the group scales together. */
.prop {
  position: absolute;
  height: auto;
  /* The global img reset caps width at 100%, which silently pinned the powder
     spread to the frame width — it can never read as ground that wide. */
  max-width: none;
  pointer-events: none;
}
/* Squashed on purpose: the dusting has to read as a ground plane under the bowl,
   not a cloud behind the swirl. */
.prop--spread {
  left: -28%; bottom: -14%;
  z-index: 0;
  width: 156cqw; height: 40cqw;
  opacity: 0.85;
}
.prop--bowl {
  right: -4%; bottom: 11%;
  z-index: 1;
  width: 30cqw;
  filter: drop-shadow(0 12px 16px rgba(13, 70, 18, 0.24));
}
.prop--leaf {
  left: -3%; bottom: 5%;
  z-index: 3;
  width: 34cqw;
  filter: drop-shadow(0 10px 14px rgba(13, 70, 18, 0.2));
}
/* Laid flat under the product bowl. The source spoon rises ~20° to the right,
   so the rotation is what levels it, not what tilts it. */
.prop--spoon {
  left: 25%; bottom: -8%;
  z-index: 4;
  width: 46cqw;
  transform: rotate(20deg);
  filter: drop-shadow(0 12px 14px rgba(13, 70, 18, 0.22));
}
/* Single column: the frame already fills the gutter, so anything hanging off its
   right edge gets clipped mid-object. Tuck the group inboard. */
@media (max-width: 859px) {
  .prop--spread { left: -14%; width: 128cqw; height: 34cqw; }
  .prop--bowl { right: 2%; width: 28cqw; }
  .prop--spoon { left: 20%; width: 42cqw; }
}

@keyframes float-y {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-11px); }
}

/* 抹茶 over the Kagoshima stamp, stacked down the left of the bowl. One asset,
   so the kanji and the stamp can never drift apart at odd viewports. */
.hero__mark {
  position: absolute;
  left: 18%; top: 6%;
  z-index: 5;
  width: clamp(46px, 13cqw, 92px);
  height: auto;
  opacity: 0.85;
}

/* stamps */
.stamp { position: absolute; z-index: 2; }

.stamp--premium {
  top: 13%; right: 15%;
  display: grid; place-content: center;
  gap: 2px;
  width: clamp(60px, 19cqw, 104px); aspect-ratio: 1;
  border: 1.5px solid var(--forest);
  border-radius: 50%;
  background: rgba(244, 239, 231, 0.72);
  backdrop-filter: blur(3px);
  text-align: center;
  font-size: clamp(0.44rem, 1.9cqw, 0.62rem);
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--forest);
}
.stamp__peak {
  display: block;
  /* Bigger than the old inline SVG: the artwork carries finer ridge detail that
     disappears below ~28px. */
  width: clamp(26px, 7.5cqw, 42px); height: auto;
  margin: 1px auto;
  opacity: 0.9;
}

@media (min-width: 860px) {
  .hero__inner {
    grid-template-columns: 1.15fr 0.95fr;
    grid-template-areas:
      "lede  media"
      "cta   media";
    align-content: center;
    column-gap: clamp(2rem, 5vw, 4rem);
    row-gap: clamp(1.75rem, 4vw, 2.75rem);
  }
  .hero__lede { text-align: left; }
  .hero__sub { margin-inline: 0; }
  .hero__rule { margin-inline: 0; }
  .hero__origin { justify-content: flex-start; }
  .hero__actions { justify-content: flex-start; }
  .hero__stats { text-align: left; }
  /* Product runs wider than its column and bleeds into the column gap and the
     gutter — the hero clips, so the extra width costs no horizontal scroll. */
  .hero__frame { width: min(42vw, 392px); }
  .hero__glow { width: 100%; }
}

/* Past 1100px the nowrap title is what floors the text track, so give it exactly
   its min-content and hand every remaining pixel to the product. */
@media (min-width: 1100px) {
  .hero__inner { grid-template-columns: min-content minmax(0, 1fr); }
  .hero__frame { width: min(42vw, 540px); }
}

/* ---------- statement band ---------- */
.statement {
  position: relative;
  padding-block: clamp(2.75rem, 6vw, 4.5rem);
  background: var(--forest);
  color: var(--on-dark);
}
.statement::after {
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(70% 120% at 88% 50%, rgba(140, 168, 60, 0.3), transparent 65%);
  pointer-events: none;
}

.statement__inner {
  position: relative; z-index: 1;
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: center;
}

.statement__line {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 600;
  line-height: 1.15;
}
.statement__line--muted { color: var(--on-dark-dim); opacity: 0.8; }

.statement__body { font-size: var(--step-1); color: var(--on-dark-dim); }
.statement__body strong { color: #fff; font-weight: 500; }
.statement__tag {
  margin-top: 1em;
  padding-top: 1em;
  border-top: 1px solid rgba(238, 243, 230, 0.22);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--matcha-lite);
}

@media (min-width: 820px) {
  .statement__inner { grid-template-columns: 1fr 1fr; }
  .statement__body { padding-left: clamp(1.5rem, 4vw, 3rem); border-left: 1px solid rgba(238, 243, 230, 0.18); }
}

/* ---------- early bird offer (statement band variant) ---------- */
/* A shade lighter than the other two green bands so they stay distinguishable
   as you scroll. All text on it still clears AA. */
.statement--promo {
  padding-block: clamp(3rem, 7vw, 5.5rem);
  background: var(--forest-mid);
  overflow: clip;
}
/* Accent mirrored to the left so the two green bands don't read as duplicates. */
.statement--promo::after {
  background: radial-gradient(65% 120% at 12% 45%, rgba(140, 168, 60, 0.34), transparent 62%);
}

.promo__flag {
  display: inline-block;
  margin: 0 0 0.9em;
  padding: 0.45em 1em;
  border: 1px solid rgba(183, 205, 106, 0.55);
  border-radius: 100px;
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--matcha-lite);
}

/* rem, not em: this element inherits the 1rem body size, so em-based spacing
   here would resolve against 16px rather than the display-sized children. */
.promo__figure {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: clamp(0.7rem, 2vw, 1.25rem);
  margin: 0 0 clamp(0.5rem, 1.5vw, 0.9rem);
  font-family: var(--font-display);
  line-height: 0.9;
  color: #fff;
}
.promo__num {
  font-size: var(--step-5);
  font-weight: 700;
  letter-spacing: -0.02em;
}
.promo__word {
  font-size: var(--step-3);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--matcha-lite);
}

.statement--promo .statement__line { color: var(--on-dark-dim); font-size: var(--step-2); }
.promo__cta { margin-top: 1.5em; }

/* The cone rides beside the figure on a phone and closes the row on a desktop,
   so the band reads as a poster rather than a wall of type. */
.promo__cone {
  margin: 0;
  grid-column: 2;
  grid-row: 1;
  align-self: end;
}
.promo__cone img {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 20px 30px rgba(0, 0, 0, 0.38));
}
/* Three columns only once the band is wide enough to keep the button on one
   line; below that the cone takes a side column and the copy stacks beside it. */
.statement--promo .statement__inner {
  /* The copy column keeps a floor wide enough for the button; the cone track
     takes what is left, so it grows on a big phone and yields on a small one. */
  grid-template-columns: minmax(min(100%, 13.5rem), 1fr) minmax(0, clamp(78px, 31vw, 180px));
  column-gap: clamp(0.9rem, 3vw, 3rem);
  align-items: end;
}
.statement--promo .statement__quote { grid-column: 1; grid-row: 1; }
.statement--promo .statement__body {
  grid-column: 1;
  grid-row: 2;
  padding-left: 0;
  border-left: 0;
}
/* The cone runs the height of the copy and drops to the bottom of the band, so
   its cropped edge is the band edge at every width — never a cut floating
   mid-section. The offset is the section padding and no more: go deeper and the
   edge slices through the wrist instead of letting the sleeve run out of frame,
   which is where the photo already ends. The 2px is slack against subpixel
   rounding leaving a sliver of the photo's own edge above the band's. */
.promo__cone {
  grid-row: 1 / span 2;
  align-self: end;
  margin-bottom: calc((clamp(3rem, 7vw, 5.5rem) + 2px) * -1);
}
/* The copy column is narrow on a phone; trim the button's side padding so the
   label still holds one line. */
.statement--promo .promo__cta { padding-inline: 1.3em; }

/* A phone band is too tall for the cone to reach the headline from the bottom
   edge — it would have to be wider than the copy. So below 620px the cone sits
   up beside the figure instead and the copy takes the full width under it. */
@media (max-width: 619px) {
  .statement--promo .statement__inner {
    grid-template-columns: minmax(0, 1fr) clamp(96px, 30vw, 150px);
  }
  .statement--promo .statement__body { grid-column: 1 / -1; }
  .promo__cone {
    grid-row: 1;
    margin-bottom: 0;
  }
  .statement--promo .promo__cta { padding-inline: 2.1em; }
}

/* Past a phone the copy column has room again, so the button gets its normal
   proportions back. */
@media (min-width: 620px) {
  .statement--promo .promo__cta { padding-inline: 2.1em; }
}

@media (min-width: 960px) {
  .statement--promo .statement__inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) clamp(150px, 15vw, 215px);
    align-items: center;
  }
  .statement--promo .statement__body {
    grid-column: 2;
    grid-row: 1;
    padding-left: clamp(1.5rem, 4vw, 3rem);
    border-left: 1px solid rgba(238, 243, 230, 0.18);
  }
  .promo__cone { grid-column: 3; grid-row: 1; }
}

/* ---------- benefit cards ---------- */
/* Six items, so three across rather than the four of a four-item row — four
   would leave a two-card orphan row. */
.cards {
  position: relative; z-index: 1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 255px), 1fr));
  gap: clamp(0.9rem, 1.8vw, 1.35rem);
}
@media (min-width: 1000px) {
  .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.card {
  display: flex;
  flex-direction: column;
  padding: clamp(1.4rem, 2.6vw, 1.8rem);
  background: rgba(255, 255, 255, 0.88);
  border: 1px solid rgba(13, 70, 18, 0.08);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease),
              background-color 0.35s var(--ease);
}
/* Every card is light at rest; green is the hover state. Colours transition
   alongside the fill so the text does not jump ahead of the background. */
.card:hover,
.card:focus-within {
  transform: translateY(-4px);
  background: var(--forest-mid);
  border-color: transparent;
  box-shadow: var(--shadow-md);
}
.card:hover h3,
.card:focus-within h3 { color: var(--on-dark); }
.card:hover p,
.card:focus-within p { color: var(--on-dark-dim); }
.card:hover .card__icon,
.card:focus-within .card__icon {
  background: var(--paper-lite);
  color: var(--forest);
}

/* Filled disc rather than an outline ring, and it sets the card's accent. */
.card__icon {
  display: grid; place-items: center;
  width: 48px; height: 48px;
  transition: background-color 0.35s var(--ease), color 0.35s var(--ease);
  margin-bottom: clamp(1.6rem, 3.4vw, 2.4rem);
  border-radius: 50%;
  background: var(--matcha);
  color: #fff;
}
/* Source icons are drawn on a 48px grid at 1.8; at half size the white stroke
   on the green disc goes too thin, so CSS overrides the attribute. */
.card__icon svg { width: 24px; height: 24px; stroke-width: 2.4; }

.card h3 {
  transition: color 0.35s var(--ease);
  font-size: var(--step-1);
  font-family: var(--font-sans);
  font-weight: 600;
  letter-spacing: 0.01em;
  margin-bottom: 0.5em;
  text-wrap: balance;
}
.card p {
  color: var(--ink-soft);
  font-size: var(--step--1);
  line-height: 1.7;
  transition: color 0.35s var(--ease);
}

/* ---------- journey ---------- */
.journey {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
  gap: clamp(1.5rem, 3vw, 2.25rem);
  counter-reset: journey;
}
.journey__step { display: flex; flex-direction: column; }

.journey__figure {
  position: relative;
  margin: 0 0 1.4rem;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-md);
}
.journey__figure img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform 0.7s var(--ease);
}
.journey__step:hover .journey__figure img { transform: scale(1.05); }

.journey__badge {
  position: absolute; top: 0.85rem; left: 0.85rem;
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border-radius: 50%;
  background: rgba(13, 70, 18, 0.88);
  color: var(--on-dark);
  font-family: var(--font-display);
  font-size: 0.85rem;
  letter-spacing: 0.02em;
}

.journey__body h3 {
  font-size: var(--step-1);
  font-family: var(--font-sans);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 0.35em;
}
.journey__body p { color: var(--ink-soft); font-size: var(--step--1); line-height: 1.75; }

/* Caption carries the place's role in the story; display serif so it reads as a
   subheading rather than a first line of body copy. */
.journey__body .journey__caption {
  margin-bottom: 0.85em;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 500;
  line-height: 1.3;
  color: var(--olive-text);
  text-wrap: balance;
}

/* Two-up range: the odd third card spans the row and goes side-by-side rather
   than sitting alone in a half-empty row. */
@media (min-width: 620px) and (max-width: 879px) {
  .journey { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .journey__step:last-child {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: clamp(1.5rem, 3vw, 2.25rem);
    align-items: center;
  }
  .journey__step:last-child .journey__figure { margin-bottom: 0; }
}

@media (min-width: 880px) {
  .journey { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ---------- why ceremonial ---------- */
/* Full-width dark band. The heading holds the left rail and the four reasons run
   as one row of photo tiles on the right. */
.why {
  background: linear-gradient(115deg, #06280c, #10421a 48%, #06280c);
}
/* Tea-leaf macro across the whole band, blurred so it reads as depth rather than
   as its own subject. Scaled up because the blur leaves a soft fringe at the
   edges, and .section clips the overflow. */
.why__bg {
  position: absolute; inset: 0;
  background: url("assets/leaf-macro.jpg") center / cover no-repeat;
  opacity: 0.3;
  filter: blur(4px) saturate(0.85);
  transform: scale(1.06);
  pointer-events: none;
}
/* Scrim, kept out of .why__bg: that layer is faded as a whole, and the scrim has
   to stay at full strength to hold the copy off the photo's highlights. Same
   z-layer as the photo, painted after it, so it lands on top. */
.why::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(100deg, rgba(4, 30, 9, 0.76), rgba(4, 30, 9, 0.3) 46%, rgba(4, 30, 9, 0.7));
  pointer-events: none;
}

.why__inner {
  display: grid;
  gap: clamp(1.75rem, 4vw, 2.75rem);
}
.why__head { max-width: 34ch; }
/* .btn is inline-flex, so it takes its own line under the heading; the margin is
   all that is needed to set it off. */
.why__cta { margin-top: clamp(1.2rem, 2.5vw, 1.8rem); }

.why__cards {
  display: grid;
  gap: clamp(0.6rem, 1.2vw, 0.9rem);
}
.why__card {
  position: relative;
  isolation: isolate;
  /* Clips the tile's own photo to the rounded corners. */
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: clamp(1.25rem, 3vw, 2rem);
  min-height: clamp(200px, 21vw, 292px);
  padding: clamp(0.95rem, 1.7vw, 1.3rem);
  border: 1px solid rgba(238, 243, 230, 0.16);
  border-radius: var(--radius);
  background: rgba(238, 243, 230, 0.07);
  transition: border-color 0.4s var(--ease), transform 0.4s var(--ease);
}
/* One rule for all four tiles; the photo itself comes from --card-img on the
   element, so a new reason is a markup change only. */
.why__card::before {
  content: "";
  position: absolute; inset: 0;
  z-index: -1;
  background-image: var(--card-img);
  background-position: center;
  background-size: cover;
  opacity: 0.42;
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
/* Weighted to the bottom, where the copy sits. */
.why__card::after {
  content: "";
  position: absolute; inset: 0;
  z-index: -1;
  background: linear-gradient(180deg, rgba(4, 30, 9, 0.12), rgba(4, 30, 9, 0.55) 45%, rgba(4, 30, 9, 0.88));
}
@media (hover: hover) {
  .why__card:hover {
    border-color: rgba(183, 205, 106, 0.55);
    transform: translateY(-4px);
  }
  .why__card:hover::before { opacity: 0.5; transform: scale(1.06); }
}
.why__num {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1;
  color: var(--matcha-lite);
}
.why__card h3 {
  margin-bottom: 0.4em;
  font-family: var(--font-sans);
  font-size: var(--step-0);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--on-dark);
}
.why__card p {
  font-size: var(--step--1);
  line-height: 1.6;
  color: var(--on-dark-dim);
}

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

/* Two rails, and the four tiles in a single row. The heading rail is deliberately
   the smaller of the two: below this the row cannot hold four columns of readable
   measure, so it falls back to the 2x2 above. */
@media (min-width: 1060px) {
  .why__inner {
    grid-template-columns: minmax(0, 0.54fr) minmax(0, 1.46fr);
    align-items: center;
    column-gap: clamp(1.5rem, 3vw, 2.75rem);
  }
  /* The rail is the narrower track, so the display size steps down with it —
     at --step-3 "The difference?" alone breaks over two lines. */
  .why__head { max-width: none; margin-bottom: 0; }
  .why .section__title { font-size: clamp(1.45rem, 2.1vw, 1.95rem); }

  .why__cards { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* Four tracks inside the shell leave ~150px of measure per tile, so the tile
     copy steps down a notch too — at --step-0 the headings break after single
     words instead of after phrases. */
  .why__card { padding: clamp(0.85rem, 1.45vw, 1.1rem); }
  .why__num { font-size: var(--step-0); }
  .why__card h3 { font-size: clamp(0.9rem, 1.05vw, 0.98rem); }
  .why__card p { font-size: clamp(0.79rem, 0.95vw, 0.86rem); line-height: 1.55; }
}

/* ---------- serving gallery ---------- */
/* Explicit counts rather than auto-fit: five items need a deliberate wrap
   (2+2+1 → 3+2 → 5) instead of whatever the track maths lands on. */
.gallery {
  position: relative; z-index: 1;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(0.9rem, 2.2vw, 1.5rem);
}
@media (min-width: 620px) { .gallery { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .gallery { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.gallery__item { display: grid; gap: 0.9rem; }

.gallery__frame {
  display: block;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-md);
}
.gallery__frame img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  transition: transform 0.75s var(--ease);
}
.gallery__item:hover .gallery__frame img { transform: scale(1.07); }

.gallery__label {
  text-align: center;
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--forest);
}

/* ---------- how to mix ---------- */
.how {
  display: grid;
  gap: clamp(2.5rem, 6vw, 4rem);
  align-items: center;
}

.steps { display: grid; gap: clamp(0.6rem, 1.6vw, 0.9rem); counter-reset: step; }
.step {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(0.9rem, 2.2vw, 1.4rem);
  align-items: center;
  padding: clamp(0.9rem, 2.2vw, 1.15rem) clamp(1rem, 2.5vw, 1.4rem);
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(13, 70, 18, 0.09);
  border-radius: var(--radius);
  transition: transform 0.3s var(--ease), background-color 0.3s var(--ease);
}
.step:hover { transform: translateX(4px); background: rgba(255, 255, 255, 0.85); }
.step__num {
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--forest);
  color: var(--on-dark);
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
}
.step p { font-size: var(--step-0); color: var(--ink-soft); }
.step strong { color: var(--forest); font-weight: 500; }

.pack {
  position: relative;
  display: grid; place-items: center;
  /* The box tracks the bag rather than the column it sits in. Everything placed
     against it — the powder, the stamp — is then a share of the artwork instead
     of a share of the cell, so the stamp keeps the same relationship to the
     bag's edge at every width instead of drifting inboard as the column grows. */
  width: min(100%, 380px);
  justify-self: center;
  padding-bottom: 3%;
  /* own stacking context, so the powder's z-index only competes with the pack
     shot beside it and not with anything else on the section */
  isolation: isolate;
  /* Query container, like .hero__frame: it lets the stamps size off the bag
     rather than off the viewport. */
  container-type: inline-size;
  /* Shared by the circle and the origin tag below it: one number keeps them the
     same width and lets the tag's offset be "one diameter down". */
  --stamp-d: clamp(74px, 29cqw, 122px);
  --tag-w: calc(var(--stamp-d) * 0.82);
}
.pack__img {
  width: 100%;
  filter: drop-shadow(0 30px 40px rgba(13, 70, 18, 0.22));
}
.pack__powder {
  position: absolute;
  /* In front of the bag: the mound reads as powder heaped against its base
     rather than a halo behind it. */
  z-index: 1;
  bottom: 0; right: -4%;
  width: 62%;
  opacity: 0.95;
}
/* Same stamp as the hero, bigger and pushed out to the corner so it breaks the
   bag's right edge. The border, fill and type still come from .stamp--premium,
   which this rule follows in source order; only the scale and placement are
   local. Every size stays proportional to the hero's (font and peak are 10% and
   40% of the diameter) so the two stamps read as one mark at two sizes. */
.pack__stamp {
  /* Negative inset: the mark is meant to break the bag's right edge. */
  top: 4%; right: -3%;
  width: var(--stamp-d);
  font-size: clamp(0.48rem, 2.9cqw, 0.76rem);
}
.pack__stamp .stamp__peak { width: clamp(30px, 11.5cqw, 50px); }

/* The hero's origin tag, cropped out of the combined kanji artwork so the
   distressed edge is the same ink stamp rather than a CSS lookalike. Only the
   frame and letters are opaque — no plate behind them. */
.pack__origin {
  position: absolute;
  z-index: 2;
  /* Opposite corner to the circle and level with it, on the bag's plain panel
     above the label. The inset is only -2%: the bag fills the shell on a phone,
     so anything deeper than the gutter (~18px at 390px) gets clipped by the
     body's overflow-x rather than hanging over the background. */
  top: 9%;
  left: -2%;
  width: var(--tag-w);
  height: auto;
  /* Off-square, like a stamp that was actually pressed on. */
  transform: rotate(-6deg);
}

@media (min-width: 880px) {
  .how { grid-template-columns: 1.15fr 0.85fr; }
}

/* specs */
.specs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
  gap: 1px;
  margin: clamp(2.5rem, 6vw, 4rem) 0 0;
  background: rgba(13, 70, 18, 0.14);
  border: 1px solid rgba(13, 70, 18, 0.14);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.specs__item {
  padding: clamp(1.25rem, 3vw, 1.85rem);
  background: rgba(255, 255, 255, 0.55);
}
.specs dt {
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--olive-text);
  margin-bottom: 0.5em;
}
.specs dd {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
  color: var(--forest);
  line-height: 1.25;
}

/* ---------- order ---------- */
.order {
  position: relative;
  padding-block: var(--section-y);
  background: var(--forest);
  color: var(--on-dark);
  overflow: clip;
}
.order::before {
  content: "";
  position: absolute; inset: 0;
  background:
    radial-gradient(55% 90% at 12% 15%, rgba(140, 168, 60, 0.3), transparent 65%),
    radial-gradient(50% 80% at 92% 88%, rgba(117, 131, 57, 0.28), transparent 65%);
  pointer-events: none;
}

.order__inner {
  position: relative; z-index: 1;
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
}
.order__copy h2 {
  font-size: var(--step-3);
  color: var(--on-dark);
  max-width: 24ch;
}
.order__copy p {
  margin-top: 0.9em;
  color: var(--on-dark-dim);
  font-size: var(--step-1);
  max-width: 38ch;
}
.order__copy .order__kicker {
  margin: 0 0 0.7em;
  font-size: var(--step-1);
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--matcha-lite);
}
/* Repeats the early bird deal at the point of contact. */
.order__copy .order__offer {
  display: inline-block;
  margin-top: 1.5em;
  padding: 0.75em 1.4em;
  border: 1px solid rgba(183, 205, 106, 0.5);
  border-radius: 100px;
  background: rgba(140, 168, 60, 0.2);
  font-size: var(--step-1);
  color: var(--on-dark);
  max-width: none;
}
.order__copy .order__offer strong {
  font-size: 1.2em;
  font-weight: 500;
  color: var(--matcha-lite);
}

.order__actions { display: grid; }

/* ---------- signup form ---------- */
.signup {
  padding: clamp(1.5rem, 3.5vw, 2.25rem);
  background: rgba(238, 243, 230, 0.08);
  border: 1px solid rgba(238, 243, 230, 0.2);
  border-radius: var(--radius-lg);
}
.signup__title {
  font-size: var(--step-2);
  color: var(--on-dark);
}
.signup__hint {
  margin: 0.5em 0 1.5em;
  font-size: var(--step--1);
  color: var(--on-dark-dim);
}

.field { display: grid; gap: 0.4rem; margin: 0 0 1rem; }
.field label {
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--matcha-lite);
}
.field input {
  width: 100%;
  padding: 0.8em 1em;
  border: 1px solid rgba(238, 243, 230, 0.28);
  border-radius: var(--radius);
  background: rgba(13, 70, 18, 0.35);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  font-weight: 300;
  color: #fff;
  transition: border-color 0.25s var(--ease), background-color 0.25s var(--ease);
}
.field input:hover { border-color: rgba(238, 243, 230, 0.45); }
.field input:focus {
  outline: 2px solid var(--matcha-lite);
  outline-offset: 2px;
  border-color: transparent;
  background: rgba(13, 70, 18, 0.5);
}
/* :user-invalid, not :invalid — empty required fields must not look wrong on load. */
.field input:user-invalid { border-color: #e0a59d; }

.signup__submit { width: 100%; margin-top: 0.5rem; }

/* ---------- consent, collection notice, submit status ---------- */
/* Australian Privacy Act (APP 5) wants the collection notice at the point of
   collection, and the Spam Act wants consent to be an explicit act — hence a
   required checkbox rather than a pre-ticked one or implied consent. */
.consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.6rem;
  margin: 0.2rem 0 0.9rem;
  font-size: 0.78rem;
  line-height: 1.55;
}
.consent input {
  width: 17px; height: 17px;
  margin-top: 0.15em;
  accent-color: var(--olive);
  cursor: pointer;
}
.consent label { cursor: pointer; }
.consent a { text-decoration: underline; text-underline-offset: 2px; }

.collection-notice {
  margin: 0 0 1rem;
  font-size: 0.7rem;
  line-height: 1.6;
  opacity: 0.75;
}
.collection-notice a { text-decoration: underline; }

/* Visually hidden, but not display:none — bots fill what they can parse. */
.honeypot {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.form-status {
  margin: 0.7rem 0 0;
  font-size: var(--step--1);
  line-height: 1.5;
  min-height: 1.5em;
}
.form-status:empty { display: none; }
.form-status[data-state="error"] { color: #e0a59d; }

/* On the cream modal the inherited on-dark colours would wash out. */
.signup .consent, .signup .collection-notice { color: var(--on-dark-dim); }
.signup .consent a, .signup .collection-notice a { color: var(--matcha-lite); }
.signup .form-status { color: var(--matcha-lite); }
.promodal .consent, .promodal .collection-notice { color: var(--ink-soft); }
.promodal .consent a, .promodal .collection-notice a { color: var(--olive-text); }
.promodal .form-status { color: var(--olive-text); }
.promodal .form-status[data-state="error"] { color: var(--stamp-red); }

.is-sending { opacity: 0.6; pointer-events: none; }

@media (min-width: 900px) {
  .order__inner { grid-template-columns: 1fr 0.9fr; }
}

/* ---------- footer ---------- */
.site-footer {
  padding-block: clamp(1.75rem, 4vw, 2.75rem);
  background: var(--band);
  border-top: 1px solid rgba(13, 70, 18, 0.12);
}
.footer-inner {
  display: grid;
  gap: 1.25rem;
  align-items: center;
  justify-items: center;
  text-align: center;
}
.footer__home { display: block; }
.footer__logo { width: clamp(120px, 20vw, 165px); }

.footer__contact {
  display: flex; flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem 1.75rem;
}
.footer__contact a {
  display: inline-flex; align-items: center; gap: 0.55em;
  font-size: var(--step--1);
  font-weight: 500;
  color: var(--forest);
  transition: color 0.25s var(--ease);
}
.footer__contact a:hover { color: var(--olive-text); }
.footer__contact svg { width: 17px; height: 17px; flex: none; opacity: 0.7; }

.footer__legal {
  margin: 0;
  font-size: var(--step--1);
  color: var(--ink-soft);
  line-height: 1.7;
}
.footer__note { display: block; opacity: 0.75; }
.footer__legal sup { font-size: 0.6em; vertical-align: super; }

@media (min-width: 760px) {
  /* Logo and contacts share the top row; the legal line rules off below them. */
  .footer-inner {
    grid-template-columns: auto 1fr;
    grid-template-areas:
      "logo  contact"
      "legal legal";
    justify-items: start;
    text-align: left;
    gap: 1.4rem 2rem;
  }
  .footer__home { grid-area: logo; }
  .footer__contact { grid-area: contact; justify-content: flex-end; justify-self: end; }
  .footer__legal {
    grid-area: legal;
    width: 100%;
    padding-top: 1.2rem;
    border-top: 1px solid rgba(13, 70, 18, 0.14);
  }
  .footer__note { display: inline; }
}

/* ---------- scroll reveal ----------
   Scoped to .js (set by an inline script in <head>) so that with JS disabled or
   broken the content is simply visible rather than stuck at opacity 0. */
.js .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}
.js .reveal.is-visible { opacity: 1; transform: none; }

/* stagger children within a grid */
.cards .reveal:nth-child(2), .gallery .reveal:nth-child(2),
.journey .reveal:nth-child(2), .steps .reveal:nth-child(2) { transition-delay: 0.08s; }
.cards .reveal:nth-child(3), .gallery .reveal:nth-child(3),
.journey .reveal:nth-child(3), .steps .reveal:nth-child(3) { transition-delay: 0.16s; }
.cards .reveal:nth-child(4), .gallery .reveal:nth-child(4),
.steps .reveal:nth-child(4) { transition-delay: 0.24s; }
.cards .reveal:nth-child(5), .gallery .reveal:nth-child(5),
.steps .reveal:nth-child(5) { transition-delay: 0.32s; }
.cards .reveal:nth-child(6) { transition-delay: 0.4s; }

/* ---------- motion / print ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .js .reveal { opacity: 1; transform: none; }
}

@media print {
  .site-header, .nav, .hero__glow { display: none !important; }
  body { background: #fff; color: #000; }
  .section--dark, .statement, .order { background: #fff !important; color: #000 !important; }
  .sec-bg { display: none !important; }
  .section--dark h2, .section--dark h3, .statement__line, .order__copy h2 { color: #000 !important; }
  .js .reveal { opacity: 1 !important; transform: none !important; }
}
/* ---------- first-visit promo modal (DORMANT) ---------- */
/* The modal is disabled as of 2026-09-10 — markup parked in a <template> in
   index.html, behaviour commented out in script.js. Everything from here to the
   promo-fade keyframes therefore matches nothing; it is left in place, and left
   as live CSS rather than commented out, because these rules carry comments of
   their own and CSS comments do not nest — block-commenting the section would
   mean deleting them.

   Cream panel. The shared .field styles are built for the page's green bands,
   so the form inputs are re-skinned for a light ground further down. */
.promodal {
  width: min(92vw, 440px);
  max-height: min(88vh, 720px);
  padding: clamp(1.6rem, 4vw, 2.4rem);
  border: 0;
  border-radius: var(--radius-lg);
  background: var(--paper-lite);
  color: var(--ink);
  box-shadow: 0 40px 90px -30px rgba(13, 70, 18, 0.5);
  overflow: auto;
  overscroll-behavior: contain;
}
.promodal::backdrop {
  background: rgba(9, 33, 12, 0.62);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
/* Pale powder wash, light enough not to fight the copy on a cream ground. */
.promodal::before {
  content: "";
  position: absolute; inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: url("assets/bg-powder-arc.webp") 75% 40% / cover no-repeat;
  opacity: 0.3;
  pointer-events: none;
}
.promodal > * { position: relative; }

.promodal__x {
  position: absolute; top: 0.75rem; right: 0.75rem;
  z-index: 1;
  display: grid; place-items: center;
  width: 36px; height: 36px;
  border: 0; border-radius: 50%;
  background: rgba(13, 70, 18, 0.08);
  color: var(--forest);
  cursor: pointer;
  transition: background-color 0.25s var(--ease);
}
.promodal__x:hover { background: rgba(13, 70, 18, 0.16); }

.promodal__eyebrow {
  margin: 0 0 0.5em;
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--olive-text);
}
.promodal__title {
  margin: 0 0 0.4em;
  padding-right: 2.5rem;
  font-size: var(--step-3);
  color: var(--forest);
  text-transform: uppercase;
  letter-spacing: 0.01em;
}
.promodal__lede {
  margin: 0 0 1.4rem;
  color: var(--ink-soft);
  font-size: var(--step-0);
}

.promodal__opts { display: grid; gap: 0.6rem; }

/* The three reasons read as choices; "No thanks" deliberately does not compete
   with them — no fill, no border, just text. */
.promodal__opt {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem;
  width: 100%;
  padding: 0.95em 1.2em;
  border: 1px solid rgba(13, 70, 18, 0.22);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.72);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  font-weight: 400;
  color: var(--forest);
  text-align: left;
  cursor: pointer;
  transition: background-color 0.25s var(--ease), border-color 0.25s var(--ease),
              transform 0.25s var(--ease);
}
.promodal__opt svg { flex: none; opacity: 0.6; transition: transform 0.25s var(--ease); }
.promodal__opt:hover {
  background: #fff;
  border-color: var(--forest);
  transform: translateY(-1px);
}
.promodal__opt:hover svg { transform: translateX(3px); }

.promodal__skip {
  justify-self: center;
  margin-top: 0.4rem;
  padding: 0.5em 0.8em;
  border: 0;
  background: none;
  font-family: var(--font-sans);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: rgba(77, 91, 70, 0.4);
}
.promodal__skip:hover { color: var(--forest); text-decoration-color: currentColor; }

/* Re-skin of the shared field styles for the cream panel. */
.promodal .field label { color: var(--olive-text); }
.promodal .field input {
  border-color: rgba(13, 70, 18, 0.2);
  background: rgba(255, 255, 255, 0.85);
  color: var(--ink);
}
.promodal .field input:hover { border-color: rgba(13, 70, 18, 0.38); }
.promodal .field input:focus {
  outline-color: var(--olive);
  background: #fff;
}
.promodal .field input:user-invalid { border-color: #b8392c; }

.promodal__submit { width: 100%; margin-top: 0.5rem; }

/* Phones take the whole screen: at this width a centred card leaves slivers of
   dimmed page around it and the options crowd the edges. dvh, not vh, so the
   panel is not cut off by mobile browser chrome.

   Doubly dormant: the modal is disabled outright, and the commented-out block
   in script.js also gates it to a fine pointer on a window of 700px or more, so
   re-enabling alone will not reach this branch — the gate has to come off too.
   Kept because that is a one-line change and this is what the panel needs on a
   phone the moment it is made. */
@media (max-width: 600px) {
  .promodal {
    width: 100vw; max-width: 100vw;
    /* Fallback first, for browsers without dvh (iOS Safari < 15.4): fit the
       content and cap at 88vh. Not 100vh — that measures the viewport with the
       browser chrome retracted, so the last lines sit underneath it. */
    height: auto; max-height: 88vh;
    height: 100dvh; max-height: 100dvh;
    padding: 3.25rem 1.4rem 2rem;
    border-radius: 0;
  }
  /* The [open] guard matters: a bare `display: flex` here beats the UA's
     `dialog:not([open]) { display: none }`, and the closed dialog then renders
     in normal flow over the page. */
  .promodal[open] {
    display: flex; flex-direction: column;
  }
  /* Centred with auto margins rather than `justify-content: center`. Centring a
     scrollable flex container that way overflows it at BOTH ends, and the part
     above the top edge cannot be scrolled to — that is what clipped the bottom
     of the taller claim step on shorter phones. Auto margins collapse to 0 as
     soon as the content outgrows the panel, so it simply scrolls instead. */
  .promodal__step {
    flex: none;
    width: 100%;
    margin-block: auto;
  }
  /* The panel can now scroll, so the close button must not scroll away with it.
     Inside a top-layer dialog `fixed` resolves against the viewport, which at
     this width is exactly the panel. */
  .promodal__x { position: fixed; top: 0.9rem; right: 0.9rem; }
  .promodal__title { font-size: var(--step-4); padding-right: 0; }
  .promodal__opt { padding: 1.1em 1.2em; }
}

/* Embedded, with a parent that did not hand back a real viewport — an embed
   still running the plain height snippet. The iframe is document-tall, so
   every vh/dvh inside it is meaningless and dialog centring would drop the
   panel halfway down the page. Fixed pixel sizing near the top of the embed
   instead: not the full-screen sheet, but a card whose content is complete and
   reachable, which is the part that was breaking. */
.is-embed-fallback .promodal[open] {
  position: absolute;
  top: 1.5rem;
  left: 0; right: 0;
  width: min(92vw, 440px);
  margin-inline: auto;
  height: auto;
  max-height: none;
  padding: clamp(1.6rem, 4vw, 2.4rem);
  border-radius: var(--radius-lg);
}
.is-embed-fallback .promodal__x { position: absolute; top: 0.75rem; right: 0.75rem; }

@media (prefers-reduced-motion: no-preference) {
  .promodal[open] { animation: promo-in 0.35s var(--ease) both; }
  .promodal[open]::backdrop { animation: promo-fade 0.35s var(--ease) both; }
}
@keyframes promo-in {
  from { opacity: 0; transform: translateY(14px) scale(0.97); }
}
@keyframes promo-fade { from { opacity: 0; } }

