/* Template #3 — bakehouse.
   Spec: design/marigold/*.dc.html. Research: design/marigold/RESEARCH.md.

   Structurally distinct from templates 1 and 2 on purpose:
     - a CENTRED masthead with the links split either side, over the hero photo,
       with no promo strip and no bounding rule
     - the hero photograph as the page GROUND, held by two scrims
     - a serif display face against a monospace utility face
     - a day bar and a rack whose items carry a live sell-out state
     - a persistent call rail, which is the one filled control on the page

   The class names ending in a block that the BUILDER emits (.rk, .day__*,
   .item, .card, .util, .quote, .stat) are its contract, not this template's.
   They are kept together at the bottom so it is obvious which half moves if the
   builder's markup changes. */

/* ---------------------------------------------------------------- tokens --- */

:root {
  /* Colour comes from content.json via {{CSS_VARS}}. Everything below is
     either a layout constant this template owns, or a state colour derived
     from the palette so any business gets a sane one. */

  /* The rail is a fixed overlay, so it is a layout constant, not content.
     72px is the spec's; --gutter and --maxw are the spec's 56 and 1248, which
     put the content edge at 128px from the left at 1440 — exactly where the
     artboard puts it. Do NOT round --maxw to 1200: every column lands 48px
     narrow and the three-up grids stop matching the spec. */
  --rail: 72px;
  --gutter: 56px;
  --maxw: 1248px;

  /* Sold out. A brand decision with a derived default, so a business that
     never names one still gets a tint that belongs to its own palette. */
  --gone: color-mix(in srgb, var(--muted) 60%, var(--bg));
  /* Body ink: not the full ink, which is too hard for a paragraph against bone.
     78% is the mix that lands on the spec value for this palette. */
  --ink-soft: color-mix(in srgb, var(--ink) 78%, var(--bg));

  /* The hero scrim. Near-black warmed toward the ink so it does not read as a
     grey wash over a warm photograph. */
  --scrim: 20, 17, 13;
  --on-scrim: #F8F3E8;
  --on-scrim-dim: #C0B7A4;
  --on-scrim-body: #D9D2C4;
  /* The open/closed dot has to survive on BOTH grounds. The accent is a deep
     olive that disappears on the scrim, so the hero uses a lifted version. */
  --live: var(--accent);
  --live-on-scrim: color-mix(in srgb, var(--accent) 55%, #EFE9DC);

  /* Serif at body scale wants a hair of negative tracking; the big display
     sizes take --display-track from content. A typographic ratio, not a brand
     decision, so it lives here. */
  --track-text: -0.005em;
  --on-scrim-nav: #F8F3E8;

  --dur: 420ms;
  --ease: cubic-bezier(0.16, 0.9, 0.3, 1);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  /* The rail sits in this padding. Below 1100 there is no rail and no padding,
     and the fixed call bar takes over — see the media queries at the end. */
  padding-left: var(--rail);
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }

a { color: var(--brand-dark); text-decoration: none; }
a:hover { color: var(--ink); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.sr-only:focus {
  position: fixed; top: 12px; left: 12px; width: auto; height: auto;
  clip: auto; padding: 12px 18px; background: var(--ink); color: var(--bg);
  z-index: 60; border-radius: 2px;
}

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

/* ------------------------------------------------------------- container --- */

/* The container standard. A rail-aware .wrap: the content edge sits one gutter
   inside the rail rather than being centred in the viewport, because the rail
   is part of the page's left margin, not a floating widget.

   Never 100vw anywhere — it includes the scrollbar and pushes a horizontal one
   on every desktop with a classic scrollbar. Full-width bands are the SECTION
   at 100%, with a .wrap inside. */
.wrap {
  width: min(var(--maxw), 100% - var(--gutter) * 2);
  /* CENTRED, not left-anchored. Anchoring it to the left gutter matches the
     1440 artboard exactly and then falls apart on every wider desktop: at 1920
     the content stopped at 1376 and left 540px of dead bone down the right.
     The artboard is one width; a real page is every width. */
  margin-inline: auto;
}

/* ------------------------------------------------------------ typography --- */

.dsp {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-track);
  text-transform: var(--display-transform);
}

/* Every utility string: hours, prices, counts, states, nav, labels, the phone
   number. This is the template's voice as much as the serif is. */
.mono { font-family: var(--font-mono); }

.h1 { font-size: clamp(52px, 10.4vw, 150px); line-height: 0.87; letter-spacing: -0.035em; margin: 0; }
.h2 { font-size: clamp(38px, 4.8vw, 68px); line-height: 0.98; letter-spacing: -0.015em; margin: 0; font-family: var(--font-display); font-weight: var(--display-weight); }
.h3 { font-size: clamp(26px, 2.4vw, 34px); line-height: 1.08; margin: 0; font-family: var(--font-display); font-weight: var(--display-weight); }

.eyebrow {
  font-family: var(--font-mono);
  font-size: 11px; font-weight: 500; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--muted); margin: 0;
}

.lede { font-size: 16px; line-height: 1.62; color: var(--ink-soft); margin: 0; }
.p    { font-size: 16px; line-height: 1.62; color: var(--ink-soft); margin: 0; }

.hl { color: var(--brand); font-style: italic; }

.rule { height: 1px; background: var(--line); border: 0; margin: 0; }

/* --------------------------------------------------------------- masthead --- */

/* Not a nav bar. Links left, mark centred, links right, no rule under it.
   On the home page it sits inside the hero and inverts; on every other page
   it sits on the page ground. One markup, two grounds. */
.mast {
  display: flex; align-items: center; gap: 40px;
  padding-top: 42px;
  position: relative; z-index: 3;
}
.mast__links {
  display: flex; gap: 32px; flex: 1 1 0;
  font-family: var(--font-mono); font-size: 13px; letter-spacing: 0.04em;
  margin: 0; padding: 0; list-style: none;
}
.mast__links--end { justify-content: flex-end; }
/* The link is the 44px target; the SPAN inside it carries the rule. Growing
   the anchor itself would drag the underline 11px off the baseline, and
   putting the target on the span would leave a 21px tap area. */
