/* =========================================================================
   BisiBean Coffee Roasting Co.
   Built from design-package.md. Palette sampled from the delivered imagery,
   accent measured out of the supplied logo, contrast ratios computed.
   ========================================================================= */

/* ---- tokens ---------------------------------------------------------- */
:root{
  --canvas:      #17100b;   /* espresso. 15.30:1 with --text */
  --panel:       #241a13;
  --panel-2:     #2e2118;
  --accent:      #ea9a25;   /* straight from the logo. 8.20:1 on canvas */
  --accent-soft: #c2aa9c;   /* clay. 8.54:1 on canvas */
  --accent-deep: #a05e12;
  --text:        #f2e6d6;
  --text-dim:    #9a8a7c;   /* 5.65:1 on canvas */
  --rule:        #4a3a2c;   /* decorative hairlines only */
  --border:      #846850;   /* 3.66:1 canvas. interactive borders + focus */
  --cream-band:  #e8d5b8;
  --cream-ink:   #2a1c12;

  --ff-display: "Fraunces", "Iowan Old Style", Georgia, serif;
  --ff-body:    "Karla", "Helvetica Neue", system-ui, sans-serif;
  --ff-mono:    "IBM Plex Mono", ui-monospace, "SF Mono", monospace;

  --wrap: 1180px;
  --gut: clamp(1.25rem, 4vw, 3rem);
  --ease: cubic-bezier(.22, .61, .36, 1);
}

/* ---- reset ------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--canvas);
  color: var(--text);
  font-family: var(--ff-body);
  font-size: clamp(1rem, .96rem + .2vw, 1.125rem);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, video { display: block; max-width: 100%; height: auto; }
h1, h2, h3 { font-family: var(--ff-display); font-weight: 600; line-height: 1.04; margin: 0; letter-spacing: -.018em; }
p { margin: 0 0 1.1em; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--border); outline-offset: 3px; border-radius: 2px; }
.sr-only, .skip:not(:focus) {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip:focus {
  position: fixed; top: .75rem; left: .75rem; z-index: 200;
  background: var(--accent); color: #1a1206; padding: .6rem 1rem;
  font-family: var(--ff-mono); font-size: .8rem; text-decoration: none;
}
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gut); }

/* ---- the signature element: the roast stamp --------------------------- */
.stamp {
  display: flex; align-items: center; gap: .7em;
  font-family: var(--ff-mono); font-size: .7rem; font-weight: 600;
  letter-spacing: .17em; text-transform: uppercase;
  color: var(--accent); margin: 0 0 1.4rem;
}
.stamp::after { content: ""; flex: 1 1 auto; height: 1px; background: linear-gradient(90deg, var(--accent), transparent 92%); }
/* .stamp__n was the batch number's colour. It is gone with the number: the
   roaster numbers its batches, but the actual current figure is the owner's to
   publish, not ours to invent. When a real number arrives, put it back in a
   <span class="stamp__n"> inside the stamp and re-add the rule below. */
.stamp__n { color: var(--accent-soft); }

/* ---- buttons ---------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: .55em;
  background: var(--accent); color: #1a1206;
  font-family: var(--ff-mono); font-size: .8rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; text-decoration: none;
  padding: .95em 1.5em; border: 1px solid var(--accent); border-radius: 2px;
  transition: background .2s var(--ease), border-color .2s var(--ease), transform .2s var(--ease);
}
.btn:hover { background: #f4ae3c; border-color: #f4ae3c; transform: translateY(-1px); }
.btn:active { background: var(--accent-deep); border-color: var(--accent-deep); transform: translateY(0); }
.btn--ghost { background: transparent; color: var(--accent); }
.btn--ghost:hover { background: var(--accent); color: #1a1206; }
.btn--sm { padding: .6em 1em; font-size: .72rem; }
.btn--wide { width: 100%; justify-content: center; padding-block: 1.1em; }

/* ---- vector layers ---------------------------------------------------- */
.grain {
  position: fixed; inset: 0; z-index: 90; pointer-events: none;
  opacity: .05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}
