/* ===================== ROOT / RESET ===================== */
:root{
  --cream: #FFF7E9;
  --cream-soft: #fdf6e6;
  --paper: #fffaf0;
  --ink: #2b1d12;
  --ink-soft: #5c4a3a;
  --green-dark: #1e4d38;
  --green: #2f6b4f;
  --oval: #2f7a52;
  --oval-dark: #1f5a3b;
  --wood: #7a4a26;
  --wood-dark: #4a2c14;
  --roof: #d9622f;
  --roof-dark: #b5461f;
  --red: #c50000;
  --gold: #eab54d;
  --gold-dark: #d99a2c;
  --pink: #f2a79e;
  --pink-dark: #e8877a;
  --shadow: 0 20px 45px -20px rgba(43,29,18,0.35);
  --radius-lg: 28px;
  --radius-md: 18px;
  --radius-sm: 10px;
  --ff-display: 'Sofia Sans Semi Condensed', sans-serif;
  --ff-logo: 'Source Serif Pro', serif;
  --ff-body: 'Sofia Sans Semi Condensed', sans-serif;
  --header-h: 66px;
}

*,*::before,*::after{ box-sizing: border-box; }
html{ scroll-behavior: smooth; }
body{
  margin:0;
  font-family: var(--ff-body);
  font-weight: 700;
  background: var(--cream);
  color: var(--ink);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  position: relative;
}

img{ max-width:100%; display:block; }
a{ color: inherit; text-decoration: none; }
ul{ list-style:none; margin:0; padding:0; }
h1,h2,h3{ font-family: 'Oswald', var(--ff-display); margin:0; font-weight:700; }
p{ margin:0; }
button{ font-family: inherit; cursor:pointer; }
.visually-hidden{
  position:absolute; width:1px; height:1px;
  overflow:hidden; white-space:nowrap;
  clip-path: inset(50%);
}

/* Decorative ledger-margin rule used on the Recommended/Explore pages */
.margin-rule{
  position: absolute;
  top: 0; bottom: 0;
  left: 64px;
  width: 1px;
  background: var(--red);
  opacity: 0.28;
  z-index: 1;
  pointer-events: none;
}

.section-inner{
  max-width: 1160px;
  margin: 0 auto;
  padding: 110px 32px;
}
.eyebrow{
  display:inline-block;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--red);
  font-weight: 700;
  margin-bottom: 12px;
}
.accent{ color: var(--red); }

.btn{
  display:inline-flex;
  align-items:center;
  gap:8px;
  padding: 14px 28px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: none;
  transition: transform .35s cubic-bezier(.2,.8,.2,1), box-shadow .35s ease, background .3s ease, color .3s ease;
  cursor:pointer;
}
.btn-gold{
  background: var(--gold);
  color: var(--ink);
  box-shadow: 0 12px 24px -10px rgba(217,154,44,0.55);
}
.btn-gold:hover{ background: var(--gold-dark); transform: translateY(-3px); box-shadow: 0 18px 30px -10px rgba(217,154,44,0.65); }
.btn-red{
  background: var(--red);
  color: var(--cream-soft);
  box-shadow: 0 12px 24px -10px rgba(197,0,0,0.55);
}
.btn-red:hover{ background: #a30000; transform: translateY(-3px); box-shadow: 0 18px 30px -10px rgba(197,0,0,0.65); }
.btn-dark{
  background: var(--ink);
  color: var(--cream-soft);
  box-shadow: 0 12px 24px -10px rgba(0,0,0,0.4);
}
.btn-dark:hover{ transform: translateY(-3px); background: var(--green-dark); }

/* ===================== SCROLL PROGRESS BAR ===================== */
.scroll-progress{
  position: fixed;
  top:0; left:0;
  height: 3px;
  width: 0%;
  background: linear-gradient(90deg, var(--gold), var(--red));
  z-index: 2000;
  transition: width .05s linear;
}

/* ===================== REVEAL UTILITY ===================== */
.reveal{
  opacity: 0;
  transform: translateY(34px);
  transition: opacity .8s cubic-bezier(.2,.7,.2,1), transform .8s cubic-bezier(.2,.7,.2,1);
}
.reveal.in-view{ opacity:1; transform: translateY(0); }

/* ===================== HEADER / NAV ===================== */
.site-header{
  position: fixed;
  top:0; left: 0; right: 0;
  height: var(--header-h);
  z-index: 1000;
  display:flex;
  align-items:center;
  background: var(--green-dark);
}
/* The scalloped "stamp" edge asset is taller than the header itself (it
   includes the perforated bottom border), so it's painted via an absolutely
   positioned layer sized/scaled so its flat top matches --header-h exactly,
   letting the scallop bumps hang past the header's own box into the page
   below rather than being clipped to the header's height. */
.site-header::before{
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: calc(var(--header-h) * 143 / 82);
  background: url("images/stamp header long.png") repeat-x left top / calc(var(--header-h) * 2570 / 82) calc(var(--header-h) * 143 / 82);
  pointer-events: none;
}
.nav-wrap{
  position: relative;
  z-index: 1;
  width:100%;
  padding: 0 32px;
  display:flex;
  align-items:center;
  justify-content: space-between;
  gap: 24px;
}
.logo{
  font-family: 'Oswald', var(--ff-display);
  font-style: normal;
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--cream-soft);
  white-space: nowrap;
}
.logo span{ color: #FFCF5F; }

.nav-right{
  display:flex;
  align-items:center;
  gap: 32px;
}
.site-nav{
  display:flex;
  align-items:center;
  gap: 32px;
}

.nav-link{
  position: relative;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink-soft);
  padding: 6px 0;
  transition: color .3s ease;
}
.nav-link::after{
  content:"";
  position:absolute;
  left:0; bottom:0;
  height:2px; width:0;
  background: var(--red);
  transition: width .3s ease;
}
.nav-link:hover{ color: var(--ink); }
.nav-link:hover::after, .nav-link.active::after{ width: 100%; }
.nav-link.active{ color: var(--ink); }

.site-nav .nav-link{
  font-size: 1.1rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.82);
}
.site-nav .nav-link:hover,
.site-nav .nav-link.active{ color: var(--cream-soft); }

.hamburger{
  display:none;
  width: 36px; height: 36px;
  border-radius: 50%;
  border: none;
  background: rgba(255,255,255,0.15);
  flex-direction: column;
  align-items:center;
  justify-content:center;
  gap:5px;
}
.hamburger span{
  width: 18px; height: 2px;
  border-radius: 2px;
  background: var(--cream-soft);
  transition: transform .3s ease, opacity .3s ease;
}
.hamburger.open span:nth-child(1){ transform: translateY(7px) rotate(45deg); }
.hamburger.open span:nth-child(2){ opacity:0; }
.hamburger.open span:nth-child(3){ transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 700px){
  .site-nav{ display:none; }
  .hamburger{ display:flex; }
}

/* ===================== MOBILE DRAWER (left-side menu) ===================== */
.drawer-overlay{
  position: fixed;
  inset: 0;
  background: rgba(20,14,8,0.4);
  z-index: 2400;
  opacity: 0;
  visibility: hidden;
  transition: opacity .35s ease, visibility .35s ease;
}
.drawer-overlay.open{ opacity: 1; visibility: visible; }

.mobile-drawer{
  position: fixed;
  top: 0; left: 0; bottom: 0;
  width: min(78vw, 320px);
  background: linear-gradient(165deg, var(--pink), var(--pink-dark));
  z-index: 2500;
  padding: 110px 20px 40px 40px;
  transform: translateX(-100%);
  transition: transform .45s cubic-bezier(.2,.8,.2,1);
  box-shadow: 30px 0 60px -30px rgba(0,0,0,0.4);
  /* scalloped right edge, echoing the scallop-blob motif used elsewhere */
  clip-path: polygon(
    0% 0%, 100% 0%,
    93% 8.33%, 100% 16.67%, 93% 25%, 100% 33.33%,
    93% 41.67%, 100% 50%, 93% 58.33%, 100% 66.67%,
    93% 75%, 100% 83.33%, 93% 91.67%, 100% 100%,
    0% 100%
  );
}
.mobile-drawer.open{ transform: translateX(0); }

.drawer-close{
  position: absolute;
  top: 26px; left: 28px;
  width: 36px; height: 36px;
  border: none;
  background: none;
  color: var(--ink);
  font-size: 1.8rem;
  line-height: 1;
  cursor: pointer;
}

