/* PlantPOP — marketing home page.

   Built from the supplied design package: `design-tokens.json` for the values,
   `IMPLEMENTATION.md` for the component and layout requirements, and the
   package's own `index.html` / `styles.css` for the structure. The page order
   is the brief's ten sections, in the brief's order.

   This file declares no tokens. It used to carry the design package's block
   verbatim at the top — a second `:root` with its own forest, its own ink, its
   own hairlines and its own type stack — so the same role resolved to
   different values depending on which surface the reader was on. That is
   reconciled: index.html links `tokens.css`, this file names roles, and the
   values behind those roles are the ones `tokens/` has always held. What was
   decided and why is in README, "Reconciling the two token sets".

   It still does not link `components.css`: the page uses none of the `.pp-*`
   shapes and draws its own sections. That is a component decision, not a token
   one — the values are now shared either way.

   The band rhythm the brief asks for is the thing to protect when editing:
   card, open space, dark band and image-led band alternate down the page, and
   making any one of them "just another card" is what flattens it.

     hero          white card
     value strip   quiet field, no card
     products      open ground, cards on it
     how it works  brand band
     care guide    white card
     gifting       blush field, image-led
     conversion    brand band
*/

/* ── Base ─────────────────────────────────────────────────────────────────── */

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* The nav links jump to sections; without this the heading lands under the
     top of the viewport rather than clear of it. */
  scroll-padding-top: 24px;
}

body {
  margin: 0;
  /* No overflow-x: hidden here, deliberately. The two card rails are real
     scroll containers (overflow-x: auto) and each carries contain: paint, so
     the cards that run past their right edge never count toward the document's
     own scrollable width, and overscroll-behavior-x: contain keeps a rail's
     drag from chaining to the page. Nothing else on the page is wider than the
     viewport, so clipping the document sideways would buy nothing and would
     hide the next thing that is — and it would not have caught the rail leak
     anyway: overflow-x: clip here left the document still reporting 566px.
     If the page ever scrolls sideways again, find the element and size it. */
  background: var(--surface-background);
  color: var(--text-primary);
  font-family: var(--pp-font-body);
  font-weight: var(--pp-weight-body);
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}

/* Display type is Nunito, which is what the rest of the system sets and what
   the wordmark is drawn in. This page used to set DM Sans at 800 for every
   heading — not as a decision but as an inheritance: the design package's own
   token named Inter, its stylesheet set DM Sans, and the stylesheet won by
   being the file the mockup was rendered from. The wordmark beside those
   headings was Nunito 900 the whole time.

   Weights follow the rule in README: 900 for the headline and for card titles,
   800 for section headings. Tracking comes off the scale rather than being
   spelled here — Nunito needs it and DM Sans does not, which is exactly why a
   family and its tracking should not be set in different files. */
h1, h2, h3 {
  font-family: var(--pp-font-display);
  font-weight: var(--pp-weight-display-soft);
  letter-spacing: var(--pp-ls-heading);
}

h1 {
  font-weight: var(--pp-weight-display);
  letter-spacing: var(--pp-ls-display-xl);
}

/* A card title, not a section heading. */
h3 { font-weight: var(--pp-weight-display); }

img, svg { max-width: 100%; }

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

/* First tab stop on the page. Off-canvas until it takes focus. */
.skip-link {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 50;
  background: var(--surface-brand);
  color: var(--brand-primary-contrast);
  padding: 11px 18px;
  border-radius: var(--radius-pill);
  font-size: 12px;
  font-weight: var(--pp-weight-body-bold);
  letter-spacing: .06em;
  text-decoration: none;
  transition: top .18s ease;
}

.skip-link:focus { top: 12px; }

/* What the cart script speaks. Present in the layout at zero size so the region
   exists before the first announcement lands in it. */
.cart-status {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
}

/* ── Announcement ───────────────────────────────────────────────────────────
   The quietest strip on the page and the loudest ground, which is the one
   inversion this design runs: it is four short facts, so it can carry the
   forest fill without competing with the hero under it. */

.announcement {
  background: var(--surface-brand);
  color: var(--text-inverse);
  min-height: 40px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 6px 14px;
  padding: 9px 16px;
  font-size: 11px;
  font-weight: var(--pp-weight-body-bold);
  letter-spacing: .1em;
  text-align: center;
}

.announcement i {
  font-style: normal;
  opacity: .5;
}

/* ── Header ─────────────────────────────────────────────────────────────────
   Logo left, links right; below 800px the links collapse behind a Menu button.
   The header is the positioning context for that panel. */