.mast__links a { color: inherit; display: inline-flex; align-items: center; min-height: 44px; }
.mast__links a > span { border-bottom: 1px solid transparent; padding-bottom: 0; }
.mast__links a:hover > span { border-bottom-color: currentColor; }
.mast__links a[aria-current="page"] > span { border-bottom-color: var(--brand); padding-bottom: 3px; }

.mast__mark {
  display: flex; flex-direction: column; align-items: center; gap: 11px;
  flex-shrink: 0; color: inherit;
}
.mast__lockup { display: flex; align-items: center; gap: 13px; }
.mast__lockup .mark__text,
.mast__lockup .mark__stack {
  font-family: var(--font-display); font-weight: var(--display-weight);
  font-size: 36px; line-height: 1; letter-spacing: -0.005em;
}
.mast__lockup img { max-height: 40px; width: auto; }
.mast__line {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.26em;
  text-transform: uppercase; color: var(--muted); margin: 0;
}

/* The bloom. Line weight, never a filled disc — the whole point of the mark is
   that it shares no silhouette with template 1's circular seal. */
.bloom { display: block; flex-shrink: 0; }
.bloom__petals { fill: none; stroke: var(--brand); stroke-width: 1.25; }
.bloom__eye { fill: var(--brand); }

/* Opens once, on load. Not on scroll, and not again. */
.js .bloom--mark { animation: bloomIn 900ms var(--ease) both; }
@keyframes bloomIn {
  from { transform: scale(0.72) rotate(-24deg); opacity: 0; }
  to   { transform: scale(1) rotate(0deg); opacity: 1; }
}

.mast__menu { display: none; }

/* ------------------------------------------------------------------ rail --- */

/* The one filled control on the site, and it never scrolls away. The audit
   finding this template answers is NO_CLICK_CALL. */
.rail {
  position: fixed; left: 0; top: 0; bottom: 0; width: var(--rail);
  display: flex; flex-direction: column; align-items: center;
  justify-content: flex-start; gap: 22px; padding-top: 210px;
  border-right: 1px solid var(--line);
  background: var(--bg);
  z-index: 40;
}
.rail__call {
  width: 44px; height: 44px; border-radius: 999px; background: var(--brand);
  color: var(--on-brand);
  display: flex; align-items: center; justify-content: center;
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.rail__call:hover { background: var(--brand-dark); color: var(--on-brand); transform: scale(1.06); }
.rail__call svg { width: 20px; height: 20px; }
.rail__label,
.rail__num {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.22em;
  writing-mode: vertical-rl; text-orientation: mixed; margin: 0;
  color: var(--ink-soft);
}
.rail__num { letter-spacing: 0.14em; color: var(--muted); }
.rail__num:hover { color: var(--ink); }
.rail__sep { width: 1px; height: 64px; background: var(--line); }

/* Over the hero the rail inverts, so it reads on the scrim rather than
   punching a bone-coloured strip through the photograph. */
.rail--over {
  background: transparent; border-right-color: rgba(248, 243, 232, 0.22);
}
.rail--over .rail__label { color: var(--on-scrim); }
.rail--over .rail__num { color: var(--on-scrim-dim); }
.rail--over .rail__sep { background: rgba(248, 243, 232, 0.28); }

/* The phone bar. Below 1100 the rail is gone and this is the same promise. */
.callbar { display: none; }

/* ------------------------------------------------------------------ hero --- */

/* The hero escapes the body's rail padding so the photograph runs to the true
   left edge and the rail sits OVER it, which is what makes the rail invert
   rather than punch a bone-coloured strip through the picture.

   Computed against 100%, never 100vw: 100vw includes the scrollbar, so on any
   desktop with a classic one this would be ~15px too wide and push a horizontal
   scrollbar on every page. */
.hero {
  position: relative; overflow: hidden;
  margin-left: calc(var(--rail) * -1);
  width: calc(100% + var(--rail));
  min-height: 880px; display: flex; flex-direction: column;
  background: rgb(var(--scrim));
  color: var(--on-scrim);
}
/* Its own content has to step back past the rail again, or the masthead and the
   headline sit half a rail to the left of every other section on the page. This
   is padding rather than a margin so .wrap's auto margins still do the centring
   and the hero lines up with the bands below it at every width. */
.hero { padding-left: var(--rail); }
.hero__img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: 0;
}
/* Two scrims, and they are load-bearing rather than decorative: on a real lead
   we do not choose the photograph, so contrast is checked against the SCRIM
   ALONE — as if the image under it were pure white. */
.hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(to bottom, rgba(var(--scrim), 0.60) 0, rgba(var(--scrim), 0) 250px),
    linear-gradient(100deg,
      rgba(var(--scrim), 0.90) 0%,
      rgba(var(--scrim), 0.76) 34%,
      rgba(var(--scrim), 0.36) 68%,
      rgba(var(--scrim), 0.14) 100%);
}
.hero > .wrap,
.hero > .mast { position: relative; z-index: 2; }

.hero .mast__links a { color: var(--on-scrim-nav); }
.hero .mast__links a,
.hero .mast__mark { color: var(--on-scrim); }
.hero .mast__line { color: var(--on-scrim-dim); }

.hero__copy { padding-top: 92px; }
.hero__eyebrow { color: var(--on-scrim-dim); }
.hero__title {
  margin-top: 30px; color: var(--on-scrim);
  /* Instrument Serif's hairlines are thin enough to disappear into a highlight
     even through the scrim, so the shadow is part of the legibility budget. */
  text-shadow: 0 2px 44px rgba(var(--scrim), 0.5);
}