.chaff { position: fixed; inset: 0; z-index: 89; pointer-events: none; overflow: hidden; }
.chaff i {
  position: absolute; top: -6vh; width: 3px; height: 3px; border-radius: 50%;
  background: var(--accent-soft); opacity: 0;
  animation: drift linear infinite;
}
@keyframes drift {
  0%   { transform: translate3d(0, -6vh, 0) scale(.6); opacity: 0; }
  12%  { opacity: .34; }
  88%  { opacity: .2; }
  100% { transform: translate3d(var(--dx, 4vw), 108vh, 0) scale(1.1); opacity: 0; }
}

/* ---- top bar ---------------------------------------------------------- */
.top {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  display: flex; align-items: center; gap: clamp(1rem, 3vw, 2.5rem);
  padding: .85rem var(--gut);
  background: linear-gradient(180deg, rgba(23,16,11,.92), rgba(23,16,11,.55) 62%, transparent);
  backdrop-filter: blur(9px); -webkit-backdrop-filter: blur(9px);
}
.top__brand { display: flex; align-items: center; gap: .6rem; text-decoration: none; }
.top__logo { width: 34px; height: 34px; object-fit: contain; }
.top__name { font-family: var(--ff-display); font-size: 1.15rem; font-weight: 600; letter-spacing: -.01em; }
.top__nav { display: flex; gap: clamp(.9rem, 2vw, 1.8rem); margin-left: auto; }
.top__nav a {
  font-family: var(--ff-mono); font-size: .72rem; letter-spacing: .13em;
  text-transform: uppercase; text-decoration: none; color: var(--text-dim);
  /* The rule is drawn on the text, not the box, so growing the target to a
     tappable size does not leave the underline floating below the label. */
  display: inline-flex; align-items: center; min-height: 44px;
  text-decoration: underline; text-underline-offset: .3em;
  text-decoration-thickness: 1px; text-decoration-color: transparent;
  transition: color .2s, text-decoration-color .2s;
}
.top__nav a:hover { color: var(--text); text-decoration-color: var(--accent); }

/* =========================================================================
   HERO
   The copy sits in the bottom third. Measured: the top centre and right of
   these frames read ~2.0:1 against the cream text, and that is also where the
   action is, so nothing goes there. The bottom third plus the scrim measures
   5.6:1 and clears body text.
   ========================================================================= */
.hero { position: relative; height: 400vh; }
.hero__pin {
  position: sticky; top: 0; height: 100vh; height: 100svh;
  overflow: hidden; display: grid;
}
.hero__video, .hero__poster {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; background-color: var(--canvas);
}
.hero__video { opacity: 0; transition: opacity .5s var(--ease); }
.hero.is-live .hero__video { opacity: 1; }
.hero__poster {
  /* The still behind the hero is the resting frame, not the opening frame: it
     is the wider, calmer composition, and it is what the copy sits on. It is
     named here rather than injected by the script, because a background-image
     inside var() is resolved and fetched as soon as the rule applies. Setting
     the variable later fetched the default as well, so the page downloaded
     both stills for one image. */
  background-image: var(--poster, url("assets/hero-end.jpg"));
  background-size: cover; background-position: 50% 42%;
  transition: opacity .5s var(--ease), background-image .3s linear;
}
/* the still crossfades out once the scrub is live, and back in if it dies */
.hero__poster.is-still { opacity: 1; }
.hero__poster.is-gone { opacity: 0; }
.hero__scrim {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(to top, rgba(23,16,11,.94) 0%, rgba(23,16,11,.80) 20%, rgba(23,16,11,.42) 40%, rgba(23,16,11,.10) 58%, transparent 72%),
    linear-gradient(to bottom, rgba(23,16,11,.55) 0%, transparent 26%);
}
.drum {
  position: absolute; top: 50%; left: 50%; width: min(74vmin, 640px); aspect-ratio: 1;
  translate: -50% -50%; pointer-events: none; opacity: .3;
}
.drum span {
  position: absolute; inset: 0; border: 1px solid rgba(234,154,37,.34); border-radius: 50%;
  animation: spin 64s linear infinite;
}
.drum span:nth-child(2) { inset: 14%; border-color: rgba(194,170,156,.22); animation-duration: 92s; animation-direction: reverse; }
.drum span:nth-child(3) { inset: 30%; border-color: rgba(234,154,37,.16); animation-duration: 128s; }
@keyframes spin { to { transform: rotate(360deg); } }