.site-header {
  position: relative;
  padding: 16px 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.logo {
  display: inline-flex;
  align-items: center;
  min-height: var(--pp-hit-min);
  text-decoration: none;
  color: var(--text-primary);
}

.logo svg { display: block; }

.nav {
  display: flex;
  align-items: center;
  gap: 30px;
}

.nav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--pp-hit-min);
  color: var(--text-primary);
  text-decoration: none;
  font-weight: var(--pp-weight-body-semi);
  font-size: 14px;
  white-space: nowrap;
}

/* The underline is the whole hover. This rule used to also swap --ink for
   --forest, which were 5.4 dE apart — a colour change nobody could see, on the
   one state that has to be unmistakable. Both are --text-primary now and the
   rule says what it always did. */
.nav a:not(.cart):hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* The one control in the nav that is always worth finding. */
.cart {
  background: var(--button-primary-bg);
  color: var(--button-primary-fg) !important;
  padding: 0 20px;
  border-radius: var(--radius-pill);
  font-weight: var(--pp-weight-body-bold);
}

.cart:hover { background: var(--button-primary-bg-hover); }

#cart-count { color: var(--text-inverse-accent); }

/* Shown below 800px. It is a real button with aria-expanded, so the panel it
   controls is a disclosure rather than a class the page toggles silently. */
.menu-toggle {
  display: none;
  align-items: center;
  gap: 8px;
  min-height: var(--pp-hit-min);
  padding: 8px 16px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 13px;
  font-weight: var(--pp-weight-body-bold);
  cursor: pointer;
}

/* ── Section shell ──────────────────────────────────────────────────────────
   The gutter is the band's margin, not its padding. It used to be padding, and
   because most bands paint their background on the section element itself, that
   put the page gutter *inside* the card: below 1180px every band ran edge to
   edge with its own radius sliced off by the screen, and on the two bands that
   kept the padding — the hero and the gift field — the image half stopped 20px
   short of the card it lives in. Same rule for the header and the footer, so
   the whole page hangs off one pair of edges. */

.section,
.site-header,
.footer {
  width: calc(100% - var(--pp-gutter) * 2);
  max-width: var(--measure-marketing);
  margin-inline: auto;
}

.section { margin-block: var(--pp-band-gap); }

/* ── Type ─────────────────────────────────────────────────────────────────
   Every display size is fluid between the phone and the desktop rather than
   switching at the 800px break: at 375px the fixed 58px headline was breaking
   "poppin'" onto a line of its own with the highlight box around it. */

.kicker {
  font-size: 10px;
  letter-spacing: var(--pp-ls-eyebrow);
  font-weight: var(--pp-weight-body-bold);
  color: var(--text-secondary);
  margin: 18px 0 8px;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  width: max-content;
  max-width: 100%;
  background: var(--surface-subtle);
  color: var(--text-primary);
  border-radius: var(--radius-pill);
  padding: 7px 13px;
  font-size: 10px;
  font-weight: var(--pp-weight-body-bold);
  letter-spacing: .08em;
}

.lead {
  font-size: clamp(15px, 1.4vw, 17px);
  line-height: 1.5;
  max-width: 44ch;
  margin: 0 0 22px;
  color: var(--text-primary);
}

/* ── Buttons ────────────────────────────────────────────────────────────────
   One pill, three fills. It is never redrawn per section — the conversion band
   takes the pink because it sits on forest, not because it is a different
   control. */

.btn,
.outline-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--pp-hit-min);
  border-radius: var(--radius-pill);
  font-family: inherit;
  font-weight: var(--pp-weight-body-bold);
  font-size: 11px;
  letter-spacing: .08em;
  padding: 13px 24px;
  /* An inline-flex row drops the whitespace between the label and the arrow
     that follows it, so "SEE ALL 12 →" was setting as "SEE ALL 12→". */
  gap: 6px;
  text-decoration: none;
  cursor: pointer;
  transition: background .18s ease, color .18s ease, border-color .18s ease;
}

.btn-primary {
  background: var(--button-primary-bg);
  color: var(--button-primary-fg);
  border: 1px solid var(--button-primary-bg);
}

.btn-primary:hover { background: var(--button-primary-bg-hover); }

.btn-pink {
  background: var(--button-accent-bg);
  color: var(--button-accent-fg);
  border: 1px solid var(--button-accent-bg);
}

.btn-pink:hover { background: var(--button-accent-bg-hover); }

.outline-btn {
  border: 1px solid var(--button-ghost-border);
  color: var(--text-primary);
  background: transparent;
  padding: 11px 18px;
}