.hero__foot {
  margin-top: auto; padding-top: 56px; padding-bottom: 48px;
  display: grid; grid-template-columns: 450px minmax(0, 1fr) 290px; gap: 48px;
  align-items: end;
}
.hero__tagline { color: var(--on-scrim-body); font-size: 16px; line-height: 1.6; margin: 0; }
.hero__links { display: flex; gap: 26px; align-items: center; }
.hero__meta {
  font-family: var(--font-mono); font-size: 12.5px; line-height: 1.95;
  color: var(--on-scrim-dim); text-align: right; margin: 0;
}
.hero__meta .hero__status { color: #EDE7DA; display: flex; align-items: center; gap: 9px; justify-content: flex-end; }
.hero__meta .dot { background: var(--live-on-scrim); }

/* ------------------------------------------------------------- text links --- */

/* Every link that is not the rail is a text link with a rule under it. Hover
   thickens the rule; the text colour does not move, so nothing reflows. */
.tlink {
  font-family: var(--font-mono); font-size: 14px; color: inherit;
  border-bottom: 1px solid currentColor; padding-bottom: 5px;
  display: inline-block;
  transition: border-color 140ms var(--ease);
}
.tlink:hover { color: inherit; border-bottom-color: var(--brand); border-bottom-width: 2px; padding-bottom: 4px; }
.tlink--quiet { color: var(--muted); border-bottom-color: var(--line); }
.hero .tlink--quiet { color: var(--on-scrim-dim); border-bottom-color: rgba(248, 243, 232, 0.32); }
.tlink--sm { font-size: 13px; padding-bottom: 4px; }

/* Text links are this site's entire navigation vocabulary, so each one has to
   be a real 44px target. The box grows UPWARD from the rule - align-items:
   flex-end keeps the underline on the text baseline - so nothing moves. */
.tlink { display: inline-flex; align-items: flex-end; min-height: 44px; }

.dot { width: 7px; height: 7px; border-radius: 999px; background: var(--live); display: inline-block; flex-shrink: 0; }

/* --------------------------------------------------------------- day bar --- */

.day {
  background: var(--band-up);
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: 40px 0 44px;
}
.day__h { margin-bottom: 26px; }
.day__track { position: relative; }
.day__line { position: absolute; left: 0; right: 0; top: 15px; height: 1px; background: var(--line); }
.day__done { position: absolute; left: 0; top: 15px; height: 1px; width: 0; background: var(--brand); transition: width 900ms var(--ease); }
.day__now {
  position: absolute; top: 9px; left: 0; width: 13px; height: 13px; margin-left: -6px;
  border-radius: 999px; background: var(--brand); border: 3px solid var(--band-up);
  opacity: 0; transition: left 900ms var(--ease), opacity 300ms linear;
}
.day__now.is-on { opacity: 1; }
.day__stops {
  position: relative; display: grid; gap: 24px;
  grid-template-columns: repeat(var(--stops, 5), minmax(0, 1fr));
  list-style: none; margin: 0; padding: 0;
}
.day__stop { display: flex; flex-direction: column; gap: 11px; }
.day__tick { width: 1px; height: 15px; background: color-mix(in srgb, var(--line) 70%, var(--ink)); }
.day__t {
  font-family: var(--font-mono); font-size: 19px; letter-spacing: -0.01em;
  margin: 0; color: var(--ink); width: max-content;
}
.day__stop.is-past .day__t { color: var(--brand); }
.day__what { font-size: 13.5px; line-height: 1.45; color: var(--muted); margin: 0; max-width: 190px; }

/* ------------------------------------------------------------------ rack --- */

.rack { padding: 104px 0; }
.rack__head { display: flex; align-items: flex-end; justify-content: space-between; gap: 40px; margin-bottom: 14px; }
/* The heading is measured, not left to fill the row: at 68px it sets on one
   659px line otherwise, and the spec breaks it after the comma. Constraining
   the column is what makes the break happen without a <br> in the content. */
.rack__head > div:first-child { max-width: 460px; }
.rack__intro { max-width: 360px; padding-bottom: 8px; }
.rack__intro > p + p { margin-top: 18px; }
.rack__grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  list-style: none; margin: 40px 0 0; padding: 0;
  border-top: 1px solid var(--line);
}

/* Symmetric horizontal padding, with the FIRST cell of each row flush to the
   wrap edge. The original had padding-left 0 on every cell, so only the previous
   cell's right padding separated the columns and the text in columns two and
   three sat hard against the rule. */
.rk {
  border-bottom: 1px solid var(--line); border-right: 1px solid var(--line);
  padding: 30px 34px 32px 34px;
  display: flex; flex-direction: column; gap: 10px;
  transition: background var(--dur) var(--ease);
}
.rack__grid .rk:nth-child(3n + 1) { padding-left: 0; }
/* No rule on the last column, or the grid trails a hanging line down its right
   edge. Rendered in the spec before it was caught there. */
.rack__grid .rk:nth-child(3n) { border-right: 0; }

.rk__name { font-family: var(--font-display); font-weight: var(--display-weight); font-size: 31px; line-height: 1.05; letter-spacing: var(--track-text); margin: 0; width: max-content; max-width: 100%; }
.rk__desc { font-size: 14.5px; line-height: 1.5; color: var(--muted); margin: 0; max-width: 320px; }
.rk__price { font-family: var(--font-mono); font-size: 14px; margin: 0; width: max-content; }

.rk__state {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.2em;
  text-transform: uppercase;
}
.rk__state .rk__dot { width: 7px; height: 7px; border-radius: 999px; background: currentColor; display: inline-block; flex-shrink: 0; }

/* The three live states, plus the two that never change. Colour carries the
   state and so does the wording — never colour alone. */
.rk__state--on,    .rk__state--sched { color: var(--accent); }
.rk__state--low    { color: var(--brand); }
.rk__state--order  { color: var(--muted); }
.rk__state--gone   { color: var(--gone); }

.rk.is-gone .rk__name { color: var(--gone); text-decoration: line-through; }
.rk.is-gone .rk__price { color: var(--gone); }
.rk.is-gone .rk__desc { color: var(--gone); }

/* --------------------------------------------------------- rack page list --- */

.rkpage__head { display: grid; grid-template-columns: minmax(0, 1fr) 440px; gap: 72px; align-items: end; padding-top: 76px; }
.rkpage__stamp { font-family: var(--font-mono); font-size: 12.5px; color: var(--muted); margin: 20px 0 0; line-height: 1.7; text-transform: uppercase; letter-spacing: 0.06em; }