/* the static hero: no JS, no video, narrow screens, reduced motion */
.hero__static {
  position: relative; z-index: 3; align-self: end;
  padding: 0 var(--gut) clamp(2.5rem, 8vh, 5.5rem);
  max-width: 44rem;
  transition: opacity .45s var(--ease);
}
.hero__h1 {
  font-size: clamp(2.9rem, 1.4rem + 7.4vw, 6.6rem);
  margin: 0 0 .5rem; text-wrap: balance;
  font-variation-settings: "opsz" 120;
}
.hero__sub { font-size: clamp(1.02rem, .95rem + .4vw, 1.3rem); color: var(--accent-soft); max-width: 34ch; margin-bottom: 1.9rem; }
.hero__phone { font-family: var(--ff-mono); font-size: .82rem; letter-spacing: .08em; margin: 1.1rem 0 0; }
.hero__phone a { color: var(--text-dim); text-decoration: none; border-bottom: 1px solid var(--rule); }
.hero__phone a:hover { color: var(--accent); border-bottom-color: var(--accent); }
.hero.is-live .hero__static { opacity: 0; pointer-events: none; }

/* the scroll journey */
.journey {
  position: absolute; inset: auto 0 0 0; z-index: 3;
  padding: 0 var(--gut) clamp(3rem, 11vh, 7rem);
  opacity: 0; pointer-events: none;
}
.hero.is-live .journey { opacity: 1; }
.band {
  position: absolute; left: var(--gut); right: var(--gut);
  bottom: clamp(3rem, 11vh, 7rem);
  opacity: 0; will-change: opacity, transform;
}
.band__line {
  font-size: clamp(2.4rem, 1.2rem + 6vw, 5.6rem);
  max-width: 20ch; text-wrap: balance;
  font-variation-settings: "opsz" 120;
}
.band__line span { display: inline-block; will-change: transform, opacity; }
.band--settle .band__line { max-width: 22ch; }
.band__cta {
  display: flex; align-items: center; gap: 1.3rem; flex-wrap: wrap;
  margin-top: 1.9rem; opacity: 0;
}
.band__tel { font-family: var(--ff-mono); font-size: .84rem; letter-spacing: .09em; color: var(--accent-soft); text-decoration: none; border-bottom: 1px solid var(--rule); padding-bottom: 3px; }
.band__tel:hover { color: var(--accent); border-bottom-color: var(--accent); }
.hero.is-live .band[data-band="3"] .band__cta { pointer-events: auto; }

.stamp--hero {
  position: absolute; z-index: 4; top: clamp(4.5rem, 12vh, 7rem);
  left: var(--gut); right: var(--gut);
  margin: 0; opacity: 0; transition: opacity .5s var(--ease);
}
.hero.is-live .stamp--hero { opacity: 1; }
.hero__ring {
  position: absolute; z-index: 4; right: var(--gut); top: 50%;
  width: 62px; height: 62px; translate: 0 -50%;
  border: 1px solid rgba(234,154,37,.3); border-radius: 50%;
  opacity: 0; transition: opacity .5s var(--ease);
}
.hero.is-live .hero__ring { opacity: 1; }
.hero__hint {
  position: absolute; z-index: 4; left: 50%; bottom: 1.2rem; translate: -50% 0;
  font-family: var(--ff-mono); font-size: .64rem; letter-spacing: .28em;
  text-transform: uppercase; color: var(--text-dim);
  display: flex; align-items: center; gap: .6rem;
  opacity: 0; transition: opacity .4s var(--ease);
}
.hero.is-live .hero__hint { opacity: .8; }
.hero__hint span { width: 1px; height: 26px; background: linear-gradient(180deg, var(--accent), transparent); }
.loader {
  position: absolute; z-index: 5; left: 50%; top: 50%; translate: -50% -50%;
  width: 34px; height: 34px; border-radius: 50%;
  border: 2px solid rgba(234,154,37,.24); border-top-color: var(--accent);
  opacity: 0; transition: opacity .3s var(--ease);
}
.loader.is-on { opacity: 1; animation: spin 1s linear infinite; }