/* The arrow after a label. It was a "→" from whatever font on the reader's
   machine carries one, which is never the label's: the glyph came in on a
   different baseline and sat two pixels above the letters beside it. Drawn, it
   is a box the flex row can centre, at the stroke weight of every other mark
   on the page. */
.arrow {
  flex: 0 0 auto;
  overflow: visible;
}

.outline-btn:hover {
  border-color: var(--button-ghost-border-strong);
  background: var(--state-hover-surface);
}

.price-pill {
  display: inline-flex;
  align-items: center;
  min-height: var(--pp-hit-min);
  background: var(--pop-secondary);
  color: var(--pop-secondary-contrast);
  border-radius: var(--radius-pill);
  padding: 0 20px;
  font-weight: var(--pp-weight-body-bold);
  font-size: 15px;
}

/* ── Hero ───────────────────────────────────────────────────────────────────
   Two columns on desktop — copy left, product visual right — stacking on
   mobile. A bordered card rather than a shadowed one: the brief asks for
   rounded cards with subtle borders, and this is the largest of them. */

.hero {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden;
  display: grid;
  grid-template-columns: 1fr 1.02fr;
  background: var(--surface);
}

.hero-copy {
  min-width: 0;
  padding: clamp(28px, 4vw, 55px) var(--pp-pad-band);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.hero h1 {
  font-size: clamp(38px, 5.4vw, 58px);
  /* .96 put the two lines closer together than the highlight box on the second
     one is tall: the comma of "care," landed on the box's top edge. */
  line-height: 1.08;
  letter-spacing: -.05em;
  margin: 0 0 20px;
  max-width: 12ch;
}

/* The one highlighted phrase on the page. Inline-block so the box wraps the
   word rather than the line — which means the box is as tall as its own line
   box, so the leading it is set with is what sizes it. At the inherited 1.05 it
   was a line-height tall and the descenders of "poppin'" ran out of the bottom;
   at .81 with the difference put back as padding the box is the same height it
   always was, sitting a few pixels lower, clear of the line above and closed
   under the descenders. Padding is in em so it holds at every headline size. */
.hero h1 em {
  font-style: normal;
  background: var(--surface-brand);
  color: var(--text-inverse);
  line-height: .88;
  padding: 0 .172em .19em;
  border-radius: var(--radius-sm);
  display: inline-block;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

/* The proof line under the CTAs. Three short facts, dot-separated — filled
   chips here would put the loudest treatment on the quietest content. */
.chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 26px;
  list-style: none;
  margin: 26px 0 0;
  padding: 0;
  font-size: 11px;
  font-weight: var(--pp-weight-body-semi);
  color: var(--text-muted);
}

/* No separator between the facts: the gap does the whole job. A dot in a
   wrapping row has to belong to the fact before it or the one after, and both
   strand it — as a ::before it opened the second line with a dot, as an ::after
   it closed the first line with one. This row wraps on every phone, and again
   from 801 to 900px where the hero is two columns and the copy is at its
   narrowest, so there was no width at which the question did not come up. At
   50% on cream the dot was barely on the page to begin with, and dropping it
   also buys back the 20px that had the row wrapping to 920. */

/* The product visual. The warm field is the package's; what stands on it is the
   shipped stake drawing, recoloured for a light ground — every line that was
   cream on the green panel is forest here. */
.hero-art {
  position: relative;
  background: var(--illustration-ground-warm);
  min-height: 300px;
  display: grid;
  place-items: center;
  padding: 24px;
}

.stake-art {
  width: 100%;
  max-width: 460px;
  height: auto;
  max-height: 100%;
}

.stake-art__stem,
.stake-art__vein,
.stake-art__wave,
.stake-art__stick {
  fill: none;
  stroke: var(--brand-primary);
  stroke-linecap: round;
}

.stake-art__stem { stroke-width: 7; }
.stake-art__vein { stroke-width: 3.5; opacity: .55; }
.stake-art__wave { stroke-width: 7; }
.stake-art__stick { stroke-width: 9; stroke: var(--botanical-soil); }

.stake-art__leaf {
  fill: var(--botanical-leaf);
  stroke: var(--brand-primary);
  stroke-width: 6;
  stroke-linejoin: round;
}

.stake-art__soil { fill: var(--botanical-soil); }

.stake-art__pot {
  fill: var(--botanical-pot);
  stroke: var(--brand-primary);
  stroke-width: 6;
  stroke-linejoin: round;
}

.stake-art__head {
  fill: var(--pop-secondary);
  stroke: var(--brand-primary);
  stroke-width: 6;
}

.stake-art__swirl {
  fill: none;
  stroke: var(--brand-primary);
  stroke-width: 2.6;
  stroke-linecap: round;
}

.stake-art__phone {
  fill: var(--surface);
  stroke: var(--brand-primary);
  stroke-width: 6;
}

.stake-art__screen { fill: var(--brand-primary); }
.stake-art__line { fill: var(--brand-primary-contrast); opacity: .85; }

/* ── Four-value strip ───────────────────────────────────────────────────────
   The open space between two cards. Sage field, one hairline between items,
   line icons rather than filled discs. */

.value-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  background: var(--surface-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 20px 12px;
}

/* The 12px above plus this padding is --pp-pad-band, so the outer text lands on
   the same line as every other band's, and the space either side of a divider
   stays twice the item padding. */
.value-strip article {
  min-width: 0;
  padding: 8px calc(var(--pp-pad-band) - 12px);
  border-right: 1px solid var(--border-subtle);
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.value-strip article:last-child { border-right: 0; }

.value-icon {
  width: 22px;
  height: 22px;
  stroke: var(--brand-primary);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  margin-bottom: 2px;
}

.value-strip strong {
  font-size: 13px;
  letter-spacing: -.01em;
}

.value-strip span {
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-secondary);
}

/* ── Section heading ────────────────────────────────────────────────────── */

.section-heading {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 16px;
  margin-bottom: 20px;
}

.section-heading h2,
.care h2 {
  margin: 0;
  font-size: clamp(20px, 2.4vw, 25px);
}

.section-heading .kicker { margin-top: 0; }

/* ── Featured products ──────────────────────────────────────────────────────
   A snapping rail on mobile, four across from 801px. The card is deliberately
   plain: tile, name, botanical name, light, price, one round action. */

.product-row {
  display: flex;
  gap: 12px;
  list-style: none;
  margin: 0;
  padding: 0 0 4px;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  /* Paint containment, for the same reason the guide rail below carries it:
     a scrolled rail can hand its scrollable width up the tree, and the page
     then reports itself wider than the viewport. The rail already clips on
     both axes — overflow-x: auto computes overflow-y to auto — so this adds
     no clipping the rail was not doing. It only stops the overflow escaping. */
  contain: paint;
}

.product-row::-webkit-scrollbar { display: none; }

.product-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 10px;
  scroll-snap-align: start;
  flex: 1 1 calc(25% - 9px);
  min-width: calc(25% - 9px);
}