.cats { display: flex; gap: 10px; flex-wrap: wrap; list-style: none; margin: 46px 0 0; padding: 0; }
.cat {
  font-family: var(--font-mono); font-size: 12.5px; letter-spacing: 0.08em;
  border-radius: 999px; padding: 0 20px; min-height: 44px;
  display: inline-flex; align-items: center; color: var(--ink);
  /* outline, not border: a 1px border makes this 2px wider than a filled pill
     and the row stops lining up. outline draws inside the box. */
  outline: 1px solid var(--line); outline-offset: -1px;
  background: transparent; cursor: pointer;
}
.cat:hover { outline-color: var(--ink); }
.cat[aria-pressed="true"] { background: var(--ink); color: var(--bg); outline-color: var(--ink); }

.rkgroups { display: flex; flex-direction: column; gap: 68px; padding: 56px 0 96px; }
.rkgroup__head { display: flex; align-items: baseline; gap: 20px; border-bottom: 1px solid var(--ink); padding-bottom: 16px; flex-wrap: wrap; }
.rkgroup__h { font-family: var(--font-display); font-weight: var(--display-weight); font-size: 46px; line-height: 1; letter-spacing: var(--track-text); margin: 0; }
.rkgroup__count { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.18em; color: var(--muted); margin: 0; text-transform: uppercase; }
.rkgroup__note { font-family: var(--font-mono); font-size: 12.5px; color: var(--muted); margin: 0 0 0 auto; }
.rkgroup__items { list-style: none; margin: 0; padding: 0; }

/* On the rack page the same .rk is a row, not a card.

   The builder emits FOUR children — state, name, description, price — with no
   wrapper around the middle two. A three-column grid therefore wrapped them:
   the description landed in the 120px price column and the price fell onto a
   second row at the far left. Every child is placed explicitly instead, so the
   markup can gain or lose a child without the row collapsing. */
.rkgroup__items .rk {
  display: grid; grid-template-columns: 150px minmax(0, 1fr) 120px;
  column-gap: 32px; row-gap: 7px;
  align-items: start; padding: 26px 0; border-right: 0;
}
.rkgroup__items .rk__state {
  grid-column: 1; grid-row: 1 / span 2;
  padding-top: 7px; font-size: 10px; letter-spacing: 0.16em; align-self: start;
}
.rkgroup__items .rk__name { grid-column: 2; grid-row: 1; font-size: 32px; line-height: 1.06; }
.rkgroup__items .rk__desc { grid-column: 2; grid-row: 2; font-size: 15px; max-width: 620px; }
.rkgroup__items .rk__price {
  grid-column: 3; grid-row: 1 / span 2;
  font-size: 16px; text-align: right; padding-top: 8px; margin: 0;
  width: auto; justify-self: end;
}

/* ------------------------------------------------------------ loam bands --- */

/* The second ground. Two of them per page at most — it is a band, not a theme. */
.loam {
  background: var(--accent); color: var(--foot-ink);
  position: relative; overflow: hidden;
  padding: 112px 0;
}
.loam .eyebrow { color: color-mix(in srgb, var(--foot-ink) 72%, var(--accent)); }
/* A shade larger and looser than body copy on bone: the loam ground eats
   contrast, and 16px at 1.62 reads tight on it. */
.loam .p, .loam .lede {
  font-size: 16.5px; line-height: 1.68;
  color: color-mix(in srgb, var(--foot-ink) 86%, var(--accent));
}
.loam .h2 { font-size: clamp(38px, 4.6vw, 66px); max-width: 820px; }
.loam .tlink { color: var(--foot-ink); border-bottom-color: color-mix(in srgb, var(--foot-ink) 72%, var(--accent)); }
.loam .rule { background: color-mix(in srgb, var(--foot-ink) 34%, var(--accent)); }

/* The mark blown up as a watermark. The only parallax on the site — it moves
   against the scroll, and only inside this band. */
.loam__bloom {
  position: absolute; right: -110px; top: -80px; width: 620px; height: 620px;
  opacity: 0.19; z-index: 0; pointer-events: none;
  will-change: transform;
}
.loam__bloom .bloom__petals { stroke: var(--foot-ink); stroke-width: 0.35; }
.loam__bloom .bloom__eye { fill: none; stroke: var(--foot-ink); stroke-width: 0.35; }
.loam > .wrap { position: relative; z-index: 1; }

.stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 40px; margin-top: 76px; max-width: 900px; list-style: none; padding: 0; }
.stat { border-top: 1px solid color-mix(in srgb, var(--foot-ink) 34%, var(--accent)); padding-top: 20px; display: flex; flex-direction: column; gap: 10px; }
.stat__n { font-family: var(--font-display); font-weight: var(--display-weight); font-size: 62px; line-height: 1; color: var(--brand); margin: 0; }
.stat__l { font-family: var(--font-mono); font-size: 12px; line-height: 1.6; letter-spacing: 0.1em; text-transform: uppercase; color: color-mix(in srgb, var(--foot-ink) 76%, var(--accent)); margin: 0; white-space: pre-line; }

/* --------------------------------------------------------------- gallery --- */

/* The builder emits a bare <li><img>. The caption in the spec is the photo's
   own alt text, surfaced — one string to write, not two. */
.tiles { padding: 104px 0 96px; }
.tiles__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 26px; list-style: none; margin: 34px 0 0; padding: 0; }
.tiles__grid li { display: flex; flex-direction: column; gap: 14px; overflow: hidden; }
.tiles__grid img { height: 340px; width: 100%; object-fit: cover; transition: transform 900ms var(--ease); }
.tiles__grid li:hover img { transform: scale(1.03); }

/* --------------------------------------------------------------- reviews --- */

.reviews { padding: 0 0 104px; }
.reviews__in { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: 64px; padding-top: 52px; }

/* RATING_SUMMARY is one inline string — "4.8 ★ · 341 Google reviews" — with the
   score in a <strong>. So the score is styled through that, not through a class
   of ours, and the rest of the line drops to a mono caption. */
.rating {
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.14em;
  color: var(--muted); margin: 0; text-transform: uppercase; line-height: 2.2;
}
.rating strong {
  display: block; font-family: var(--font-display); font-weight: var(--display-weight);
  font-size: 54px; line-height: 1; letter-spacing: -0.01em; color: var(--brand);
  margin-bottom: 12px;
}