/* =========================================================================
   SECTIONS. No two adjacent sections share a layout skeleton.
   ========================================================================= */
.sec { padding: clamp(4.5rem, 13vh, 9rem) 0; position: relative; }
.eyebrow {
  font-family: var(--ff-mono); font-size: .7rem; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase; color: var(--accent);
  margin: 0 0 1.1rem;
}
.h2 { font-size: clamp(1.9rem, 1.1rem + 3.4vw, 3.7rem); margin: 0 0 1.6rem; text-wrap: balance; font-variation-settings: "opsz" 96; }
.lede { font-size: clamp(1.06rem, 1rem + .45vw, 1.34rem); color: var(--accent-soft); max-width: 46ch; }
.fine { font-family: var(--ff-mono); font-size: .76rem; letter-spacing: .04em; color: var(--text-dim); max-width: 52ch; margin-top: 2.4rem; }

/* scroll reveal */
.reveal { opacity: 0; transform: translateY(20px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.reveal.is-in { opacity: 1; transform: none; }

/* ---- 1. the roast: offset printed frames, deliberately not a grid ------ */
.roast { background: var(--canvas); }
.frames { display: grid; grid-template-columns: 1.35fr .95fr; gap: clamp(1rem, 3vw, 2.5rem); align-items: end; margin: clamp(2.5rem, 6vh, 4rem) 0 clamp(2.5rem, 6vh, 4rem); }
.frame { margin: 0; position: relative; }
.frame img { width: 100%; background-color: var(--tint, var(--panel)); }
.frame::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  box-shadow: inset 0 0 0 1px rgba(242,230,214,.09);
}
.frame--b { margin-bottom: clamp(1.5rem, 5vh, 4rem); }
.frame figcaption {
  font-family: var(--ff-mono); font-size: .7rem; letter-spacing: .08em;
  color: var(--text-dim); margin-top: .8rem;
}
@media (max-width: 720px) { .frames { grid-template-columns: 1fr; } .frame--b { margin-bottom: 0; } }

/* ---- 2. the shelf: asymmetric grid with one wide cell ----------------- */
.shelf { background: var(--panel); }
.shelf__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(.7rem, 1.6vw, 1.3rem); margin: clamp(2rem, 5vh, 3.4rem) 0; }
.bean { margin: 0; overflow: hidden; }
.bean img { width: 100%; background-color: var(--tint, var(--panel-2)); transition: transform .8s var(--ease); }
.bean:hover img { transform: scale(1.035); }
.bean--wide { grid-column: span 2; }
@media (max-width: 760px) { .shelf__grid { grid-template-columns: 1fr 1fr; } .bean--wide { grid-column: span 2; } }

.card {
  position: relative; margin: 0; max-width: 46rem;
  background: var(--canvas); border: 1px solid var(--rule);
  padding: clamp(1.6rem, 3.4vw, 2.8rem);
  /* a corner notch, so the card reads as a cut label rather than a box */
  clip-path: polygon(0 0, calc(100% - 22px) 0, 100% 22px, 100% 100%, 0 100%);
}
.card__h3 { font-size: clamp(1.7rem, 1.2rem + 1.9vw, 2.5rem); margin: 0 0 .7rem; }
.card__body { color: var(--accent-soft); margin-bottom: 1.5rem; }
.shelf .fine { margin-top: 2.6rem; }