/* Fixed ratio, so four tiles are the same height whatever the card holds. */
.product-art {
  position: relative;
  aspect-ratio: 5 / 4;
  border-radius: var(--radius-sm);
  display: grid;
  place-content: center;
  justify-items: center;
  text-align: center;
  gap: 6px;
  padding: 12px;
  font-weight: var(--pp-weight-body-bold);
  font-size: 11px;
  letter-spacing: .06em;
  color: var(--text-primary);
}

/* No alpha on it. At .72 over the pink tile this line was 3.5:1 — the tile
   grounds run from blush to butter, and forest at full strength is the only
   value that clears AA on all four. Size and weight hold the hierarchy. */
.product-art small {
  font-size: 10px;
  font-weight: var(--pp-weight-body-bold);
  letter-spacing: .06em;
  color: var(--text-primary);
}

.tile-stake {
  width: 84px;
  height: 84px;
  overflow: visible;
}

.tile-stake__head {
  fill: var(--surface);
  stroke: var(--brand-primary);
  stroke-width: 5;
}

.tile-stake__stick {
  fill: none;
  stroke: var(--brand-primary);
  stroke-width: 6;
  stroke-linecap: round;
}

.tile-stake__swirl {
  fill: none;
  stroke: var(--brand-primary);
  stroke-width: 2.4;
  stroke-linecap: round;
}

/* The rail's four grounds, in family order. Named by position, because that is
   all a tile means by being the third one. */
.tile-1 { background: var(--tile-ground-1); }
.tile-2 { background: var(--tile-ground-2); }
.tile-3 { background: var(--tile-ground-3); }
.tile-4 { background: var(--tile-ground-4); }

.product-card h3 {
  font-size: 14px;
  margin: 12px 0 2px;
}

.product-card p {
  margin: 0 0 7px;
  color: var(--text-muted);
  font-size: 11px;
  font-style: italic;
}

.product-card .light {
  margin: 0;
  font-size: 10.5px;
  font-weight: var(--pp-weight-body-semi);
  color: var(--text-muted);
}