.quotes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 52px; list-style: none; margin: 0; padding: 0; }
.quote { display: flex; flex-direction: column; gap: 18px; margin: 0; }
.quote__stars { color: var(--brand); font-size: 13px; letter-spacing: 0.24em; margin: 0; }
.quote__text { font-family: var(--font-display); font-weight: var(--display-weight); font-size: 26px; line-height: 1.34; letter-spacing: var(--track-text); font-style: italic; margin: 0; }
.quote__by { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.12em; color: var(--muted); margin: 0; text-transform: uppercase; }
.quote--pending { opacity: 0.55; }

/* ----------------------------------------------------------------- visit --- */

.visit { background: var(--band-up); border-top: 1px solid var(--line); padding: 96px 0; }
.visit__in { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 72px; align-items: start; }
.visit__addr { font-family: var(--font-mono); font-size: 15px; line-height: 1.9; margin: 0; font-style: normal; }
.visit__img { height: 620px; overflow: hidden; }
.visit__img img { width: 100%; height: 100%; object-fit: cover; }

/* The builder emits a <dl> of dt/dd pairs, with .closed on the dd. A two-column
   grid is what turns that into the ruled table the spec draws — floating the
   dd right instead would break the shared baseline on a wrapped day label. */
.hours {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  margin: 46px 0 0; padding: 0; max-width: 400px;
  font-family: var(--font-mono); font-size: 13.5px;
  color: var(--ink-soft);
}
.hours dt, .hours dd {
  margin: 0; padding: 11px 0;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 70%, var(--bg));
}
.hours dd { text-align: right; padding-left: 24px; }
.hours dd.closed, .hours dd.closed + dt { color: var(--gone); }
.hours__note { font-size: 13.5px; line-height: 1.6; color: var(--muted); margin: 18px 0 0; max-width: 400px; }

/* Inner-page grids. These used to be inline styles on the pages, which meant the
   responsive rules below could not reach them — inline wins — and the visit and
   cakes pages overflowed by 406px and 238px at 390. A fixed-track grid belongs in
   the stylesheet where a media query can override it. */
.visit__cols {
  display: grid; grid-template-columns: 340px 380px minmax(0, 1fr);
  gap: 56px; align-items: start; padding-bottom: 88px;
}
.cake__hero {
  display: grid; grid-template-columns: minmax(0, 1fr) 480px;
  gap: 64px; align-items: center; padding: 88px 0 80px;
}
.cake__prices {
  display: grid; grid-template-columns: 420px minmax(0, 1fr);
  gap: 72px; align-items: start;
}
.tiles__grid--two { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 0; }
.utils__grid--two { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 56px; }
.map { height: 520px; background: var(--band-up); outline: 1px solid var(--line); outline-offset: -1px; position: relative; overflow: hidden; }
.map svg { width: 100%; height: 100%; display: block; }
.map__pin {
  position: absolute; left: 22px; bottom: 20px; background: var(--bg);
  outline: 1px solid var(--line); outline-offset: -1px; padding: 12px 16px;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.06em; margin: 0;
  text-transform: uppercase;
}

/* ------------------------------------------------------------- utilities --- */

/* UTILITIES emits <div class="util util--N"> with an optional .util__img and an
   inner <div> around the text — so the grid container is a plain div, not a ul,
   and the photo is hidden here: the spec's utility cards are type only, and a
   third row of photographs after the gallery is one photograph too many. */
.utils { padding: 100px 0; }
.utils__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 44px; margin: 34px 0 0; }
.util { display: flex; flex-direction: column; gap: 16px; border-top: 1px solid var(--ink); padding-top: 22px; }
.util__h { font-family: var(--font-display); font-weight: var(--display-weight); font-size: 34px; line-height: 1.08; letter-spacing: var(--track-text); margin: 0; }
.util__p { font-size: 15px; line-height: 1.62; color: var(--ink-soft); margin: 0; }
.util .tlink { align-self: flex-start; }
.util__img { display: none; }

/* ---------------------------------------------------------------- steps ---- */

.steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 48px; list-style: none; margin: 40px 0 0; padding: 0; }
.step { border-top: 1px solid var(--ink); padding-top: 22px; display: flex; flex-direction: column; gap: 14px; }
.step__n { font-family: var(--font-mono); font-size: 13px; letter-spacing: 0.2em; color: var(--brand); margin: 0; }
.step__h { font-family: var(--font-display); font-weight: var(--display-weight); font-size: 38px; line-height: 1.06; letter-spacing: var(--track-text); margin: 0; }
.step__p { font-size: 15.5px; line-height: 1.62; color: var(--ink-soft); margin: 0; }

/* The starter page's clock: four ruled stops, mono times, serif headings. */
.clock { margin: 40px 0 0; padding: 0; list-style: none; border-bottom: 1px solid var(--line); }
.clock__row { display: grid; grid-template-columns: 200px minmax(0, 1fr) 300px; gap: 56px; align-items: start; padding: 40px 0; border-top: 1px solid var(--line); }
.clock__t { font-family: var(--font-mono); font-size: 34px; letter-spacing: -0.02em; color: var(--brand); margin: 0; }
.clock__when { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.18em; color: var(--muted); margin: 8px 0 0; text-transform: uppercase; }
.clock__h { font-family: var(--font-display); font-weight: var(--display-weight); font-size: 40px; line-height: 1.08; letter-spacing: var(--track-text); margin: 0 0 14px; }
.clock__aside { font-family: var(--font-mono); font-size: 12.5px; line-height: 1.8; color: var(--muted); border-left: 1px solid var(--line); padding-left: 24px; margin: 0; }

/* ---------------------------------------------------------------- prices --- */

.prices { list-style: none; margin: 0; padding: 0; }
.price {
  display: grid; grid-template-columns: minmax(0, 1fr) 180px; gap: 32px;
  align-items: baseline; padding: 24px 0; border-bottom: 1px solid var(--line);
}
.price__name { font-family: var(--font-display); font-weight: var(--display-weight); font-size: 30px; line-height: 1.1; letter-spacing: var(--track-text); margin: 0; }
.price__note { font-size: 14.5px; line-height: 1.55; color: var(--muted); margin: 7px 0 0; }
.price__v { font-family: var(--font-mono); font-size: 17px; text-align: right; margin: 0; }

/* ------------------------------------------------------------------- faq --- */