.drawer-nav{
  display: flex;
  flex-direction: column;
  gap: 26px;
}
.drawer-nav .nav-link{
  font-family: var(--ff-display);
  font-style: italic;
  font-size: 1.5rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--ink);
  padding: 0;
}
.drawer-nav .nav-link::after{ display: none; }
.drawer-nav .nav-link:hover,
.drawer-nav .nav-link.active{ color: var(--cream-soft); }

/* ===================== DECORATIVE DIVIDER ===================== */
.deco-divider{ display: none; }

.diamond-divider{
  display:flex;
  align-items:center;
  justify-content:center;
  gap: 12px;
  padding: 56px 0 8px;
}
.diamond-divider .dash{ width: 44px; height: 2px; background: var(--pink-dark); border-radius: 2px; }
.diamond-divider .diamond{ width: 12px; height: 12px; background: var(--pink-dark); transform: rotate(45deg); border-radius: 2px; }

/* ===================== HERO SCENE ===================== */
.hero{ position:relative; }
/* Short enough that the plate's fall reads as continuous downward motion
   leaving the warung behind, not a long hold while it spins in place. */
.hero-scroll-wrap{ height: 108vh; position: relative; }
.hero-pin{
  position: sticky;
  top:0;
  height: 100vh;
  overflow: hidden;
  display:flex;
  align-items:center;
  justify-content:center;
}
.hero-illustration{
  position:absolute; inset:0;
  background: #f6dcb8; /* matches the illustration's sky tone if any edge peeks through */
  overflow: hidden;
}
.hero-illustration img,
.hero-illustration video{
  position:absolute; inset:0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center center;
  will-change: transform;
}
/* Fades the illustration into the gold tone the next section's batik
   pattern sits on, so the two sections read as one continuous scene
   rather than a hard cut. */
.hero-illustration::after{
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 42%;
  background: linear-gradient(to bottom, rgba(234,181,77,0) 0%, rgba(234,181,77,0.6) 55%, rgba(234,181,77,1) 100%);
  pointer-events: none;
}

/* ===================== HERO TITLE ===================== */
.hero-title{
  position: absolute;
  top: 13%;
  left: 50%;
  width: 100%;
  transform: translate(-50%, 0);
  z-index: 5;
  text-align:center;
  will-change: transform, opacity;
}
/* Hero logo text only ("Snacks of the Archipelago") keeps the serif font -
   everything else on the site now matches the bold condensed sans used in
   the "Indonesian Snacks..." reveal, via the --ff-display variable above. */
.script-lead{
  font-family: 'Oswald', var(--ff-logo);
  font-style: normal;
  font-weight: 700;
  font-size: clamp(3.4rem, 7.2vw, 5rem);
  color: var(--green-dark);
  margin-bottom: 6px;
}
.hero-title h1{ line-height: 1; }
.pill-badge{
  display:inline-block;
  font-family: 'Oswald', var(--ff-logo);
  font-style: normal;
  font-size: clamp(3.3rem, 8.4vw, 5.7rem);
  font-weight: 700;
  color: var(--cream-soft);
  background: var(--red);
  padding: 10px 38px;
  border-radius: 0;
  transform: rotate(-2deg);
  box-shadow: 0 14px 26px -10px rgba(200,64,44,0.5);
}


/* ===================== SCROLL-TRIGGER FLYING PLATE =====================
   Fixed to the viewport the whole time (traveling from the warung counter
   down to the celebrate-teaser's landing spot, then resting there) - see
   currentLandingViewportY() in home.js, which reads the landing target's
   live on-screen position every frame rather than a one-time snapshot, so
   once that target's pinned section eventually un-sticks and scrolls
   normally, the plate follows it away continuously, with no jump and no
   fade needed. */
.plate{
  position: fixed;
  left: 50%;
  top: 0;
  width: 200px;
  height: 195px;
  transform: translate(-50%, -260px) rotate(-6deg) scale(0.85);
  z-index: 60;
  pointer-events: none;
  will-change: transform, top, left;
}
/* The whole bag photo shows the entire time, airborne and landed alike - no
   swap to the cropped/open variant on landing. */
.plate-bag{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center top;
}
.plate-bag-open{ opacity: 0; }

.scroll-cue{
  position:absolute;
  bottom: 34px;
  left:50%;
  transform: translateX(-50%);
  display:flex;
  flex-direction:column;
  align-items:center;
  gap: 10px;
  color: var(--green-dark);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 700;
  z-index: 6;
  transition: opacity .4s ease;
}
.scroll-cue-line{
  width: 1px; height: 46px;
  background: rgba(30,77,56,0.3);
  position: relative;
  overflow:hidden;
}
.scroll-cue-line i{
  position:absolute;
  top:-100%; left:0;
  width:100%; height:100%;
  background: var(--red);
  animation: cueDrop 1.8s ease-in-out infinite;
}
@keyframes cueDrop{
  0%{ top:-100%; }
  60%{ top:100%; }
  100%{ top:100%; }
}

/* ===================== TAPED PHOTO CARDS (reused) ===================== */
.photo-card{
  position: relative;
  background: var(--paper);
  padding: 10px 10px 18px;
  border-radius: 4px;
  box-shadow: var(--shadow);
  transition: transform .3s ease, box-shadow .3s ease;
}
.photo-card:hover{ transform: rotate(0deg) scale(1.04); z-index: 5; box-shadow: 0 26px 55px -18px rgba(43,29,18,0.4); }
.photo-card .tape{
  position:absolute; top:-12px; left:50%;
  transform: translateX(-50%) rotate(-6deg);
  width: 64px; height: 22px;
  background: rgba(240,200,120,0.6);
}
.tilt-a{ transform: rotate(-4deg); }
.tilt-b{ transform: rotate(3deg); }
.tilt-c{ transform: rotate(-2deg); }