/* margin-top:auto is what holds the price row on one line across four cards of
   unequal copy. Without it the row floats up under the shortest name. */
.product-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin-top: auto;
  padding-top: 12px;
}

.product-bottom b { font-size: 14px; }

.add {
  flex: 0 0 auto;
  display: grid;
  place-content: center;
  width: var(--pp-hit-min);
  height: var(--pp-hit-min);
  border: 0;
  border-radius: 50%;
  background: var(--button-primary-bg);
  color: var(--button-primary-fg);
  cursor: pointer;
  transition: background .18s ease;
}

.add:hover { background: var(--button-primary-bg-hover); }

/* The confirmation: the bag swaps for a tick for a moment. Both marks live in
   the button from the start, so nothing is fetched or measured mid-press. */
.add__tick { opacity: 0; }

.add.is-added .add__bag { opacity: 0; }
.add.is-added .add__tick { opacity: 1; }

/* ── How it works ───────────────────────────────────────────────────────────
   The forest band in the middle of the page. Three cards, one fill across all
   three — three different fills here would read as a scale. */

.how {
  background: var(--surface-brand);
  color: var(--text-inverse);
  border-radius: var(--radius-lg);
  padding: var(--pp-pad-band);
}

.how .kicker {
  color: var(--text-inverse-accent);
  margin-top: 0;
}

.how h2 {
  margin: 0 0 20px;
  font-size: clamp(21px, 2.6vw, 26px);
}

.steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.steps li {
  background: var(--surface-brand-elevated);
  border: 1px solid var(--border-on-brand);
  border-radius: var(--radius-md);
  padding: 20px;
}

.step-num {
  display: grid;
  place-content: center;
  width: 28px;
  height: 28px;
  background: var(--pop-secondary);
  color: var(--pop-secondary-contrast);
  border-radius: 50%;
  font-size: 13px;
}

.steps h3 {
  margin: 12px 0 4px;
  font-size: 16px;
}

.steps p {
  font-size: 12px;
  line-height: 1.55;
  margin: 0;
  color: var(--text-inverse-muted);
}

/* ── Care guide ─────────────────────────────────────────────────────────────
   Editorial column left, compact guide cards right. The cards rail on mobile
   the way the product row does. */