.faqs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 48px 72px; list-style: none; margin: 40px 0 0; padding: 0; }
.faq { border-top: 1px solid color-mix(in srgb, var(--foot-ink) 34%, var(--accent)); padding-top: 22px; }
.faq__q { font-family: var(--font-display); font-weight: var(--display-weight); font-size: 30px; line-height: 1.14; letter-spacing: var(--track-text); margin: 0 0 12px; }
.faq__a { font-size: 15.5px; line-height: 1.68; margin: 0; }

/* -------------------------------------------------------------- big call --- */

.bigcall { padding: 84px 0 92px; display: flex; align-items: center; justify-content: space-between; gap: 56px; flex-wrap: wrap; }
.bigcall__h { font-family: var(--font-display); font-weight: var(--display-weight); font-size: clamp(36px, 4vw, 58px); line-height: 1.04; max-width: 660px; margin: 0; }
.btn--call {
  display: inline-flex; align-items: center; gap: 13px; flex-shrink: 0;
  background: var(--brand); color: var(--on-brand); border-radius: 999px;
  min-height: 68px; padding: 0 36px;
  font-family: var(--font-mono); font-size: 19px;
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.btn--call:hover { background: var(--brand-dark); color: var(--on-brand); transform: translateY(-2px); }
.btn--call svg { width: 22px; height: 22px; }

/* ---------------------------------------------------------------- footer --- */

.foot { background: var(--foot-bg); color: var(--foot-ink); padding: 76px 0 44px; }
.foot__in { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 64px; align-items: start; }
.foot__mark { display: flex; align-items: center; gap: 13px; margin-bottom: 22px; color: var(--foot-ink); }
.foot__mark .mark__text, .foot__mark .mark__stack { font-family: var(--font-display); font-weight: var(--display-weight); font-size: 30px; line-height: 1; }
.foot__sub { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.24em; color: color-mix(in srgb, var(--foot-ink) 55%, var(--foot-bg)); text-transform: uppercase; }
.foot__h { font-family: var(--font-display); font-weight: var(--display-weight); font-size: 40px; line-height: 1.12; letter-spacing: var(--track-text); max-width: 460px; margin: 0; }
.foot__num { font-family: var(--font-mono); font-size: 21px; margin: 28px 0 0; color: var(--brand); display: inline-block; }
.foot__num:hover { color: var(--brand); border-bottom: 1px solid var(--brand); }
.foot__cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px; font-family: var(--font-mono); font-size: 13px; line-height: 2.1; }
.foot__cols h2 { font-size: 10.5px; letter-spacing: 0.16em; margin: 0 0 10px; font-weight: 500; text-transform: uppercase; color: color-mix(in srgb, var(--foot-ink) 45%, var(--foot-bg)); }
.foot__cols ul { list-style: none; margin: 0; padding: 0; }
.foot__cols a { color: color-mix(in srgb, var(--foot-ink) 76%, var(--foot-bg)); display: inline-flex; align-items: center; min-height: 44px; }
.foot__cols a:hover { color: var(--foot-ink); }
.foot__base {
  border-top: 1px solid color-mix(in srgb, var(--foot-ink) 18%, var(--foot-bg));
  margin-top: 56px; padding-top: 22px;
  display: flex; justify-content: space-between; gap: 24px; flex-wrap: wrap;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.1em;
  color: color-mix(in srgb, var(--foot-ink) 45%, var(--foot-bg));
  text-transform: uppercase;
}
.foot__base a { color: inherit; text-decoration: underline; }

/* The pitch-mode disclaimer. audit-page.js looks for .disclaimer by name —
   renaming it makes the guard line invisible to the audit. */
.disclaimer { text-transform: none; letter-spacing: 0.04em; max-width: 60ch; }
.portfolio-note { text-transform: none; letter-spacing: 0.04em; max-width: 60ch; }

/* ---------------------------------------------------------------- motion --- */

/* The hidden state is applied ONLY when the script that undoes it is running.
   No JS -> no .js on <html> -> nothing is ever hidden. The failure mode is
   "no animation", never "no content". */
.js .reveal { opacity: 0; transform: translateY(14px); }
.js .reveal.is-in { opacity: 1; transform: none; transition: opacity 620ms var(--ease), transform 620ms var(--ease); }
/* Children only slide. The section owns the fade — fading both multiplies the
   two opacities and a band sits washed out through most of its transition,
   which reads as a rendering fault. One fade per element. */
.js .reveal [data-stagger] { transform: translateY(12px); }
.js .reveal.is-in [data-stagger] {
  transform: none;
  transition: transform 560ms var(--ease);
  transition-delay: calc(var(--i, 0) * 40ms);
}

@media (prefers-reduced-motion: reduce) {
  html:not(.force-motion) .js .reveal,
  html:not(.force-motion) .js .reveal [data-stagger] { opacity: 1 !important; transform: none !important; transition: none !important; }
  html:not(.force-motion) .js .bloom--mark { animation: none; }
  html:not(.force-motion) .loam__bloom { transform: none !important; }
  html:not(.force-motion) .day__done,
  html:not(.force-motion) .day__now { transition: none; }
  html:not(.force-motion) * { scroll-behavior: auto !important; }
}

/* ------------------------------------------------------------ responsive --- */

@media (max-width: 1240px) {
  .hero__foot { grid-template-columns: minmax(0, 1fr) 260px; }
  .hero__links { grid-column: 1 / -1; }
  .clock__row { grid-template-columns: 150px minmax(0, 1fr); }
  .clock__aside { grid-column: 2; border-left: 0; padding-left: 0; }
  .rkpage__head { grid-template-columns: minmax(0, 1fr) 340px; gap: 48px; }
}

/* Below 1100 the rail would eat a fifth of a laptop viewport, so it goes and
   the header takes the number. No bottom bar yet — at this height it is the
   worse trade. */