.photo-art{
  width: 100%;
  height: 160px;
  border-radius: 2px;
  background: linear-gradient(155deg, var(--cream), #efe0c4);
  position: relative;
  overflow: hidden;
}
.photo-art img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ===================== CELEBRATE TEASER (the plate's landing spot) =====================
   Now a scroll-jacked pinned scene, like the ingredients section: the plate
   lands, scroll continues to "hold" on the bowl for a beat (nothing moves),
   then a handful of random snacks tumble in from above one after another. */
.celebrate-teaser{ background: var(--cream); position: relative; overflow: hidden; }
.celebrate-teaser::before{
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 95%;
  background: url("images/yellow batik extended.png") no-repeat;
  background-size: 140%;
  background-position: center;
  z-index: 0;
}
.celebrate-scroll-wrap{ position: relative; }
.celebrate-pin{
  position: sticky;
  top: 0;
  height: 100vh;
  z-index: 55; /* position:sticky always opens its own stacking context, so
    this - not the falling-snacks z-index inside it - is what's compared
    against the hero plate (z-index: 60), which lives outside this subtree
    entirely. Deliberately kept below the plate so the falling snacks (and
    everything else in this subtree) paint behind the bag, not in front of
    it - they should look like they're landing inside it, not on top of it. */
  display: flex;
  align-items: flex-start;
  overflow: hidden;
}
/* The heading stays anchored near the top of the pinned screen (rather than
   the whole heading+basket block being vertically centered as one unit) so
   it's always fully visible - the (much taller) landed basket hangs below
   it and is allowed to run off the bottom edge of the screen, clipped by
   .celebrate-pin's overflow: hidden. That's the intended look, not a bug. */
.celebrate-teaser-inner{ text-align: center; width: 100%; padding-top: 16vh; }
/* Enlarged via transform (not font-size) on purpose: transform never
   triggers reflow, so the box this occupies in the .celebrate-pin flex
   stack - and therefore the landing oval's on-screen position below it,
   which the flying-bag scroll trigger reads live every frame - stays
   pixel-identical no matter how big this renders. transform-origin is
   anchored to the bottom edge so the growth reads upward/outward rather
   than eating into the margin-bottom gap above the subtext. */
.celebrate-heading{
  font-size: clamp(2.88rem, 6.36vw, 4.18rem);
  line-height: 1.15;
  color: var(--red);
  text-transform: uppercase;
  margin-bottom: 18px;
  transform: scale(1.45);
  transform-origin: center bottom;
}
/* Row-by-row reveal: each line fades + slides up on its own, staggered via
   the transition-delay set inline on each row - reuses the site's generic
   .reveal-on-view mechanism (see common.js), just applied per line here. */
.celebrate-row{ display: block; }
.celebrate-subtext{
  max-width: 560px;
  margin: 0 auto 40px;
  font-weight: 600;
  font-size: 1.22rem;
  line-height: 1.5;
  color: var(--green-dark);
}
/* Invisible now on purpose: this is only a sizing/position anchor for the
   flying bag's landing math and the falling-snacks overlay. The bag itself
   (scaled to exactly match this box) is the only visible "bowl" - so
   there's a single shape here, not two overlapping ones. */
.landing-oval{
  position: relative;
  width: min(85%, 1700px);
  height: clamp(500px, 70vw, 750px);
  margin: 0 auto;
}

/* All snack chips share this single anchor point, dead center of the
   landing-oval, instead of resting side by side in a row - each one flies
   in from off-screen, holds briefly, then shrinks and fades away right on
   this spot, so it reads as tumbling into the basket and disappearing
   rather than accumulating next to it. This is a plain, static position
   relative to the oval (no JS/scroll math involved) - deliberately simple
   so it can't drift out of sync the way a computed position could. */
.falling-snacks{
  position: absolute;
  left: 50%;
  top: 40%;
  z-index: 65; /* only matters within .celebrate-pin's own stacking context -
    whether this whole subtree paints in front of or behind the hero plate
    is governed by .celebrate-pin's own z-index (55, deliberately below the
    plate's 60) so the snacks land behind the bag, not on top of it */
  pointer-events: none;
}
.falling-snack-chip{
  position: absolute;
  left: 0;
  top: 0;
  width: 720px;
  height: 720px;
  opacity: 0;
  will-change: transform, opacity;
}
.falling-snack-chip .fsc-photo{
  display: block;
  width: 100%; height: 100%;
  object-fit: contain;
}

/* ===================== MARKET STALLS -> HOMEMADE KITCHENS: 4 STAMP CARDS =====================
   A pinned scroll sequence, like the celebration section: four postage-stamp
   cards reveal one after another in a horizontal row as the user scrolls. */
.stamps-teaser{ background: var(--cream) url("images/flower background orange.png") no-repeat center / 100% 100%; position: relative; }
.stamps-scroll-wrap{ position: relative; }
.stamps-pin{
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  overflow: hidden;
}
.stamps-teaser-inner{ position: relative; width: 100%; }
/* Sits centered behind where the two cards land, and fades out (driven by
   updateStamps() in home.js) as they pull in, rather than staying visible
   underneath/behind them once they've arrived. */
.stamps-lead-text{
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  z-index: 0;
  text-align: center;
  color: var(--red);
  text-transform: uppercase;
  line-height: 1.15;
  font-size: clamp(2.2rem, 6vw, 4rem);
  pointer-events: none;
}
.stamps-lead-row{ display: block; }
.stamps-row{
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: center;
  align-items: stretch;
  gap: 28px;
  flex-wrap: nowrap;
}
.stamp-card{
  position: relative;
  width: 460px;
  height: 500px;
  flex-shrink: 0;
  background: url("images/yellow batik stamp cropped.png") center / 100% 100% no-repeat;
  opacity: 0;
  will-change: transform, opacity;
}

.stamp-card-text{
  padding: 52px 46px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.stamp-card-text .stamp-number{
  font-family: var(--ff-display);
  font-weight: 800;
  font-size: 3.6rem;
  color: var(--green-dark);
  margin-bottom: 6px;
}
.stamp-card-text h2{ font-size: 2.2rem; line-height: 1.15; color: var(--ink); margin-bottom: 22px; }
.stamp-card-text p{ color: var(--ink-soft); line-height: 1.7; margin-bottom: 28px; font-size: 1.02rem; }
.stamp-card-text .btn{ align-self: center; }

/* ===================== SNACKS: CULTURE + HORIZONTAL SCROLL ===================== */
.snacks{ position: relative; background-color: #FFC0B6; }
.snacks-scroll-wrap{ height: 220vh; position: relative; }
.snacks-pin{
  position: sticky;
  top:0;
  height: 100vh;
  overflow: hidden;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  background-image: url("images/pink framed background ext.png");
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

/* Phrase-by-phrase reveal: each word/icon chunk below fades and slides up
   from the bottom, one after another (driven from home.js), and stays put
   once revealed, so the full sentence is assembled by the end of the scroll. */
.snacks-phrase{
  max-width: 1200px;
  padding: 0 32px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0 clamp(0.9rem, 2.6vw, 1.9rem);
}
.phrase-item{
  opacity: 0;
  will-change: transform, opacity;
  font-family: 'Oswald', var(--ff-body);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  font-size: clamp(2.4rem, 8vw, 5.6rem);
  line-height: 1.2;
  color: #C50000;
}
.phrase-item.phrase-icon{
  display: inline-flex;
  align-items: center;
}
.phrase-item.phrase-icon img{
  width: clamp(2.4rem, 6vw, 4.4rem);
  height: clamp(2.4rem, 6vw, 4.4rem);
  object-fit: contain;
}

/* ===================== CELEBRATE / CTA ===================== */
.celebrate{ position:relative; overflow:hidden; background: var(--cream); padding: 80px 0; }
/* Invisible at rest - scaled and faded in from home.js as the section
   scrolls into view, so it visibly grows rather than just appearing. */
.celebrate-circle{
  position: absolute;
  left: 50%; top: 50%;
  width: min(52vw, 700px);
  aspect-ratio: 1 / 1;
  background: #FCD443 url("images/yellow batik.png") repeat;
  background-size: 420px 420px;
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0.15);
  opacity: 0;
  z-index: 0;
  will-change: transform, opacity;
}
.celebrate-inner{ position: relative; z-index: 2; display:flex; justify-content:center; }
.celebrate-card{ text-align:center; max-width: 680px; padding: 20px; }
.celebrate-cta-heading{
  font-size: clamp(3.2rem, 7.6vw, 5.8rem);
  line-height: 1.1;
  text-transform: uppercase;
  color: var(--red);
  margin-bottom: 18px;
}
.celebrate-row--sub{
  display: block;
  text-transform: none;
  color: var(--green-dark);
  font-size: clamp(1.9rem, 4vw, 2.7rem);
  margin-top: 6px;
}
.celebrate-cta-text{ color: var(--ink-soft); font-size: clamp(1.05rem, 1.8vw, 1.3rem); line-height:1.7; margin-bottom: 26px; }

/* ===================== FOOTER: NAV + APP + WORDMARK =====================
   Dark-green footer with a couple of the floral line-art motifs scattered
   as a faint background texture (inverted + low-opacity so the dark
   linework reads as a pale flourish against the green, rather than
   invisible dark-on-dark). App Store/Google Play badges are plain text
   pills for now - swap .footer-v2-badge's contents for real badge images
   once available, rather than recreating Apple/Google's trademarked badge
   artwork from scratch. */
.footer-v2{
  position: relative;
  background: var(--green-dark);
  overflow: hidden;
  padding: 90px 32px 36px;
}
.footer-v2-motif{
  position: absolute;
  width: 380px;
  opacity: 0.16;
  filter: invert(1);
  pointer-events: none;
  user-select: none;
}
.footer-v2-motif-a{ top: -70px; left: -80px; }
.footer-v2-motif-b{ top: -90px; right: -90px; transform: scaleX(-1); }

.footer-v2-inner{ position: relative; z-index: 2; max-width: 1200px; margin: 0 auto; }
.footer-v2-top{
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 32px;
  margin-bottom: 92px;
}
.footer-v2-heading{
  font-family: var(--ff-display);
  font-weight: 800;
  color: var(--gold);
  font-size: 1.25rem;
  margin: 0 0 10px;
}
.footer-v2-links{ display: flex; flex-direction: column; gap: 5px; }
.footer-v2-links a{ color: var(--cream-soft); font-weight: 600; font-size: 0.92rem; }
.footer-v2-links a:hover{ text-decoration: underline; }

.footer-v2-app{ text-align: right; }
.footer-v2-app-heading{
  font-family: var(--ff-display);
  font-weight: 800;
  color: var(--gold);
  font-size: 1.05rem;
  line-height: 1.4;
  margin: 0 0 14px;
}
.footer-v2-badges{ display: flex; gap: 10px; justify-content: flex-end; }
.footer-v2-badge{
  display: inline-flex;
  align-items: center;
  padding: 9px 18px;
  border-radius: 8px;
  background: var(--ink);
  color: var(--cream-soft);
  font-size: 0.78rem;
  font-weight: 700;
}

.footer-v2-wordmark{
  display: block;
  font-family: var(--ff-display);
  font-weight: 800;
  font-size: clamp(3rem, 9vw, 6rem);
  line-height: 1;
  color: var(--cream-soft);
}
.footer-v2-wordmark span{ color: var(--gold); }

.footer-v2 .footer-bottom{
  position: relative;
  z-index: 2;
  text-align: left;
  font-size: 0.78rem;
  color: var(--cream-soft);
  opacity: 0.7;
  padding-top: 20px;
}

@media (max-width: 700px){
  .footer-v2-top{ flex-direction: column; }
  .footer-v2-app{ text-align: left; }
  .footer-v2-badges{ justify-content: flex-start; }
  .footer-v2-motif{ width: 260px; }
}

/* ===================== FLOATING BUTTONS ===================== */
.back-to-top{
  position: fixed;
  bottom: 28px; right: 28px;
  width: 48px; height: 48px;
  border-radius:50%;
  border: none;
  background: var(--ink);
  color: var(--cream-soft);
  font-size: 1.1rem;
  display:flex; align-items:center; justify-content:center;
  opacity:0; visibility:hidden;
  transform: translateY(10px);
  transition: opacity .3s ease, transform .3s ease, visibility .3s ease, background .3s ease;
  z-index: 900;
}
.back-to-top.show{ opacity:1; visibility:visible; transform:translateY(0); }
.back-to-top:hover{ background: var(--red); }

/* ===================== SHARED SUBPAGE HERO ===================== */
.page-hero{ background: var(--cream) url("images/flower background orange.png") no-repeat center / 100% 100%; }
.page-hero .section-inner{ text-align: center; padding-bottom: 20px; max-width: 1100px; }
.page-hero h1{ font-size: clamp(4.6rem, 12vw, 9.6rem); color: var(--red); text-transform: uppercase; margin-bottom: 18px; }
.page-hero-subtext{
  color: var(--green-dark);
  font-weight: 800;
  font-size: clamp(1.4rem, 2.6vw, 2.1rem);
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.sotd-meta{ display: flex; align-items: center; gap: 12px; margin-bottom: 26px; }

/* The featured snack's photo, as a plate resting at the base of the
   two-tone landing hero; falls back to a plain color swatch when a snack
   has no photo of its own. */
.photo-frame-img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: 50%;
}
.photo-frame-img[hidden]{ display: none; }
.photo-frame-fill{
  width: 100%;
  height: 100%;
  border-radius: 50%;
}

/* ===================== RECOMMENDED: PHOTO HERO BANNER ===================== */
.catalog-hero{
  position: relative;
  height: 320px;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.catalog-hero-photos{ position: absolute; inset: 0; display: flex; }
.catalog-hero-photos img{ width: 34%; height: 100%; object-fit: cover; flex: 1; filter: saturate(1.05); }
.catalog-hero-overlay{
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(30,20,10,0.35), rgba(30,20,10,0.65));
}
.catalog-hero-text{ position: relative; z-index: 2; text-align: center; color: var(--cream-soft); padding: 0 24px; }
.catalog-hero-text .eyebrow{ color: var(--gold); }
.catalog-hero-text h1{ font-style: italic; font-size: clamp(2.4rem, 6vw, 4rem); margin-bottom: 12px; }
.catalog-hero-text p{ color: rgba(253,246,230,0.9); font-size: 1.05rem; max-width: 480px; margin: 0 auto; }

/* ===================== RECOMMENDED: SIDEBAR FILTERS + CATALOG GRID ===================== */
.catalog{ background: var(--cream); }
/* .section-inner and .catalog-layout both live on this same element, and
   this two-class selector otherwise wins over a plain .catalog-layout rule
   regardless of source order - so the real gap has to be set here. */
.catalog .section-inner{ padding-top: 190px; }
.catalog-layout{
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 40px;
  align-items: start;
}
.filter-sidebar{
  background: var(--paper);
  border: 2px solid var(--gold);
  border-radius: var(--radius-md);
  padding: 26px 24px;
  position: sticky;
  top: 100px;
}
.filter-sidebar h3{ font-size: 1.15rem; color: var(--green-dark); margin-bottom: 18px; }
.filter-group{ margin-bottom: 22px; }
.filter-group-label{ font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-soft); opacity: 0.75; margin-bottom: 10px; }
.filter-check{
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 0;
  cursor: pointer;
  font-size: 0.92rem;
  color: var(--ink);
}
.filter-check input{ accent-color: var(--green); width: 16px; height: 16px; }
.filter-clear{
  border: none;
  background: none;
  color: var(--red);
  font-weight: 700;
  font-size: 0.84rem;
  padding: 4px 0;
}
.filter-clear:hover{ text-decoration: underline; }

.catalog-grid{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 24px;
}
.catalog-card{
  background: var(--paper);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow);
  transition: transform .3s ease, box-shadow .3s ease, opacity .3s ease;
}
.catalog-card:hover{ transform: translateY(-6px); box-shadow: 0 26px 50px -18px rgba(43,29,18,0.35); }
.catalog-card.hidden{ display: none; }
.catalog-swatch{ height: 120px; position: relative; }
.swatch-a{ background: linear-gradient(140deg, #6fae5a, #3f7d34); }
.swatch-b{ background: linear-gradient(140deg, #e7b568, #c98a2f); }
.swatch-c{ background: linear-gradient(140deg, #f0d18f, #d9a441); }
.swatch-d{ background: linear-gradient(140deg, #e8c877, #b98936); }
.swatch-e{ background: linear-gradient(140deg, #ecc888, #c2872f); }
.swatch-f{ background: linear-gradient(140deg, #e0a94f, #a56423); }
.catalog-body{ padding: 20px; }
.catalog-top{ display: flex; justify-content: space-between; align-items: baseline; gap: 10px; margin-bottom: 2px; }
.catalog-top h3{ font-size: 1.05rem; }
.catalog-top h3 a:hover{ color: var(--green-dark); text-decoration: underline; }
.catalog-region{ font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-soft); opacity: 0.7; margin-bottom: 10px; }
.catalog-desc{ color: var(--ink-soft); font-size: 0.9rem; line-height: 1.55; margin-bottom: 12px; }
.catalog-recipe-link{ display: inline-block; font-size: 0.82rem; font-weight: 700; color: var(--red); }
.catalog-recipe-link:hover{ text-decoration: underline; }
.catalog-empty{ text-align: center; color: var(--ink-soft); padding: 40px 0; }

.fav-heart{
  position: absolute;
  top: 10px; right: 10px;
  width: 32px; height: 32px;
  border-radius: 50%;
  border: none;
  background: rgba(255,255,255,0.85);
  color: rgba(43,29,18,0.35);
  font-size: 1.05rem;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: color .2s ease, transform .2s ease;
}
.fav-heart:hover{ transform: scale(1.12); }
.fav-heart.active{ color: var(--red); }

.tag{
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: 999px;
  white-space: nowrap;
}
.tag.mild{ background: rgba(47,107,79,0.12); color: var(--green); }
.tag.savory{ background: rgba(217,154,44,0.18); color: var(--gold-dark); }
.tag.spicy{ background: rgba(193,80,46,0.12); color: var(--red); }

/* ===================== EXPLORE: ZOOMABLE MAP ===================== */
.map-section{ background: var(--cream); }
.map-section .section-inner{ padding-top: 0; padding-bottom: 40px; max-width: 1400px; }
.map-layout{ display: grid; grid-template-columns: 1fr; }

/* Real pre-made stamp-frame asset (1449x775) with its own scalloped edge
   and light-blue "ocean" panel baked in, rather than a CSS-generated mat -
   the shared #stampScallop clip path distorts badly at this wide an aspect
   ratio (see map-viewport comment below), so a purpose-built image sidesteps
   that entirely. .map-wrap is inset by the exact percentages of the image's
   own blue panel (measured directly from the asset) so the live map lines
   up with the printed frame regardless of rendered size. */
.map-postcard-wrap{
  position: relative;
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  aspect-ratio: 1449 / 775;
  background: url("images/map frame.png") center / 100% 100% no-repeat;
  filter: drop-shadow(0 20px 45px rgba(43,29,18,0.35));
}
.map-wrap{
  position: absolute;
  top: 9.68%;
  bottom: 10.58%;
  left: 4.97%;
  right: 6.62%;
  z-index: 2;
}

.map-frame{
  position: relative;
  width: 100%;
  height: 100%;
  background: #dbf4fc;
  overflow: hidden;
  cursor: grab;
  touch-action: none;
}
.map-frame.grabbing{ cursor: grabbing; }

/* Static (never panned/zoomed) wrapper around the map's content layers
   (the island SVG + the markers), so a left/right fade can stay anchored
   to the frame's actual visible edges - masking .map-zoom-group directly
   wouldn't work, since that element itself gets panned/scaled, which
   would drag the fade's position along with it instead of keeping it
   pinned to the frame edges. UI overlays (marker cards, zoom controls)
   live outside this wrapper so they're never faded. */
.map-viewport{
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 6%, black 94%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, black 6%, black 94%, transparent 100%);
}
.map-zoom-group{
  position: absolute;
  inset: 0;
  transform-origin: 0 0;
  will-change: transform;
}
.map-zoom-group svg{ display: block; width: 100%; height: 100%; }
.map-zoom-group svg g{ fill: var(--green); transition: fill .2s ease; }

.map-zoom-controls{
  position: absolute;
  bottom: 16px;
  right: 16px;
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: opacity .2s ease;
}
/* The detail card is right-anchored and vertically centered, so it can
   overlap this corner when open - hide the controls rather than let a
   z-index fight put unusable buttons under (or jarringly over) the card.
   The pins/labels are hidden too - they live in map space, not the card's,
   so whichever ones fall near the card would otherwise show through or
   overlap its text instead of staying neatly inside the stamp. */
.map-frame:has(.map-detail-card.open) .map-zoom-controls,
.map-frame:has(.map-detail-card.open) .map-markers{
  opacity: 0;
  pointer-events: none;
}
.map-zoom-btn{
  width: 42px; height: 42px;
  border-radius: 50%;
  border: none;
  background: var(--gold);
  color: var(--ink);
  font-family: var(--ff-display);
  font-size: 1.3rem;
  font-weight: 800;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 12px 24px -10px rgba(217,154,44,0.55);
  cursor: pointer;
  transition: background .2s ease, transform .2s ease, box-shadow .2s ease;
}
.map-zoom-btn:hover{ background: var(--gold-dark); transform: translateY(-3px); box-shadow: 0 18px 30px -10px rgba(217,154,44,0.65); }
.map-zoom-reset{
  width: auto;
  height: 36px;
  padding: 0 16px;
  border-radius: 999px;
  font-size: 0.66rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.map-hint{
  text-align: center;
  font-size: 0.78rem;
  color: var(--green-dark);
  opacity: 0.7;
  margin-top: 14px;
  letter-spacing: 0.02em;
}

/* Region pins: positioned via left/top in JS (kept outside the zoomed/panned
   group so they stay a constant screen size regardless of map zoom), more
   of them fading in as the zoom level rises. */
.map-markers{
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
}
.map-marker{
  position: absolute;
  width: 22px; height: 22px;
  margin: -11px 0 0 -11px;
  background: url("images/symbol (3).png") no-repeat center / contain;
  border: none;
  padding: 0;
  cursor: pointer;
  pointer-events: auto;
  transform: scale(1);
  opacity: 1;
  filter: drop-shadow(0 2px 4px rgba(43,29,18,0.4));
  transition: transform .3s cubic-bezier(.2,.8,.2,1), opacity .3s ease, filter .2s ease;
}
.map-marker:hover,
.map-marker:focus-visible{ transform: scale(1.3); filter: drop-shadow(0 3px 7px rgba(43,29,18,0.5)); }
.map-marker.tier-hidden{
  transform: scale(0);
  opacity: 0;
  pointer-events: none;
}
.map-marker--tier1{
  width: 40px; height: 40px;
  margin: -20px 0 0 -20px;
  background: var(--red);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 3px 8px rgba(43,29,18,0.45);
}
.map-marker--tier1:hover,
.map-marker--tier1:focus-visible{ filter: none; }
.map-marker-count{
  font-family: 'Oswald', var(--ff-display);
  font-weight: 700;
  font-size: 1.05rem;
  color: #fff;
  pointer-events: none;
}
.map-marker--tier2{
  width: 34px; height: 34px;
  margin: -17px 0 0 -17px;
}

.map-marker-card{
  position: absolute;
  z-index: 7;
  width: 220px;
  padding: 16px 18px;
  background: var(--paper);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow);
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px);
  transition: opacity .2s ease, transform .2s ease, visibility .2s ease;
}
.map-marker-card.open{ opacity: 1; visibility: visible; transform: translateY(0); }
.map-marker-card-close{
  position: absolute;
  top: 8px; right: 10px;
  width: 22px; height: 22px;
  border: none;
  background: none;
  font-size: 1.1rem;
  line-height: 1;
  color: var(--ink-soft);
  cursor: pointer;
}
.map-marker-card-close:hover{ color: var(--red); }
.map-marker-card-photo{
  width: 100%;
  aspect-ratio: 1;
  border-radius: calc(var(--radius-md) - 4px);
  margin-bottom: 10px;
  overflow: hidden;
}
.map-marker-card-photo[hidden]{ display: none; }
.map-marker-card-photo img{ width: 100%; height: 100%; object-fit: cover; display: block; }
.map-marker-card-name{
  font-family: var(--ff-display);
  font-weight: 800;
  color: var(--green-dark);
  font-size: 1rem;
  margin: 0 20px 6px 0;
}
.map-marker-card-blurb{ color: var(--ink-soft); font-size: 0.85rem; line-height: 1.5; margin-bottom: 10px; }
.map-marker-card-snack{ color: var(--ink); font-size: 0.8rem; line-height: 1.5; }
.map-marker-card-snack b{ color: var(--red); }
.map-marker-card-snack.has-link{ cursor: pointer; }
.map-marker-card-cta{
  display: block;
  margin-top: 8px;
  color: var(--red);
  font-weight: 700;
  font-size: 0.76rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.map-marker-card-snack.has-link:hover .map-marker-card-cta{ text-decoration: underline; }

/* ===================== MAP: REGIONAL PIN PREVIEW CARD =====================
   The .is-pin variant used for tier-2/3 (specific-snack) markers: a rounded
   "map pin" callout - white body with a triangular tail pointing down at
   the marker - showing just the snack's photo, its name, and a small
   bouncing triangle hinting the pin is interactive. Tier-1 (island) cards
   stay the plain rectangular text card above. */
.map-marker-card.is-pin{
  width: 190px;
  padding: 20px 18px 26px;
  border-radius: 32px;
  text-align: center;
  overflow: visible;
  cursor: default;
}
.map-marker-card.is-pin.has-link{ cursor: pointer; }
.map-marker-card.is-pin::after{
  content: "";
  position: absolute;
  left: 50%;
  bottom: -20px;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 20px solid transparent;
  border-right: 20px solid transparent;
  border-top: 22px solid var(--paper);
}
.map-marker-card.is-pin .map-marker-card-close{ display: none; }
.map-marker-card.is-pin .map-marker-card-photo{
  width: 74%;
  margin: 0 auto 16px;
  border-radius: 50%;
  box-shadow: var(--shadow);
}
.map-marker-card.is-pin .map-marker-card-name{
  font-family: 'Oswald', var(--ff-display);
  font-weight: 700;
  text-transform: uppercase;
  color: var(--red);
  font-size: 1.15rem;
  margin: 0;
}
.map-marker-card-indicator{ display: none; }
.map-marker-card.is-pin .map-marker-card-indicator{
  display: block;
  width: 0;
  height: 0;
  margin: 8px auto 0;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-top: 8px solid var(--red);
  animation: mapPinIndicatorBounce 1.1s ease-in-out infinite;
}
@keyframes mapPinIndicatorBounce{
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(5px); }
}

/* ===================== EXPLORE: MAP DETAIL CARD (right side, on click) =====================
   A bigger companion to the small pin-preview card above: appears fixed to
   the right side of the map on click (not hover), fading + easing in,
   showing the same photo/name but with room for a longer description.
   Persists until explicitly closed (X button, clicking elsewhere on the
   map, or panning/zooming) rather than dismissing on mouseleave like the
   small pin card does. */
.map-detail-card{
  position: absolute;
  right: clamp(20px, 4vw, 60px);
  top: 50%;
  z-index: 8;
  /* Capped so the card's own height (aspect-ratio-driven) stays comfortably
     inside .map-frame's ocean height - it used to be taller than the frame
     itself, which meant the frame's overflow:hidden silently clipped off
     the top (including the close button) and bottom of every open card. */
  width: min(300px, 27vw);
  aspect-ratio: 815 / 1122;
  padding: 30px 32px 34px;
  box-shadow: var(--shadow);
  text-align: center;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(-50%) translateY(16px);
  transition: opacity .4s ease, transform .4s ease, visibility .4s ease;
}
/* Only this inner wrapper scrolls for unusually long descriptions - keeping
   overflow off the card itself means the close button, the ::before stamp
   graphic, and the pointer indicator below (all of which deliberately sit
   at or past the card's own edges) never get clipped or trigger a stray
   scrollbar just because the indicator pokes out past the bottom. */
.map-detail-card-scroll{
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
}
/* The stamp asset is landscape (1122x815) - turned on its side here (same
   rotate-90deg trick as the Recipe/History cards) so the full scalloped
   edge shows on every side instead of "cover" cropping the left/right
   scallops off to fit this much-taller-than-wide card. 137.67% = 1122/815
   (pre-rotation width, relative to the card's own width); 72.64% =
   815/1122 (pre-rotation height) - reciprocals of the target ratio. */
.map-detail-card::before{
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 137.67%;
  height: 72.64%;
  background: url("images/longer batik stamp (2).png") center / 100% 100% no-repeat;
  transform: translate(-50%, -50%) rotate(90deg);
  z-index: -1;
}
.map-detail-card.open{
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: translateY(-50%) translateY(0);
}
.map-detail-card.has-link{ cursor: pointer; }
.map-detail-card-close{
  position: absolute;
  top: 16px; right: 18px;
  width: 26px; height: 26px;
  border: none;
  background: none;
  font-size: 1.3rem;
  line-height: 1;
  color: rgba(43,29,18,0.5);
  cursor: pointer;
}
.map-detail-card-close:hover{ color: var(--ink); }
.map-detail-card-photo{
  width: 68%;
  aspect-ratio: 1;
  margin: 0 auto 16px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--paper);
  box-shadow: var(--shadow);
}
.map-detail-card-photo img{ width: 100%; height: 100%; object-fit: cover; display: block; }
.map-detail-card-region{
  font-family: var(--ff-display);
  font-weight: 800;
  color: var(--ink);
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  text-align: right;
  margin: 0 0 4px;
}
.map-detail-card-name{
  font-family: 'Oswald', var(--ff-display);
  font-weight: 700;
  color: var(--red);
  text-transform: uppercase;
  font-size: clamp(1.7rem, 2.8vw, 2.3rem);
  line-height: 1.1;
  text-align: left;
  margin: 0 0 12px;
}
.map-detail-card-desc{
  color: var(--ink);
  font-size: 0.92rem;
  line-height: 1.55;
  text-align: left;
  margin: 0;
}
.map-detail-card-indicator{
  position: absolute;
  left: 50%;
  bottom: -10px;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  border-top: 10px solid var(--red);
  animation: mapPinIndicatorBounce 1.1s ease-in-out infinite;
}
@media (max-width: 700px){
  .map-detail-card{
    left: 16px;
    right: 16px;
    top: auto;
    bottom: 16px;
    width: auto;
    transform: translateY(20px);
  }
  .map-detail-card.open{ transform: translateY(0); }
}

/* ===================== EXPLORE: STATS STRIP ===================== */
.stats-section{ background: var(--green-dark); }
.stats-inner{
  padding-top: 64px;
  padding-bottom: 64px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 48px 64px;
}
.stat-item{ text-align: center; }
.stat-number{
  font-family: var(--ff-display);
  font-weight: 800;
  font-size: clamp(2.6rem, 6vw, 4rem);
  line-height: 1;
  color: var(--gold);
  margin-bottom: 8px;
}
.stat-label{
  font-size: 0.85rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--cream-soft);
}

/* ===================== EXPLORE: LOCAL MARKETS CAROUSEL ===================== */
.markets-section{ background: var(--cream) url("images/flower background orange.png") no-repeat center / 100% 100%; padding-bottom: 40px; }
.markets-heading{
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  margin-bottom: 44px;
}
.markets-word{
  font-size: clamp(4.6rem, 12vw, 9.6rem);
  line-height: 0.95;
  color: var(--red);
  text-transform: uppercase;
}
.markets-caption{
  color: var(--green-dark);
  font-weight: 800;
  font-size: clamp(1.1rem, 2vw, 1.5rem);
  line-height: 1.4;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
  margin-bottom: 4px;
}

.markets-carousel{
  display: flex;
  align-items: center;
  gap: 18px;
}
.markets-track{
  flex: 1;
  display: flex;
  gap: 26px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding: 6px 2px 14px;
  scrollbar-width: none;
}
.markets-track::-webkit-scrollbar{ display: none; }
.markets-frame{
  position: relative;
  flex: 0 0 calc((100% - 52px) / 3);
  scroll-snap-align: start;
  aspect-ratio: 700 / 760;
  background: url("images/pink stamp batik cropped.png") no-repeat center / 100% 100%;
  padding: clamp(18px, 4vw, 32px);
  overflow: hidden;
  transition: transform .35s cubic-bezier(.2,.8,.2,1), box-shadow .35s ease;
  will-change: transform;
}
.markets-frame:hover{
  transform: rotate(-2deg) scale(1.06);
  box-shadow: var(--shadow);
  z-index: 2;
}
.markets-frame img{
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.markets-frame-label{
  position: absolute;
  left: clamp(18px, 4vw, 32px);
  right: clamp(18px, 4vw, 32px);
  bottom: clamp(18px, 4vw, 32px);
  padding: 12px 10px 8px;
  background: linear-gradient(to top, rgba(0,0,0,0.72), transparent);
  color: #fff;
  font-family: var(--ff-display);
  font-weight: 700;
  font-size: 0.82rem;
  text-align: center;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .3s ease, transform .3s ease;
  pointer-events: none;
}
.markets-frame:hover .markets-frame-label{ opacity: 1; transform: translateY(0); }
.markets-arrow{
  flex-shrink: 0;
  width: 36px; height: 36px;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--pink-dark);
  font-size: 1rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform .2s ease, color .2s ease;
}
.markets-arrow:hover{ color: var(--red); transform: scale(1.15); }

@media (max-width: 700px){
  .markets-heading{ margin-bottom: 28px; }
  .markets-caption{ white-space: normal; }
  .markets-frame{ flex-basis: 70vw; }
}

/* ===================== SNACK DETAIL PAGE ===================== */
/* Floating back button on the snack detail page: since a snack page can be
   reached from either Recommendations or the Explore map, a plain browser
   back button isn't reliable - this gives both destinations explicitly. */
.snack-back{
  position: fixed;
  top: calc(var(--header-h) + 20px);
  left: clamp(20px, 4vw, 40px);
  z-index: 500;
}
.snack-back-btn{
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: none;
  background: #FFC5C0;
  color: #ffffff;
  cursor: pointer;
  box-shadow: 0 10px 22px -10px rgba(43,29,18,0.4);
  transition: background .25s ease, transform .25s ease;
}
.snack-back-btn:hover{ transform: scale(1.06); }
.snack-back.open .snack-back-btn{ background: #2b1d12; }
.snack-back-btn svg{ flex-shrink: 0; }
.snack-back-menu{
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: 200px;
  background: #fff;
  border-radius: 16px;
  padding: 8px;
  box-shadow: 0 8px 24px rgba(43,29,18,0.22);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity .2s ease, transform .2s ease, visibility .2s ease;
}
.snack-back.open .snack-back-menu{ opacity: 1; visibility: visible; transform: translateY(0); }
.snack-back-option{
  display: block;
  padding: 10px 14px;
  border-radius: 10px;
  color: var(--ink);
  font-family: var(--ff-body);
  font-weight: 600;
  font-size: 0.92rem;
  text-decoration: none;
  transition: background .15s ease, color .15s ease;
}
.snack-back-option:hover{ background: var(--cream); color: var(--red); }

.snack-hero{ background: var(--cream); padding-top: 0; }

/* The landing area: a two-tone (cream/gold) split behind the region label
   and the big bold title, with the snack's photo resting as a plate at
   the base. */
.snack-landing{
  position: relative;
  overflow: hidden;
  min-height: 100vh;
  display: flex;
  align-items: flex-start;
}
.snack-landing-pattern{
  position: absolute;
  inset: 0;
  background: url("images/flower motif 1.png") repeat;
  background-size: 560px 560px;
  opacity: 0.1;
  pointer-events: none;
}
.snack-landing-inner{
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  width: 100%;
  padding-top: 170px;
  padding-bottom: clamp(140px, 20vw, 220px);
}
.snack-landing-region{
  align-self: flex-end;
  margin: 0 8% 6px 0;
  color: var(--pink-dark);
  font-weight: 800;
  font-size: clamp(1.4rem, 2.6vw, 2.1rem);
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.snack-landing-title{
  align-self: center;
  margin: 0;
  max-width: 90%;
  text-align: center;
  font-size: clamp(4.6rem, 12vw, 9.6rem);
  line-height: 0.95;
  color: var(--red);
  text-transform: uppercase;
}
/* Invisible now on purpose: this is only a sizing/position anchor for the
   flying photo's scroll-trigger math (see .snack-flying-photo below and
   the "HERO: FLYING PHOTO" block in snack.js) - the real visible plate
   photo lives in that separate fixed element instead. */
.snack-landing-plate{
  position: absolute;
  z-index: 3;
  left: 50%;
  --plate-size: clamp(480px, 70vw, 980px);
  bottom: calc(var(--plate-size) / -2);
  transform: translateX(-50%);
  width: var(--plate-size);
  aspect-ratio: 1;
  border-radius: 50%;
  visibility: hidden;
}

/* The snack photo itself: starts pinned over the hero anchor above, then as
   the user scrolls it detaches from the page's normal flow, shrinks, and
   eases into the small sticky photo reserved for it next to the History
   section's card stack (#historyPhoto) - same "detach, fly, land on a real
   target" trick as the homepage's flying bag (see home.js), just
   scroll-following on the way out instead of pinned, since this hero isn't
   scroll-jacked. Position/size are driven every frame from JS (see
   snack.js); only opacity (the landing crossfade with the real target)
   transitions in CSS. */
.snack-flying-photo{
  position: fixed;
  left: 0;
  top: 0;
  z-index: 45;
  border-radius: 50%;
  overflow: hidden;
  pointer-events: none;
  opacity: 1;
  transition: opacity .35s ease;
  will-change: transform, width, height, opacity;
}

/* Ingredients: "build-a-dish" scroll trigger. The wrapper's height is set in
   JS (proportional to how many ingredients there are); the inner content
   stays pinned to the viewport for that whole scroll distance while each
   ingredient flies into the bowl in turn. */
.ingredients-section{
  position: relative;
  background-image: linear-gradient(rgba(234,181,77,0.55), rgba(234,181,77,0.55)), url("images/yellow batik seamless.png");
  background-size: 100% 100%, 640px 640px;
}
.ingredients-pin{
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  overflow: hidden;
}
/* The heading lives inside the pinned viewport, directly above the
   list+bowl grid, rather than in its own scrolling section above - that
   way the gap between them is just this element's own margin-bottom, not
   dependent on where the sticky pin happens to be mid-scroll. */
.ingredients-pin-inner{ width: 100%; max-width: 1160px; margin: 0 auto; padding: 0 32px; }
.ingredients-layout{
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: 50px;
  align-items: center;
  width: 100%;
}
.ingredient-list{ display: flex; flex-direction: column; gap: 10px; }
.ingredient-item{
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 16px;
  border-radius: var(--radius-md);
  opacity: 0.35;
  transform: translateX(0);
  cursor: pointer;
  transition: opacity .3s ease, transform .3s ease, background .3s ease, box-shadow .3s ease;
}
.ingredient-item:hover{ background: rgba(43,29,18,0.05); }
.ingredient-item .ing-icon{
  font-size: 1.6rem;
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--paper);
  box-shadow: var(--shadow);
  display: flex;
  align-items: center;
  justify-content: center;
}
.ingredient-item .ing-name{ font-family: 'Oswald', var(--ff-display); font-weight: 700; color: var(--green-dark); display: block; font-size: 1.05rem; }
.ingredient-item .ing-note{ font-family: var(--ff-body); font-weight: 600; font-size: 0.84rem; color: var(--ink); }
.ingredient-item.active{ opacity: 1; background: var(--paper); box-shadow: var(--shadow); transform: translateX(8px); }
.ingredient-item.done:not(.active){ opacity: 0.6; }

.build-bowl-wrap{ display: flex; justify-content: center; align-items: center; }
.build-bowl{ position: relative; width: min(70vw, 340px); height: 230px; }
.bowl-rim{
  position: absolute; top: 0; left: -4%; right: -4%;
  height: 30px;
  border-radius: 50%;
  background: linear-gradient(180deg, #f7c2ba, var(--pink));
  border: none;
  z-index: 2;
}
.bowl-base{
  position: absolute; top: 14px; left: 0; right: 0; bottom: 0;
  border-radius: 0 0 140px 140px / 0 0 100px 100px;
  background: linear-gradient(180deg, var(--pink), var(--pink-dark));
  border: none;
  box-shadow: var(--shadow), inset 0 -14px 24px rgba(43,29,18,0.14);
}
.bowl-items{
  position: absolute; inset: 30px 14px 24px;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-end;
  justify-content: center;
  gap: 6px;
  z-index: 3;
}
.bowl-chip{
  width: 44px; height: 44px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.35rem;
  opacity: 0;
  will-change: transform, opacity;
  /* Only box-shadow/filter transition, not transform/opacity - those two
     are set inline every scroll frame by updateIngredients() in snack.js,
     and a transition on them would add lag to that scroll-linked motion. */
  transition: box-shadow .3s ease, filter .3s ease;
}
.bowl-chip.highlighted{
  box-shadow: 0 0 0 4px var(--gold), var(--shadow);
  filter: brightness(1.1);
}
.bowl-chip-img{ width: 100%; height: 100%; object-fit: cover; display: block; }
.bowl-chip-placeholder{ width: 55%; height: 55%; background: #000; }

/* ===================== SNACK: THE STORY ===================== */
.history-section{ background: var(--cream); position: relative; }

/* History: four stamp cards (What It Is / Colonial Origins / Local
   Adaptation / Flavor Profile) stacked with a slight tilt, front card
   first. The wrapper's height is set in JS (proportional to how many
   cards need to swipe away); the inner content stays pinned to the
   viewport for that scroll distance while the front card swipes off to
   reveal the one underneath - driven entirely by scroll position, not a
   drag/swipe gesture. */
.history-stack-wrap{ position: relative; }
.history-stack-pin{
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(28px, 5vw, 80px);
  overflow: hidden;
  padding: 0 40px;
}
/* Landscape layout, matching the reference mockup - uses the real
   pre-cut landscape stamp assets (1122x815) instead of the portrait one,
   so the aspect-ratio here matches those exactly and the 100%-100%
   background maps onto it 1:1 without stretching the scalloped edge. */
.history-stack{
  position: relative;
  width: min(630px, 54vw);
  aspect-ratio: 1122 / 815;
}
.history-card{
  position: absolute;
  inset: 0;
  background: url("images/longer batik stamp (2).png") no-repeat center / 100% 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 8% 11%;
  filter: drop-shadow(0 10px 18px rgba(43,29,18,0.14));
  will-change: transform, opacity;
}
/* A real pre-cut pink stamp asset, sharing the exact same scalloped
   silhouette as the yellow one above - no CSS masking or color-shifting
   filter needed now that both exist as proper cutouts. */
.history-card--pink{ background-image: url("images/longer batik stamp (1).png"); }
.history-card h3{
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.4em;
  row-gap: 0;
  font-size: clamp(2.7rem, 5.6vw, 4.1rem);
  line-height: 0.95;
  text-transform: uppercase;
  margin-bottom: 16px;
}
.history-card .hp-red,
.history-card .hp-black{ color: var(--red); }
.history-card p{ color: var(--ink); line-height: 1.55; font-size: clamp(1rem, 1.5vw, 1.15rem); max-width: 42ch; }
.history-card .flavor-bars--card{ width: 100%; max-width: 340px; gap: 13px; }
.history-card .flavor-bars--card .flavor-bar-label{ width: 72px; font-size: 0.98rem; }
.history-card .flavor-bars--card .flavor-bar-track{ height: 11px; }

/* The hero's flying snack photo (see "HERO: FLYING PHOTO" in snack.js)
   lands here, next to the card stack, rather than replacing it - starts
   invisible and stays hidden until the scroll trigger marks it "landed"
   (at the moment the flying copy reaches this same on-screen spot), so
   there's never a moment with both the flying and resting photo visible
   at once. Stays put on the right for the whole card-swiping scroll,
   since it lives inside the same sticky pin as the cards. */
.history-photo{
  flex-shrink: 0;
  width: min(38vw, 420px);
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  opacity: 0;
  transition: opacity .35s ease;
}
.history-photo img,
.history-photo .photo-frame-fill{ width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }

@media (max-width: 800px){
  .snack-flying-photo{ display: none; }
  .history-card{ padding: 9% 9%; }
  .history-card p{ font-size: 0.85rem; }
  .history-stack-pin{ flex-direction: column; gap: 24px; padding: 24px 20px; }
  .history-stack{ width: min(600px, 90vw); }
  .history-photo{ width: min(58vw, 280px); opacity: 1; }
}

/* ===================== SNACK: RECIPE =====================
   Every snack has a couple of real variants (classic vs. a regional or
   modern twist), fanned out as overlapping stamp cards (like a hand of
   cards) rather than picked from a separate list. Clicking any card
   raises it to the front so it's fully readable; the rest stay tucked in
   their resting fanned position behind it. The whole section pins in
   place and reserves extra scroll distance (see #recipeScrollWrap in
   snack.js) so the cards rise up from below and land with a bounce as you
   scroll, the same scroll-scrubbed mechanic as the homepage's Market/
   Kitchens stamp cards - just rising from the bottom instead of the
   sides. */
.recipe-section{ position: relative; background: var(--cream-soft); }
.recipe-pin{
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  overflow: hidden;
}
.recipe-pin-inner{ width: 100%; text-align: center; }
.recipe-fan{
  position: relative;
  max-width: 1560px;
  margin: 24px auto 24px;
  height: min(800px, 66vh);
  display: flex;
  align-items: flex-start;
  justify-content: center;
}
/* Each card uses one of three pre-made artwork frames (see
   RECIPE_CARD_ART in snack.js) - "01."/"03." come pre-tilted and "02."
   comes upright, number already baked into the art, each with its own
   real aspect ratio (set inline per-card from JS, since they're not all
   the same). Position/z-index for the fanned-out resting state and the
   "brought to front" active state are set inline from snack.js
   (renderRecipeCards()). The text itself lives in .recipe-card-inner, sized/
   positioned/rotated inline per card (also from RECIPE_CARD_ART) to land
   exactly on the white area actually printed on the artwork - measured
   from the PNGs themselves rather than approximated with plain padding,
   which is why the two tilted cards' text is rotated to match. */
.recipe-card{
  position: absolute;
  top: 20px;
  left: 50%;
  width: min(560px, 88vw, 49vh);
  margin-left: calc(min(560px, 88vw, 49vh) / -2);
  border: none;
  background-color: transparent;
  background-repeat: no-repeat;
  background-position: center;
  background-size: 100% 100%;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  font: inherit;
  transition: transform .4s cubic-bezier(.2,.8,.2,1);
}
.recipe-card-inner{
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 4%;
  overflow-x: hidden;
  overflow-y: auto;
}
/* --recipe-text-scale is set inline per-card from snack.js
   (fitRecipeCardText()), which shrinks it step by step until the card's
   title+steps fit without needing to scroll - every size below scales off
   this one variable rather than each other independently. */
.recipe-card{ --recipe-text-scale: 1; }
.recipe-card-title{
  font-family: var(--ff-display);
  font-style: italic;
  font-weight: 700;
  font-size: calc(1.05rem * var(--recipe-text-scale));
  color: var(--red);
  line-height: 1.2;
  margin-bottom: calc(12px * var(--recipe-text-scale));
  padding-bottom: calc(10px * var(--recipe-text-scale));
  border-bottom: 1px dashed rgba(43,29,18,0.2);
  width: 100%;
}
.recipe-card-steps{
  counter-reset: cardstep;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(9px * var(--recipe-text-scale));
}
.recipe-card-steps li{
  display: flex;
  gap: calc(10px * var(--recipe-text-scale));
  align-items: flex-start;
  width: 100%;
  max-width: 32ch;
  color: var(--ink-soft);
  font-size: calc(0.8rem * var(--recipe-text-scale));
  line-height: 1.4;
}
/* Without this, the step text is a bare (anonymous) flex item that
   defaults to shrinking toward its min-content width - the width of its
   single longest word - rather than filling the space next to the number
   circle, which is what was causing the text to wrap almost one word per
   line instead of using the card's actual available width. */
.recipe-card-steps li span{
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
}
.recipe-card-steps li::before{
  counter-increment: cardstep;
  content: counter(cardstep);
  flex-shrink: 0;
  width: calc(19px * var(--recipe-text-scale));
  height: calc(19px * var(--recipe-text-scale));
  border-radius: 50%;
  background: var(--wood-dark);
  color: var(--cream-soft);
  font-weight: 700;
  font-size: calc(0.64rem * var(--recipe-text-scale));
  font-family: var(--ff-display);
  display: flex;
  align-items: center;
  justify-content: center;
}
@media (max-width: 700px){
  .recipe-fan{ height: min(700px, 62vh); }
  .recipe-card{ width: min(420px, 90vw, 46vh); margin-left: calc(min(420px, 90vw, 46vh) / -2); }
}

/* ===================== SNACK: FLAVOR PROFILE =====================
   Flavor Profile is now the back-most card in the History stamp-card
   stack (see .history-card .flavor-bars--card above) rather than its own
   section - these bar-row rules are still shared by that card. */
.ingredients-heading{
  text-align: left;
  color: var(--red);
  text-transform: uppercase;
  font-size: clamp(2.6rem, 5vw, 3.8rem);
  margin-bottom: 36px;
}
.recipe-heading{
  text-align: center;
  color: var(--red);
  text-transform: uppercase;
  font-size: clamp(2.6rem, 5vw, 3.8rem);
  margin-bottom: 36px;
}
.flavor-bars{ display: flex; flex-direction: column; gap: 22px; }
.flavor-bar-row{ display: flex; align-items: center; gap: 20px; }
.flavor-bar-label{
  width: 84px;
  flex-shrink: 0;
  text-align: left;
  font-family: var(--ff-display);
  font-weight: 700;
  color: var(--wood-dark);
}
.flavor-bar-track{
  flex: 1;
  height: 14px;
  border-radius: 999px;
  background: var(--cream-soft);
  overflow: hidden;
}
.flavor-bar-fill{
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--wood-dark);
}

/* ===================== RESPONSIVE ===================== */
@media (max-width: 900px){
  .stamps-row{ flex-wrap: wrap; justify-content: center; gap: 20px; }
  .stamp-card{ width: min(84vw, 360px); height: 420px; }
  .stamp-card-text{ padding: 38px 32px; }
  .stamp-card-text h2{ font-size: 1.8rem; }
  .stamp-card-text p{ font-size: 0.94rem; }
  .catalog-layout{ grid-template-columns: 1fr; }
  .filter-sidebar{ position: static; }
  .margin-rule{ display: none; }
  .snack-landing{ min-height: unset; }
  .snack-landing-inner{ padding-top: 100px; padding-bottom: 220px; }
  .snack-landing-region{ align-self: center; margin: 0 0 6px; text-align: center; }
  .snack-landing-title{ padding-left: 24px; padding-right: 24px; max-width: 100%; font-size: clamp(2.4rem, 9vw, 3.6rem); text-align: center; }
  .snack-landing-plate{ --plate-size: min(85vw, 340px); }
  .ingredients-layout{ grid-template-columns: 1fr; }
  .build-bowl-wrap{ order: -1; margin-bottom: 24px; }
}

@media (max-width: 600px){
  .section-inner{ padding: 80px 22px; }
  .hero-scroll-wrap{ height: 112vh; }
  .snacks-scroll-wrap{ height: 200vh; }
  .plate{ width: 150px; height: 146px; }
  .celebrate-card{ padding: 40px 26px; }
  .catalog-hero{ height: 260px; }
  .catalog-hero-photos img{ width: 50%; }
  .catalog-hero-photos img:nth-child(3){ display: none; }
}

/* ===================== REDUCED MOTION ===================== */
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior: auto; }
  *{ animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
}