.care {
  background: var(--surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  /* The guide rail is a grid item that scrolls sideways, and a scrolled grid
     item reports its scrollable width up to the grid container: without this
     the document itself gained 210px of horizontal scroll on a phone while the
     rail was clipping correctly. The card is a rounded object; clipping to it
     is what the hero and the gift field already do. This bounds the rail's
     paint, but not the width it reports once it has been dragged — that takes
     contain: paint on .care-row itself. */
  overflow: hidden;
  padding: var(--pp-pad-band);
  display: grid;
  grid-template-columns: 190px 1fr;
  gap: 34px;
}

.care-intro { min-width: 0; }
.care-intro .kicker { margin-top: 0; }

.care-intro > p:not(.kicker) {
  font-size: 13px;
  line-height: 1.5;
  margin: 16px 0 20px;
  color: var(--text-muted);
}

.care-row {
  display: flex;
  gap: 12px;
  list-style: none;
  margin: 0;
  padding: 0 0 4px;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  /* The rail is a grid item, and overflow: hidden on .care above is not enough
     on its own: once this rail has actually been dragged, the scrolled-out
     width leaks past that clip and lands on the document. On a 390px phone the
     page then measured 566px wide — nothing painted out there, but iOS Safari
     sizes its minimum scale from that number, so the whole page could be
     pinched out and panned into a band of empty cream. Paint containment ends
     the propagation at the rail. It clips nothing new: overflow-x: auto already
     computes overflow-y to auto, so this box was clipping on both axes. */
  contain: paint;
}

.care-row::-webkit-scrollbar { display: none; }

.care-row li {
  flex: 1 1 220px;
  min-width: 220px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 15px 15px 4px;
  display: grid;
  grid-template-columns: 60px 1fr;
  column-gap: 12px;
  align-content: start;
  scroll-snap-align: start;
}

.mini-stake {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  display: grid;
  place-content: center;
  grid-row: 1 / 3;
}

.mini-stake svg { width: 42px; height: 42px; }

.care-row h3 {
  margin: 4px 0 0;
  font-size: 13px;
}

.care-row p {
  margin: 0 0 12px;
  font-size: 10.5px;
  font-style: italic;
  color: var(--text-muted);
}

.care-row b,
.care-row span:not(.visually-hidden) {
  grid-column: 2;
  font-size: 10.5px;
}

.care-row b { color: var(--text-primary); }

.care-row span:not(.visually-hidden) {
  margin-bottom: 6px;
  color: var(--text-muted);
}

.care-row a {
  grid-column: 1 / -1;
  display: inline-flex;
  align-items: center;
  min-height: var(--pp-hit-min);
  color: var(--text-primary);
  text-decoration: none;
  font-size: 11px;
  font-weight: var(--pp-weight-body-bold);
  letter-spacing: .08em;
  gap: 6px;
  margin-top: 6px;
}

.care-row a:hover { color: var(--text-primary); text-decoration: underline; }

/* ── Gifting ────────────────────────────────────────────────────────────────
   Blush field, copy left, the box right. The gift box is drawn, not
   photographed: no product photography ships with this repository, and a grey
   rectangle saying "photo here" is worse than a drawing that says the thing. */

.gift {
  background: var(--pop-highlight);
  border-radius: var(--radius-lg);
  overflow: hidden;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  min-height: 270px;
}

.gift-copy {
  min-width: 0;
  padding: var(--pp-pad-band);
}

.gift-copy .kicker { margin-top: 0; }

.gift h2 {
  font-size: clamp(22px, 2.8vw, 28px);
  line-height: 1.08;
  max-width: 16ch;
  margin: 0 0 14px;
}

.gift-copy > p:not(.kicker) {
  max-width: 42ch;
  font-size: 13.5px;
  line-height: 1.5;
  margin: 0 0 22px;
  color: var(--text-primary);
}

.gift-art {
  align-self: stretch;
  background: linear-gradient(135deg, var(--illustration-ground-blush),
                                            var(--illustration-ground-blush-deep));
  display: grid;
  place-items: center;
  padding: 24px;
}

/* The frame is the drawing's own bounds plus an even margin, so the box sits
   in the middle of the field rather than 25px below it: the viewBox it was
   drawn in carried 37 units of headroom over the tallest stake and 12 under
   the box, and the panel centres the frame, not the ink. The cap is the height
   the drawing already stood at, so the band is the height it always was. */
.gift-box {
  width: 100%;
  max-width: 260px;
  height: auto;
  max-height: 100%;
}

.gift-box__body {
  fill: var(--pp-gold-pale);
  stroke: var(--brand-primary);
  stroke-width: 6;
  stroke-linejoin: round;
}

.gift-box__lid {
  fill: var(--pp-gold-ground);
  stroke: var(--brand-primary);
  stroke-width: 6;
}

.gift-box__ribbon {
  fill: none;
  stroke: var(--pop-secondary);
  stroke-width: 12;
}

.gift-box__stick {
  fill: none;
  stroke: var(--botanical-soil);
  stroke-width: 8;
  stroke-linecap: round;
}

.gift-box__head {
  stroke: var(--brand-primary);
  stroke-width: 6;
}

/* Three stakes in a box, drawn from the system's own stake set rather than
   from three picked hues — the same three heads a care page puts in the soil. */
.gift-box__head--1 { fill: var(--stake-light-medium); }
.gift-box__head--2 { fill: var(--stake-light-low); }
.gift-box__head--3 { fill: var(--stake-light-bright); }

/* ── Trust / conversion ─────────────────────────────────────────────────────
   The second forest band: the ask on the left, one stranger's sentence on the
   right, a rule between them. */

.conversion {
  background: var(--surface-brand);
  color: var(--text-inverse);
  border-radius: var(--radius-lg);
  padding: var(--pp-pad-band);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 34px;
  align-items: center;
}

.conversion-copy { min-width: 0; }

.conversion h2 {
  font-size: clamp(23px, 2.9vw, 28px);
  margin: 0 0 8px;
}

.conversion p {
  font-size: 13.5px;
  margin: 0 0 20px;
  color: var(--text-inverse-muted);
}

.testimonial {
  min-width: 0;
  border-left: 1px solid var(--border-on-brand);
  padding-left: var(--pp-pad-band);
  margin: 0;
}

/* Pink, not gold: on this ground pink is one of the two type colours the band
   already carries, and a second accent hue here would be a third. */
.stars {
  width: 108px;
  height: 20px;
  fill: var(--text-inverse-accent);
}

.testimonial blockquote {
  font-size: clamp(15px, 1.5vw, 16.5px);
  line-height: 1.45;
  margin: 10px 0;
  color: var(--text-inverse);
}

.testimonial figcaption {
  font-size: 11.5px;
  color: var(--text-inverse-muted);
}

/* ── Footer ─────────────────────────────────────────────────────────────── */

.footer {
  padding: 38px 0 50px;
  display: grid;
  grid-template-columns: 2fr repeat(3, 1fr);
  gap: 30px;
}

.footer-brand p {
  font-size: 11.5px;
  line-height: 1.7;
  color: var(--text-muted);
  margin: 14px 0 0;
}

.footer-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.footer-group b {
  font-size: 10px;
  letter-spacing: .12em;
  margin-bottom: 6px;
}

.footer-group a {
  display: inline-flex;
  align-items: center;
  min-height: var(--pp-hit-min);
  font-size: 12px;
  color: var(--text-primary);
  text-decoration: none;
}

.footer-group a:hover { color: var(--text-primary); text-decoration: underline; }

.footer small {
  grid-column: 1 / -1;
  color: var(--text-muted);
  font-size: 10px;
  border-top: 1px solid var(--border-subtle);
  padding-top: 18px;
}

/* ── Focus ──────────────────────────────────────────────────────────────────
   One ring everywhere, flipped to cream on the two forest bands where an ink
   ring would be invisible. */

a:focus-visible,
button:focus-visible {
  outline: 3px solid var(--state-focus-ring);
  outline-offset: 3px;
  border-radius: 4px;
}

.btn:focus-visible,
.outline-btn:focus-visible,
.cart:focus-visible,
.add:focus-visible,
.menu-toggle:focus-visible { border-radius: var(--radius-pill); }

.add:focus-visible { border-radius: 50%; }

.announcement a:focus-visible,
.how a:focus-visible,
.conversion a:focus-visible,
.conversion button:focus-visible {
  outline-color: var(--state-focus-ring-on-brand);
}

/* ── Scroll reveal ──────────────────────────────────────────────────────────
   The care pages' reveal, running off assets/js/reveal.js. The hidden state is
   scoped to .js-reveal, which only that script sets: with JavaScript off or
   blocked the class never lands and every section renders normally. The hero
   carries no data-reveal, so the first screen never waits on a script. */

[data-reveal] {
  transition: opacity var(--motion-reveal), transform var(--motion-reveal);
}

.js-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(var(--motion-reveal-shift));
}