/* ---- 3. the bake: the one light band --------------------------------- */
.bake { background: var(--cream-band); color: var(--cream-ink); }
.bake__band {
  position: absolute; inset: 0; background-image: var(--bg, none);
  background-size: cover; background-position: 50% 50%;
  opacity: .17; mix-blend-mode: multiply;
}
.bake > .wrap { position: relative; }
.bake .eyebrow { color: #8a4f10; }
.bake .lede { color: #4a3320; }
.tiles {
  list-style: none; margin: clamp(2rem, 5vh, 3rem) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1px; background: rgba(42,28,18,.2);
  border: 1px solid rgba(42,28,18,.2);
}
.tiles li {
  background: var(--cream-band); padding: 1.15rem 1rem;
  font-family: var(--ff-display); font-size: 1.16rem; font-weight: 600;
}
@media (max-width: 560px) { .tiles { grid-template-columns: repeat(2, 1fr); } }

/* ---- 4. the place: full-bleed with the copy hung off a plate ---------- */
.place { position: relative; overflow: hidden; }
.place__bg {
  position: absolute; inset: 0; margin: 0;
  background-image: var(--bg, none); background-size: cover; background-position: 50% 45%;
}
.place::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(23,16,11,.96) 6%, rgba(23,16,11,.78) 46%, rgba(23,16,11,.52) 100%);
}
.place > .wrap { position: relative; z-index: 2; }
.facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1px; margin: clamp(2.4rem, 6vh, 3.6rem) 0 0;
  background: var(--rule); border: 1px solid var(--rule);
}
.facts > div { background: rgba(23,16,11,.86); padding: 1.15rem 1.2rem; }
.facts dt { font-family: var(--ff-mono); font-size: .66rem; letter-spacing: .16em; text-transform: uppercase; color: var(--accent); margin-bottom: .45rem; }
.facts dd { margin: 0; font-size: .97rem; color: var(--accent-soft); }

/* ---- 5. visit: table on the left, address plate on the right ---------- */
.visit { background: var(--canvas); }
.visit__grid { display: grid; grid-template-columns: 1.25fr .85fr; gap: clamp(1.6rem, 4vw, 3.4rem); align-items: start; }
.hours table { width: 100%; border-collapse: collapse; }
.hours th, .hours td { text-align: left; padding: .78rem 0; border-bottom: 1px solid var(--rule); }
.hours th { font-weight: 400; color: var(--text); }
.hours td { font-family: var(--ff-mono); font-size: .88rem; text-align: right; color: var(--accent-soft); }
.hours .is-closed th, .hours .is-closed td { color: var(--text-dim); }
.hours .is-closed td::after { content: " (roastery day)"; font-size: .72rem; }
.note { font-size: .95rem; color: var(--text-dim); margin-top: 1.2rem; max-width: 42ch; }
.visit__side { border: 1px solid var(--rule); background: var(--panel); padding: clamp(1.4rem, 3vw, 2.2rem); }
.visit__addr { font-size: 1.02rem; line-height: 1.75; }
.visit__tel { font-family: var(--ff-mono); font-size: 1.05rem; margin: 1.2rem 0 1.5rem; }
.visit__tel a { text-decoration: none; border-bottom: 1px solid var(--rule); padding-bottom: 3px; }
.visit__tel a:hover { color: var(--accent); border-bottom-color: var(--accent); }
@media (max-width: 820px) { .visit__grid { grid-template-columns: 1fr; } }