@media (max-width: 1099px) {
  :root { --rail: 0px; --gutter: 40px; }
  .rail { display: none; }
  .hero { min-height: 720px; }
  .visit__in, .foot__in, .visit__cols, .cake__hero, .cake__prices { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  .visit__img { height: 380px; }
  .rack__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rack__grid .rk:nth-child(3n) { border-right: 1px solid var(--line); }
  .rack__grid .rk:nth-child(2n) { border-right: 0; }
  .tiles__grid, .utils__grid, .steps, .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .quotes, .faqs { grid-template-columns: minmax(0, 1fr); }
  .visit__cols { padding-bottom: 48px; }
  .cake__hero { padding: 48px 0 40px; }
  .reviews__in { grid-template-columns: minmax(0, 1fr); gap: 32px; }
}

@media (max-width: 859px) {
  .mast { gap: 12px; padding-top: 22px; }
  /* The link rows collapse into one menu target; the mark stays centred. */
  .mast__links { display: none; }
  .mast__menu {
    display: flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; flex-shrink: 0; color: inherit;
    background: none; border: 0; padding: 0; cursor: pointer;
  }
  .mast__spacer { width: 44px; flex-shrink: 0; }
  .mast__mark { flex-grow: 1; }
  .mast__lockup .mark__text, .mast__lockup .mark__stack { font-size: 27px; }
  .mast__line { font-size: 8.5px; letter-spacing: 0.22em; }

  .hero { min-height: 660px; }
  /* A phone hero is mostly type, so the wash goes vertical and heavier. */
  .hero__scrim {
    background: linear-gradient(to bottom,
      rgba(var(--scrim), 0.72) 0%, rgba(var(--scrim), 0.60) 42%, rgba(var(--scrim), 0.80) 100%);
  }
  .hero__copy { padding-top: 44px; }
  .hero__foot { grid-template-columns: minmax(0, 1fr); gap: 18px; padding-bottom: 28px; padding-top: 32px; }
  .hero__meta { text-align: left; }
  .hero__meta .hero__status { justify-content: flex-start; }
  .hero__links { flex-wrap: wrap; gap: 16px; }


  .rack__grid, .tiles__grid, .utils__grid, .steps, .stats,
  .tiles__grid--two, .utils__grid--two { grid-template-columns: minmax(0, 1fr); }
  .rack__grid .rk { border-right: 0 !important; padding-right: 0; }
  .rack__head, .rkpage__head { grid-template-columns: minmax(0, 1fr); display: block; }
  .rack__intro { max-width: none; margin-top: 24px; }
  .rkgroup__items .rk { grid-template-columns: minmax(0, 1fr) auto; gap: 12px 20px; }
  .rkgroup__items .rk__state { grid-column: 1 / -1; padding-top: 0; }
  .rkgroup__items .rk__price { padding-top: 0; }
  .rkgroup__note { margin-left: 0; width: 100%; }
  .clock__row { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .clock__aside { grid-column: 1; }
  .price { grid-template-columns: minmax(0, 1fr) auto; gap: 16px; }
  .day__stops { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .day__stop { display: grid; grid-template-columns: 62px minmax(0, 1fr); gap: 14px; padding: 13px 0; border-bottom: 1px solid color-mix(in srgb, var(--line) 70%, var(--bg)); }
  .day__tick { display: none; }
  .day__t { font-size: 15px; }
  .day__what { max-width: none; }
  .day__line, .day__done, .day__now { display: none; }
  .visit__img { height: 300px; }
  .map { height: 320px; }
  .bigcall { padding: 56px 0 64px; }
  .foot__cols { grid-template-columns: minmax(0, 1fr); gap: 24px; }

  /* Everything above the bar has to clear it. */
  body { padding-bottom: 76px; }
  .callbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    display: flex; align-items: center; gap: 10px;
    height: 76px; padding: 10px 16px;
    background: var(--bg); border-top: 1px solid var(--line);
  }
  .callbar__call {
    flex-grow: 1; min-height: 56px; border-radius: 999px;
    background: var(--brand); color: var(--on-brand);
    display: flex; align-items: center; justify-content: center; gap: 10px;
    font-family: var(--font-mono); font-size: 14px; letter-spacing: 0.04em;
  }
  .callbar__call:hover { color: var(--on-brand); }
  .callbar__dir {
    width: 56px; min-height: 56px; border-radius: 999px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center; color: var(--ink);
    outline: 1px solid color-mix(in srgb, var(--line) 60%, var(--ink)); outline-offset: -1px;
  }
  .callbar svg { width: 20px; height: 20px; }
}

@media (max-width: 520px) {
  :root { --gutter: 20px; }

  /* No entrance rotation on a phone. At 360 the mark is centred with almost no
     slack either side, and the -24deg start of bloomIn pushes its bounding box
     about a pixel past the viewport — enough for documentElement.scrollWidth to
     report an overflow for the length of the animation. It reads as a rendering
     fault in the audit and adds nothing at 27px. */
  .js .bloom--mark { animation: none; }
  .rack, .tiles, .utils { padding: 48px 0; }
  .loam { padding: 56px 0; }
  .visit { padding: 48px 0; }
  .rkgroups { gap: 44px; padding: 40px 0 56px; }
  .loam__bloom { width: 300px; height: 300px; right: -110px; top: -50px; }
  .stats { margin-top: 40px; }
}

/* -------------------------------------------------- print (a menu prints) --- */

@media print {
  .rail, .callbar, .hero__img, .hero__scrim, .loam__bloom, .cats { display: none; }
  body { padding: 0; }
  .hero { min-height: 0; background: none; color: var(--ink); }
  .hero__title, .hero__eyebrow, .hero__tagline, .hero__meta { color: var(--ink); text-shadow: none; }
  .loam { background: none; color: var(--ink); }
  .rk, .price { break-inside: avoid; }
}


/* =================================================================== motion ===
   Everything below is hover, pointer and scroll behaviour. It obeys the same two
   rules as the reveals: nothing is applied unless the script that drives it is
   running, and prefers-reduced-motion / ?capture=1 turn all of it off while
   leaving every state readable. */

/* The text link's rule sweeps in from the left rather than appearing. Two
   layers: a static hairline, and a brand line that scales over it. A border
   cannot do this, which is why .tlink stopped using one. */
.tlink { position: relative; border-bottom: 0 !important; }
.tlink::before,
.tlink::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
}
.tlink::before { background: currentColor; }
.tlink::after {
  height: 2px; background: var(--brand);
  transform: scaleX(0); transform-origin: left center;
  transition: transform 280ms var(--ease);
}
.tlink:hover::after,
.tlink:focus-visible::after { transform: scaleX(1); }
.tlink--quiet::before { background: var(--line); }
.hero .tlink--quiet::before { background: rgba(248, 243, 232, 0.32); }
.loam .tlink::before { background: color-mix(in srgb, var(--foot-ink) 72%, var(--accent)); }

/* Rack rows. A tint and a growing dot — the row is not a link, so it must not
   pretend to be one with a lift or a shadow. */
.rk:hover { background: var(--band-up); }
.rack__grid .rk:hover { background: color-mix(in srgb, var(--ink) 3%, var(--bg)); }
.rk .rk__dot { transition: transform 260ms var(--ease); }
.rk:hover .rk__dot { transform: scale(1.5); }
.rk.is-gone:hover { background: transparent; }

/* Day stops. Hovering one brings its hour forward without moving anything. */
.day__stop { transition: color 200ms var(--ease); }
.day__stop:hover .day__t { color: var(--brand); }
.day__stop:hover .day__what { color: var(--ink); }

/* Tiles. The photo scales; the caption steps up to meet it. */
.tiles__grid li p { transition: transform 420ms var(--ease), color 420ms var(--ease); }
.tiles__grid li:hover p { transform: translateY(-3px); color: var(--ink); }

/* The hero photograph drifts at a fraction of the scroll. A hint, not a ride —
   site.js caps it at 40px, the same cap template 2 uses. */
.hero__img { will-change: transform; }

/* Magnetic controls. The call button leans toward the pointer, capped at 8px:
   past that the thing you are aiming at moves away from you. */
.rail__call, .btn--call, .callbar__call { will-change: transform; }

/* ---------------------------------------------------------------- cursor --- */

/* A dot on the pointer and a ring that lerps behind it. The lag is what reads as
   weight rather than as a second pointer. Drawn only where there is a real
   pointer, and .has-cursor (which hides the native one) is added by the same
   script that draws the replacement — so a failure leaves a normal cursor
   rather than none. */
.cur, .cur-ring { display: none; }

@media (hover: hover) and (pointer: fine) {
  .cur, .cur-ring {
    position: fixed; top: 0; left: 0; z-index: 90; pointer-events: none;
    border-radius: 999px; display: block;
  }
  .cur { width: 7px; height: 7px; background: var(--brand); margin: -3.5px 0 0 -3.5px; }
  .cur-ring {
    width: 34px; height: 34px; margin: -17px 0 0 -17px;
    border: 1px solid color-mix(in srgb, var(--ink) 40%, transparent);
    transition: width 240ms var(--ease), height 240ms var(--ease),
                margin 240ms var(--ease), border-color 240ms var(--ease),
                background 240ms var(--ease);
  }
  .has-cursor, .has-cursor a, .has-cursor button { cursor: none; }
  /* A caret is information. Never hide it. */
  .has-cursor input, .has-cursor textarea, .has-cursor [contenteditable] { cursor: auto; }

  .is-over-hero .cur-ring { border-color: rgba(248, 243, 232, 0.55); }
  .is-hot .cur-ring {
    width: 54px; height: 54px; margin: -27px 0 0 -27px;
    border-color: var(--brand);
    background: color-mix(in srgb, var(--brand) 12%, transparent);
  }
}

@media (prefers-reduced-motion: reduce) {
  html:not(.force-motion) .tlink::after { transition: none; }
  html:not(.force-motion) .rk,
  html:not(.force-motion) .rk .rk__dot,
  html:not(.force-motion) .tiles__grid li p,
  html:not(.force-motion) .day__stop { transition: none; }
  html:not(.force-motion) .cur,
  html:not(.force-motion) .cur-ring { display: none !important; }
  html:not(.force-motion) .hero__img { transform: none !important; }
}


/* ============================================== the rest of the motion ===
   Added after the first pass, which shipped the hover and pointer effects but
   left the page static on load and on scroll: nothing was marked [data-stagger], so
   the stagger rule had nothing to act on, and the builder's data-count stats
   had no script to count them. */

/* The hero writes itself in on load. Three beats, not one — the eyebrow, then
   the headline, then the facts — so the first screen resolves rather than
   appearing. Only ever applied when .js is on the root. */
.js.hero-anim .hero__eyebrow,
.js.hero-anim .hero__title,
.js.hero-anim .hero__foot > * {
  opacity: 0; transform: translateY(18px);
  animation: heroIn 900ms var(--ease) forwards;
}
.js.hero-anim .hero__eyebrow   { animation-delay: 80ms; }
.js.hero-anim .hero__title     { animation-delay: 160ms; }
.js.hero-anim .hero__foot > *  { animation-delay: 420ms; }
.js.hero-anim .hero__foot > *:nth-child(2) { animation-delay: 500ms; }
.js.hero-anim .hero__foot > *:nth-child(3) { animation-delay: 580ms; }

@keyframes heroIn {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

/* The masthead condenses once past the first screen. Cosmetic only — no content
   depends on it, and it is padding, so nothing reflows around it. */
.mast { transition: padding-top 320ms var(--ease); }
.is-scrolled .mast { padding-top: 22px; }

/* The filled call controls take a fill that rises from the bottom, rather than
   swapping colour. --brand-dark is already in the palette. */
.rail__call, .btn--call, .callbar__call { position: relative; overflow: hidden; isolation: isolate; }
.rail__call::before, .btn--call::before, .callbar__call::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--brand-dark);
  transform: translateY(100%);
  transition: transform 380ms var(--ease);
}
.rail__call:hover::before, .btn--call:hover::before, .callbar__call:hover::before {
  transform: translateY(0);
}

/* The count-up needs a stable box or the stat row jumps as digits are added. */
.stat__n { font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  html:not(.force-motion) .js.hero-anim .hero__eyebrow,
  html:not(.force-motion) .js.hero-anim .hero__title,
  html:not(.force-motion) .js.hero-anim .hero__foot > * {
    opacity: 1 !important; transform: none !important; animation: none !important;
  }
  html:not(.force-motion) .mast,
  html:not(.force-motion) .rail__call::before,
  html:not(.force-motion) .btn--call::before,
  html:not(.force-motion) .callbar__call::before { transition: none; }
}