.js-reveal [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

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

  .js-reveal [data-reveal] {
    opacity: 1;
    transform: none;
  }

  * {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
}

/* ── Tablet ─────────────────────────────────────────────────────────────────
   801–1040px: the gutters come in and the product cards compress rather than
   the row starting to scroll. */

@media (min-width: 801px) {
  /* The package sets 510px on the hero. It is a floor, not a height: the copy
     column sets the real one whenever it needs more. */
  .hero { min-height: 470px; }
}

@media (max-width: 1000px) and (min-width: 801px) {
  /* The shell's two roles narrow with the viewport. They step down the spacing
     ladder rather than to numbers of their own — these were 18px and 14px,
     neither of which is a rung. */
  :root { --pp-gutter: var(--space-4); }

  .hero { grid-template-columns: 1fr 1fr; }
  .care { grid-template-columns: 172px 1fr; gap: 22px; }
  .conversion { gap: 26px; }
  .testimonial { padding-left: 26px; }
}

/* ── Mobile ─────────────────────────────────────────────────────────────────
   Single column everywhere, the nav behind a Menu button, and the two card rows
   become rails. Cards sit at 72% of the viewport up to 260px, so a phone shows
   one and a bit — enough of the next card to say the row scrolls — and a 768px
   tablet shows three without stretching them. */

@media (max-width: 800px) {
  :root {
    --pp-gutter: var(--space-3);
    --pp-band-gap: var(--space-3);
  }

  .announcement {
    font-size: 9.5px;
    letter-spacing: .08em;
    gap: 4px 10px;
    padding: 8px 12px;
  }

  .site-header { padding: 12px 0; }

  .menu-toggle { display: inline-flex; }

  /* The panel. Absolute rather than in flow, so opening it does not push the
     hero down the page. */
  .nav {
    display: none;
    position: absolute;
    top: calc(100% - 4px);
    left: 0;
    right: 0;
    z-index: 20;
    background: var(--surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 10px;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    box-shadow: var(--shadow-md);
  }

  .nav.is-open { display: flex; }

  .nav a {
    padding: 0 14px;
    border-radius: 12px;
  }

  /* In the panel the row itself answers, so it does not also need the rule. */
  .nav a:not(.cart):hover {
    background: var(--state-hover-surface);
    text-decoration: none;
  }

  .cart {
    justify-content: center;
    margin-top: 6px;
  }

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

  /* Copy first, art second — the headline is what the first screen is for.
     The ratio is capped: at 768px a 4:3 art block is 576px tall, which puts the
     whole of the first screen under one drawing. */
  /* width:100% is load-bearing. A stretched grid item with an aspect-ratio
     resolves its width from its clamped height, so once max-height caught the
     ratio the panel narrowed with it: at 768px the art field was 480px of a
     740px card, left-aligned, with a quarter of the hero left blank. Stating
     the width keeps the panel full-bleed and lets the ratio give way. */
  .hero-art {
    min-height: 0;
    width: 100%;
    aspect-ratio: 4 / 3;
    max-height: 360px;
    padding: 18px;
  }

  .value-strip {
    grid-template-columns: 1fr 1fr;
    padding: 10px 12px;
  }

  .value-strip article {
    padding: 14px 12px;
    border-right: 1px solid var(--border-subtle);
    border-bottom: 1px solid var(--border-subtle);
  }

  /* The two on the right lose the divider, the two on the bottom lose theirs. */
  .value-strip article:nth-child(2n) { border-right: 0; }
  .value-strip article:nth-last-child(-n + 2) { border-bottom: 0; }

  .section-heading {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }

  /* The rail bleeds to the page edge so the card that is half in view is cut by
     the screen, not by a gutter — and the padding puts the first card back on
     the gutter line. */
  .product-row {
    margin: 0 calc(var(--pp-gutter) * -1);
    padding: 0 var(--pp-gutter) 4px;
    /* The snapport has to match that padding. Without it the first card's snap
       position sits one gutter inside the rail, the rail comes to rest at
       scrollLeft: 14 with nothing having scrolled it, and the page reports a
       document wider than the viewport. */
    scroll-padding-inline: var(--pp-gutter);
  }

  .product-card {
    flex: 0 0 clamp(200px, 72%, 260px);
    min-width: 0;
  }

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

  .care {
    grid-template-columns: 1fr;
    gap: 20px;
  }

  .care-row li {
    flex: 0 0 clamp(230px, 78%, 270px);
    min-width: 0;
  }

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

  /* 16:10 left the box 70px taller than the opening it had to fit into. */
  .gift-art {
    width: 100%;
    aspect-ratio: 4 / 3;
    max-height: 300px;
    padding: 16px;
  }

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

  .testimonial {
    border-left: 0;
    border-top: 1px solid var(--border-on-brand);
    padding: 22px 0 0;
  }

  .footer {
    grid-template-columns: 1fr 1fr;
    gap: 26px;
    padding: 30px 0 44px;
  }

  .footer-brand { grid-column: 1 / -1; }
}

/* ── Wide phone to tablet ───────────────────────────────────────────────────
   620–800px: still the mobile branch — one-column sections, rails, the menu
   behind its button — but wide enough that the four-up strip, the three steps
   and the four-column footer read better than their stacked forms. */

@media (min-width: 620px) and (max-width: 800px) {
  .value-strip { grid-template-columns: repeat(4, 1fr); }

  .value-strip article {
    padding: 8px calc(var(--pp-pad-band) - 12px);
    border-bottom: 0;
    border-right: 1px solid var(--border-subtle);
  }

  .value-strip article:last-child { border-right: 0; }

  .steps { grid-template-columns: repeat(3, 1fr); }

  .footer { grid-template-columns: 1.6fr repeat(3, 1fr); }
  .footer-brand { grid-column: auto; }
}

/* ── Narrow phone ───────────────────────────────────────────────────────────
   Under 620px the four facts in the announcement no longer hold one line, and
   the wrapped flex row leaves the separator after the last fact on line one
   hanging at the end of it. Two even columns instead: the facts pair up 2×2,
   the break is where the design puts it rather than where the text runs out,
   and the separators — which only ever stood in for a column edge — come off.
   The strip fits one line again from about 550px, so 620 is the same rung the
   block above uses with room to spare for a fallback font. */

@media (max-width: 619px) {
  .announcement {
    display: grid;
    grid-template-columns: auto auto;
    justify-content: center;
    justify-items: center;
    column-gap: clamp(16px, 5vw, 34px);
    row-gap: 4px;
  }

  .announcement i { display: none; }
}

/* The narrowest phones: 375px still has to hold the value strip two across and
   the price row on one line. */
@media (max-width: 390px) {
  .value-strip article { padding: 12px 8px; }
  .value-strip strong { font-size: 12.5px; }
  .actions { gap: 10px; }
}