/* ---- 7. order: form on a rule-lined plane ---------------------------- */
.order { background: var(--panel); }
.form { display: grid; grid-template-columns: 1fr 1fr; gap: 1.4rem; margin-top: clamp(2rem, 5vh, 3rem); max-width: 52rem; }
.field { display: flex; flex-direction: column; gap: .45rem; }
.field--wide { grid-column: 1 / -1; }
.field label { font-family: var(--ff-mono); font-size: .68rem; letter-spacing: .16em; text-transform: uppercase; color: var(--accent); }
.field input, .field select, .field textarea {
  background: var(--canvas); color: var(--text);
  border: 1px solid var(--rule); border-radius: 2px;
  padding: .82rem .9rem; font: inherit; font-size: .98rem; width: 100%;
  transition: border-color .2s var(--ease);
}
.field textarea { resize: vertical; min-height: 5.5rem; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--border); }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--border); outline: 2px solid var(--border); outline-offset: 1px; }
.field input[aria-invalid="true"] { border-color: #c9552f; }
.form__note { font-family: var(--ff-mono); font-size: .7rem; letter-spacing: .04em; color: var(--text-dim); margin: .9rem 0 0; text-align: center; }
.form__note.is-err { color: #e08a68; }
@media (max-width: 620px) { .form { grid-template-columns: 1fr; } }

/* ---- footer ----------------------------------------------------------- */
.foot { background: var(--canvas); border-top: 1px solid var(--rule); padding: clamp(3.5rem, 9vh, 6rem) 0 2.5rem; }
.foot__top { display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; padding-bottom: 2rem; border-bottom: 1px solid var(--rule); }
.foot__logo { width: 52px; height: 52px; object-fit: contain; }
.foot__name { font-family: var(--ff-display); font-size: 1.4rem; margin: 0; }
.foot__top .stamp { margin: 0 0 0 auto; flex: 1 1 14rem; }
.foot__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 2rem; padding: 2.4rem 0; }
.foot__grid p { font-size: .95rem; color: var(--text-dim); margin: 0 0 .3rem; }
.foot__h { font-family: var(--ff-mono); font-size: .66rem; letter-spacing: .16em; text-transform: uppercase; color: var(--accent) !important; margin-bottom: .8rem !important; }
.foot__social { display: flex; gap: 1.1rem; margin-top: .5rem; }
/* "X" is a single glyph, so on its own it lands under the 24px target minimum.
   The size comes from the box, and the underline is drawn on the text rather
   than the box, so growing the target does not push the rule away from it. */
.foot__social a {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px;
  text-decoration: underline; text-underline-offset: .28em;
  text-decoration-thickness: 1px; text-decoration-color: var(--rule);
}
.foot__social a:hover { color: var(--accent); text-decoration-color: var(--accent); }
.foot__base { font-family: var(--ff-mono); font-size: .68rem; letter-spacing: .06em; color: var(--rule); margin: 0; padding-top: 1.6rem; border-top: 1px solid var(--rule); }

/* ---- floating WhatsApp, desktop only ---------------------------------- */
.wa {
  position: fixed; right: var(--gut); bottom: var(--gut); z-index: 95;
  display: none; align-items: center; gap: .6rem;
  background: var(--accent); color: #1a1206; text-decoration: none;
  font-family: var(--ff-mono); font-size: .74rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase;
  padding: .95em 1.3em; border-radius: 2px;
  box-shadow: 0 12px 34px rgba(0,0,0,.42);
  transition: transform .2s var(--ease), background .2s var(--ease);
}
.wa:hover { background: #f4ae3c; transform: translateY(-2px); }
.wa.is-shown { display: inline-flex; }
@media (min-width: 1000px) { .wa { display: inline-flex; } }

/* ---- no scrub: the hero becomes a page, not a scrub -------------------- */
/* The 400vh scroll range and the sticky pin belong to the video. Wherever the
   video is gated off there is no scrub to drive them, and the four band
   headlines sit at opacity 0 inside a hero four viewports tall, so the page
   scrolls through with nothing on it and looks frozen. Here the hero collapses
   to a single screen and the headlines stack underneath the static hero as
   ordinary text: read, not waited on.

   Two conditions trigger it. The media query catches the two CSS can see and
   works before any script runs; .hero.is-static is set by the same gate
   function that sets up the scrub, and catches the rest (save-data, 2g on a
   wide screen, a browser with no H.264 decoder). The two blocks below must
   stay in step. */
@media (max-width: 899px), (prefers-reduced-motion: reduce) {
  .hero { height: auto; }
  .hero__pin { position: relative; top: auto; height: auto; min-height: 100svh; display: block; background: var(--canvas); }
  .hero__static { padding-top: calc(71px + clamp(1.6rem, 5vh, 3rem)); }
  /* Collapsed, the copy is permanent rather than revealed by a scrub, so the
     wash is heavier than it is during playback: the top gradient holds almost
     to opaque where the h1 and the standfirst sit, which are small text on a
     photograph and need 4.5:1. Measured against the rendered pixels, not
     against the token. */
  .hero__scrim {
    background:
      linear-gradient(to top, rgba(23,16,11,.97) 0%, rgba(23,16,11,.93) 32%,
                             rgba(23,16,11,.80) 52%, rgba(23,16,11,.52) 74%,
                             rgba(23,16,11,.18) 90%, transparent 100%),
      linear-gradient(to bottom, rgba(23,16,11,.88) 0%, rgba(23,16,11,.74) 26%,
                             rgba(23,16,11,.36) 46%, transparent 62%);
  }
  .journey { position: static; inset: auto; opacity: 1; pointer-events: auto;
    background: linear-gradient(to bottom, rgba(23,16,11,0) 0%, var(--canvas) 28%, var(--canvas) 100%);
    margin-top: calc(clamp(1rem, 4vh, 2rem) * -1);
    padding: clamp(1rem, 5vh, 3rem) var(--gut) clamp(2.5rem, 7vh, 4rem);
  }
  .band {
    position: static; opacity: 1; max-width: 24ch;
    margin: 0 0 1.5rem; padding-left: 1.1rem;
    border-left: 2px solid var(--accent-deep);
  }
  /* band 1 repeats the h1, so it would read as a stutter */
  .band[data-band="0"] { display: none; }
  .band__line { font-size: clamp(1.6rem, 1.1rem + 2.6vw, 2.4rem); max-width: none; }
  /* inline, because the scrub wrote them and the gate that clears them is
     debounced 180ms; this closes the gap rather than waiting for the script */
  .band__line span { transform: none !important; opacity: 1 !important; }
  /* the static hero directly above already carries the order button and the
     number. A second identical pair 100px lower reads as a mistake, and there
     is meant to be one way to order */
  .band__cta { display: none; }
  .hero__ring, .hero__hint, .stamp--hero, .drum, .chaff, .loader { display: none; }
}
.hero.is-static .hero { height: auto; }
.hero.is-static .hero__pin { position: relative; top: auto; height: auto; min-height: 100svh; display: block; background: var(--canvas); }
.hero.is-static .hero__static { padding-top: calc(71px + clamp(1.6rem, 5vh, 3rem)); }
.hero.is-static .hero__scrim {
  background:
    linear-gradient(to top, rgba(23,16,11,.97) 0%, rgba(23,16,11,.93) 32%,
                           rgba(23,16,11,.80) 52%, rgba(23,16,11,.52) 74%,
                           rgba(23,16,11,.18) 90%, transparent 100%),
    linear-gradient(to bottom, rgba(23,16,11,.88) 0%, rgba(23,16,11,.74) 26%,
                           rgba(23,16,11,.36) 46%, transparent 62%);
}
.hero.is-static .journey { position: static; inset: auto; opacity: 1; pointer-events: auto;
  background: linear-gradient(to bottom, rgba(23,16,11,0) 0%, var(--canvas) 28%, var(--canvas) 100%);
  margin-top: calc(clamp(1rem, 4vh, 2rem) * -1);
  padding: clamp(1rem, 5vh, 3rem) var(--gut) clamp(2.5rem, 7vh, 4rem);
}
.hero.is-static .band {
  position: static; opacity: 1; max-width: 24ch;
  margin: 0 0 1.5rem; padding-left: 1.1rem;
  border-left: 2px solid var(--accent-deep);
}
.hero.is-static .band[data-band="0"] { display: none; }
.hero.is-static .band__line { font-size: clamp(1.6rem, 1.1rem + 2.6vw, 2.4rem); max-width: none; }
.hero.is-static .band__line span { transform: none !important; opacity: 1 !important; }
.hero.is-static .band__cta { display: none; }
.hero.is-static .hero__ring, .hero.is-static .hero__hint,
.hero.is-static .stamp--hero, .hero.is-static .drum,
.hero.is-static .chaff, .hero.is-static .loader { display: none; }

/* ---- motion off ------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
  .chaff, .drum { display: none; }
  .hero { height: auto; }
  .hero__pin { position: relative; height: auto; min-height: 100vh; }
  .hero__ring, .hero__hint, .stamp--hero { display: none; }
  .loader { display: none; }
}

/* ---- small screens ---------------------------------------------------- */
@media (max-width: 560px) {
  .top__nav { display: none; }
  .top__cta { margin-left: auto; }
  /* On a phone the header is the only order button in reach, so it has to be
     a real target rather than a 34px pill. */
  .top__cta { min-height: 44px; padding-inline: 1.1em; }
  .top__brand { min-height: 44px; display: inline-flex; align-items: center; }
  .shelf__grid { grid-template-columns: 1fr; }
  .bean--wide { grid-column: span 1; }
  .foot__top .stamp { margin-left: 0; }
}
