/* ==========================================================================
   KSP — Krupam Spices Processors
   Design system, 2026 redesign.

   Hand-authored CSS on purpose: this site has no build step, so a utility
   framework would mean either a toolchain the client cannot run or a
   render-blocking CDN script on every page. Tokens below do the same job.

   Palette note: the old stylesheet's accent was #2f8fc6, a blue, while the
   logo is red and maroon (#c54341 / #a13028). Everything here is derived
   from the logo instead. Every text pair in use was measured against WCAG
   AA; the two that failed (a light warm grey, and turmeric as body text)
   are not used for body text anywhere.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Brand, taken from the logo */
  --brand:        #a13028;   /* 7.07:1 on white  — primary actions, links   */
  --brand-dark:   #6d1f19;   /* 11.29:1 on white — hover, deep panels       */
  --brand-light:  #c54341;   /* 4.94:1 with white text — accents only       */

  /* Warm neutrals. The old palette was a cold blue-white; spices are warm. */
  --ink:          #1c1614;   /* 17.30:1 on --bg */
  --ink-soft:     #3d332e;   /* 11.87:1 on --bg */
  --muted:        #6b615c;   /*  5.82:1 on --bg — the lightest text allowed */
  --bg:           #fdfbf7;
  --surface:      #ffffff;
  --sand:         #f6f0e6;
  --sand-deep:    #efe6d6;
  --line:         #e8dfd2;
  --line-strong:  #d8cab4;

  /* Supporting accents. Turmeric never carries body text: it measures
     4.06:1 on white, which fails AA. Large display and fills only. */
  --turmeric:      #b0700f;
  --turmeric-text: #8a5809;  /* 6.03:1 with white text */
  --green:         #1f6b3f;  /* 6.28:1 on --bg — "in stock", success */

  /* Type */
  /* 2026-09-12: the client saw "Arial". Inter reads as Arial to most eyes,
     and when Google Fonts failed to load the fallback literally was Arial.
     Plus Jakarta Sans has visible character at text sizes, and the fallback
     stack now has no Arial in it anywhere. */
  --font-sans: "Plus Jakarta Sans", "Segoe UI", "Trebuchet MS", system-ui, sans-serif;
  --font-display: "Fraunces", "Playfair Display", Georgia, "Times New Roman", serif;

  --step--1: clamp(0.82rem, 0.79rem + 0.12vw, 0.88rem);
  --step-0:  clamp(1rem, 0.97rem + 0.15vw, 1.06rem);
  --step-1:  clamp(1.15rem, 1.09rem + 0.3vw, 1.32rem);
  --step-2:  clamp(1.4rem, 1.28rem + 0.6vw, 1.75rem);
  --step-3:  clamp(1.75rem, 1.5rem + 1.2vw, 2.4rem);
  --step-4:  clamp(2.1rem, 1.6rem + 2.4vw, 3.4rem);
  --step-5:  clamp(2.6rem, 1.75rem + 4vw, 4.4rem);

  /* Spacing, 4px base */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;
  --sp-9: 96px; --sp-10: 128px;

  --radius-sm: 6px;
  --radius:    12px;
  --radius-lg: 20px;
  --radius-pill: 999px;

  --shadow-sm: 0 1px 2px rgba(45, 28, 20, 0.06);
  --shadow:    0 4px 16px rgba(45, 28, 20, 0.07);
  --shadow-lg: 0 18px 44px rgba(45, 28, 20, 0.12);

  --wrap: 1200px;
  --wrap-narrow: 780px;

  /* Layers */
  --z-base: 0;
  --z-raised: 10;
  --z-sticky: 20;
  --z-overlay: 40;
  --z-float: 100;
  --z-modal: 1000;

  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* --------------------------------------------------------------------------
   2. Reset and base
   -------------------------------------------------------------------------- */

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

html {
  scroll-behavior: smooth;
  /* Sticky header height, so anchor links don't land under it */
  scroll-padding-top: 92px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Jakarta sets a touch smaller and lighter than Inter did, so paragraph
   copy gets a hair more weight to keep the measured contrast honest. */
p, li, dd, address, .lede { font-weight: 450; }
strong, b { font-weight: 700; }

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }

a { color: inherit; text-decoration: none; }

button { font: inherit; color: inherit; }

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

h1 { font-size: var(--step-5); }
h2 { font-size: var(--step-4); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }

p { margin: 0 0 var(--sp-4); }
p:last-child { margin-bottom: 0; }

ul, ol { margin: 0; padding: 0; list-style: none; }

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

::selection { background: var(--brand); color: #fff; }

.hidden { display: none !important; }
/* The hidden ATTRIBUTE too: a display:flex rule on the same element would
   otherwise win over the browser's default and show it anyway. */
[hidden] { display: none !important; }

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

.skip-link {
  position: absolute;
  top: -60px;
  left: var(--sp-4);
  z-index: var(--z-modal);
  padding: var(--sp-3) var(--sp-5);
  background: var(--brand);
  color: #fff;
  font-weight: 600;
  border-radius: 0 0 var(--radius) var(--radius);
  transition: top 180ms var(--ease);
}
.skip-link:focus { top: 0; }

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */

.wrap {
  width: min(var(--wrap), 100% - var(--sp-6));
  margin-inline: auto;
}

@media (min-width: 768px) {
  .wrap { width: min(var(--wrap), 100% - var(--sp-8)); }
}

.section { padding-block: var(--sp-8); }

@media (min-width: 768px) {
  .section { padding-block: var(--sp-9); }
}

.section--sand { background: var(--sand); }
.section--tight { padding-block: var(--sp-7); }

.section-head {
  max-width: 62ch;
  margin-bottom: var(--sp-7);
}

.section-head--center {
  max-width: 58ch;
  margin-inline: auto;
  text-align: center;
}

.eyebrow {
  display: block;
  margin: 0 0 var(--sp-3);
  color: var(--brand);
  font-family: var(--font-sans);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.lede {
  max-width: 62ch;
  margin-top: var(--sp-4);
  color: var(--muted);
  font-size: var(--step-1);
  line-height: 1.6;
}

.rule {
  width: 56px;
  height: 3px;
  margin: var(--sp-5) 0 0;
  background: var(--brand);
  border-radius: var(--radius-pill);
}

.section-head--center .rule { margin-inline: auto; }

/* --------------------------------------------------------------------------
   4. Buttons
   app.js emits `class="btn primary"` on product cards and `class="btn"`
   (plus `.active`) on category filters, so those selectors must stay.
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 48px;             /* touch target */
  padding: var(--sp-3) var(--sp-6);
  border: 1.5px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-align: center;
  cursor: pointer;
  transition: background 180ms var(--ease), color 180ms var(--ease),
              border-color 180ms var(--ease), transform 180ms var(--ease),
              box-shadow 180ms var(--ease);
}

.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.btn:active { transform: translateY(0); }

.btn.primary {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}
.btn.primary:hover { background: var(--brand-dark); border-color: var(--brand-dark); }

.btn--outline {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--ink);
}
.btn--outline:hover { border-color: var(--brand); color: var(--brand); }

.btn--ghost {
  min-height: 44px;
  padding: var(--sp-2) 0;
  background: none;
  border: 0;
  border-bottom: 2px solid var(--brand);
  border-radius: 0;
  color: var(--brand);
}
.btn--ghost:hover { transform: none; box-shadow: none; color: var(--brand-dark); border-color: var(--brand-dark); }

.btn--lg { min-height: 56px; padding: var(--sp-4) var(--sp-7); font-size: var(--step-0); }

.btn .icon { width: 18px; height: 18px; flex: none; }

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-6);
}

/* --------------------------------------------------------------------------
   5. Header
   Rendered directly in the HTML rather than injected by JS, so it paints
   with the first frame instead of shifting the page after DOMContentLoaded.
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: rgba(253, 251, 247, 0.88);
  border-bottom: 1px solid var(--line);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  min-height: 76px;
  white-space: nowrap;   /* 2026-09-15: the full name + six links must stay one row */
}

.brand { display: flex; align-items: center; gap: var(--sp-3); }
.brand img { width: auto; height: 46px; }

.brand__text { display: none; }

@media (min-width: 1100px) {
  .brand__text {
    display: block;
    padding-left: var(--sp-3);
    border-left: 1px solid var(--line-strong);
    line-height: 1.2;
    white-space: normal;   /* the name breaks into two lines: Krupam Spices / Processors */
    max-width: 9.5rem;
  }
  .brand__text strong {
    display: block;
    font-family: var(--font-display);
    font-size: 14px;
    font-weight: 600;
  }
  .brand__text span {
    display: block;
    color: var(--muted);
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
  }
}

.nav { display: none; }

@media (min-width: 940px) {
  .nav {
    display: flex;
    align-items: center;
    gap: var(--sp-5);
  }
  .nav a {
    position: relative;
    padding: var(--sp-2) 0;
    color: var(--ink-soft);
    font-size: var(--step--1);
    font-weight: 500;
    letter-spacing: 0.02em;
    transition: color 160ms var(--ease);
  }
  .nav a::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    height: 2px;
    background: var(--brand);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 200ms var(--ease);
  }
  .nav a:hover { color: var(--brand); }
  .nav a:hover::after { transform: scaleX(1); }
}

.header__actions { display: flex; align-items: center; gap: var(--sp-3); }

.header__phone {
  display: none;
  align-items: center;
  gap: var(--sp-2);
  color: var(--ink);
  font-size: var(--step--1);
  font-weight: 600;
}
.header__phone:hover { color: var(--brand); }
.header__phone .icon { width: 18px; height: 18px; flex: none; color: var(--brand); }   /* 2026-09-16: "very small" -- the flex row was squeezing it to 8px wide; flex:none stops that */

@media (min-width: 1100px) { .header__phone { display: inline-flex; } }

.header__cta { display: none; }
@media (min-width: 940px) { .header__cta { display: inline-flex; } }

/* Mobile menu */
.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  background: transparent;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.nav-toggle .icon { width: 22px; height: 22px; }
.nav-toggle__close { display: none; }
.nav-toggle[aria-expanded="true"] .nav-toggle__open { display: none; }
.nav-toggle[aria-expanded="true"] .nav-toggle__close { display: block; }

@media (min-width: 940px) { .nav-toggle { display: none; } }

.mobile-nav {
  display: none;
  padding: var(--sp-4) 0 var(--sp-6);
  border-top: 1px solid var(--line);
}
.mobile-nav[data-open="true"] { display: block; }

@media (min-width: 940px) { .mobile-nav { display: none !important; } }

.mobile-nav a {
  display: block;
  padding: var(--sp-4) 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--step-1);
  font-weight: 500;
}
.mobile-nav a:last-of-type { border-bottom: 0; }
.mobile-nav .btn { width: 100%; margin-top: var(--sp-4); }

/* --------------------------------------------------------------------------
   6. Hero
   Split layout on a light ground rather than text over a dark photo, so the
   headline sits at 17:1 contrast instead of fighting an image.
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  overflow: hidden;
  padding-block: var(--sp-7) var(--sp-8);
  background:
    radial-gradient(70% 60% at 88% 12%, rgba(176, 112, 15, 0.09), transparent 70%),
    radial-gradient(55% 55% at 4% 92%, rgba(161, 48, 40, 0.07), transparent 70%),
    var(--bg);
}

@media (min-width: 900px) {
  .hero { padding-block: var(--sp-9); }
}

.hero__grid {
  display: grid;
  gap: var(--sp-7);
  align-items: center;
}

@media (min-width: 900px) {
  .hero__grid {
    grid-template-columns: 1.15fr 0.85fr;
    gap: var(--sp-8);
  }
}

.hero__title {
  margin-bottom: var(--sp-5);
  /* The em below is its own line, so leave the first line alone rather than
     letting `balance` break "Rakhe swaad ke saath" into a ragged stack. */
  font-size: clamp(2.4rem, 1.6rem + 2.9vw, 3.5rem);
  text-wrap: normal;
}

.hero__title em {
  display: block;
  color: var(--brand);
  font-style: normal;
}

.hero__sub {
  max-width: 46ch;
  color: var(--ink-soft);
  font-size: var(--step-1);
}

.hero__proof {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-7);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--line);
}

.hero__proof li {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--ink-soft);
  font-size: var(--step--1);
  font-weight: 500;
}

.hero__proof .icon { width: 18px; height: 18px; color: var(--brand); flex: none; }

/* Image side */
.hero__media { position: relative; }

.hero__media img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

@media (min-width: 900px) {
  .hero__media img { aspect-ratio: 5 / 6; }
}

.seal {
  position: absolute;
  right: calc(var(--sp-5) * -1);
  bottom: var(--sp-6);
  display: grid;
  place-content: center;
  gap: 2px;
  width: 132px;
  height: 132px;
  padding: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 50%;
  box-shadow: var(--shadow-lg);
  text-align: center;
}

@media (max-width: 560px) {
  .seal { right: var(--sp-3); width: 108px; height: 108px; }
}

.seal strong {
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 700;
  line-height: 1;
  color: var(--brand);
}

.seal span {
  color: var(--muted);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   7. The chooser — the three-way decision, directly under the hero
   -------------------------------------------------------------------------- */

.fork {
  display: grid;
  gap: var(--sp-5);
}

@media (min-width: 800px) {
  .fork { grid-template-columns: 1fr 1fr; gap: var(--sp-6); }
}

.fork__card {
  display: flex;
  flex-direction: column;
  padding: var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition: transform 220ms var(--ease), box-shadow 220ms var(--ease),
              border-color 220ms var(--ease);
}

@media (min-width: 800px) { .fork__card { padding: var(--sp-7); } }

.fork__card:hover {
  transform: translateY(-4px);
  border-color: var(--line-strong);
  box-shadow: var(--shadow-lg);
}

.fork__card--b2b {
  background: linear-gradient(160deg, var(--brand-dark), #4d1512);
  border-color: transparent;
  color: #fff;
}
.fork__card--b2b h3 { color: #fff; }
.fork__card--b2b .fork__tag { background: rgba(255, 255, 255, 0.16); color: #fff; }
.fork__card--b2b p { color: rgba(255, 255, 255, 0.82); }
.fork__card--b2b .fork__list li { color: rgba(255, 255, 255, 0.9); }
.fork__card--b2b .fork__list .icon { color: #e9b44c; }
.fork__card--b2b .btn.primary { background: #fff; border-color: #fff; color: var(--brand-dark); }
.fork__card--b2b .btn.primary:hover { background: var(--sand); border-color: var(--sand); }

.fork__tag {
  align-self: flex-start;
  padding: var(--sp-1) var(--sp-3);
  background: var(--sand-deep);
  border-radius: var(--radius-pill);
  color: var(--brand-dark);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.fork__card h3 { margin: var(--sp-4) 0 var(--sp-3); }

.fork__list {
  display: grid;
  gap: var(--sp-3);
  margin: var(--sp-5) 0 var(--sp-6);
}

.fork__list li {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  color: var(--ink-soft);
  font-size: var(--step--1);
}

.fork__list .icon {
  width: 18px; height: 18px;
  margin-top: 2px;
  color: var(--brand);
  flex: none;
}

.fork__card .actions { margin-top: auto; }

/* --------------------------------------------------------------------------
   8. Product catalogue
   Visible by default. The old build hid it behind a button, so a first-time
   visitor saw no product at all.
   -------------------------------------------------------------------------- */

.catalog__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-5);
  margin-bottom: var(--sp-6);
}

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-bottom: var(--sp-6);
}

.filters .btn {
  min-height: 44px;
  padding: var(--sp-2) var(--sp-5);
  background: var(--surface);
  border-color: var(--line);
  color: var(--ink-soft);
  font-weight: 500;
}
.filters .btn:hover { transform: none; border-color: var(--brand); color: var(--brand); box-shadow: none; }
.filters .btn.active {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  font-weight: 600;
}

.product-grid {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
}

.product-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: transform 220ms var(--ease), box-shadow 220ms var(--ease);
}

.product-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }

.product-card > img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: var(--sand);
}

.product-card .body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: var(--sp-2);
  padding: var(--sp-5);
}

.product-card .category {
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.product-card h3 { font-size: var(--step-1); }

.product-card .price {
  margin: 0;
  color: var(--brand);
  font-family: var(--font-sans);
  font-size: var(--step-1);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.product-card .body > p:not(.price) {
  margin: 0;
  color: var(--muted);
  font-size: var(--step--1);
}

.product-card .btn { margin-top: auto; width: 100%; }

.notice {
  margin: var(--sp-5) 0 0;
  padding: var(--sp-5);
  background: var(--sand);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
  color: var(--muted);
  font-size: var(--step--1);
  text-align: center;
}
.notice:empty { display: none; }

/* Skeletons, shown until Supabase answers */
.skeleton-grid {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
}

.skeleton {
  height: 320px;
  background: linear-gradient(100deg, var(--sand) 30%, var(--sand-deep) 50%, var(--sand) 70%);
  background-size: 220% 100%;
  border-radius: var(--radius);
  animation: shimmer 1.4s linear infinite;
}

@keyframes shimmer {
  from { background-position: 180% 0; }
  to   { background-position: -20% 0; }
}

/* --------------------------------------------------------------------------
   9. Story, and the KRUPAM meaning
   -------------------------------------------------------------------------- */

.story {
  display: grid;
  gap: var(--sp-7);
  align-items: center;
}

@media (min-width: 900px) {
  .story { grid-template-columns: 0.95fr 1.05fr; gap: var(--sp-8); }
  .story__media { order: -1; }
}

.story__media img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

/* Dadi: an illustration, not a photo. Parth, 2026-09-30: no background of any
   kind behind her, so no panel, glow or shadow; she sits on the page itself.
   Her drawing ends in a straight cut, so the last stretch fades out instead of
   stopping on a hard edge in mid-air. */
.story__media--dadi {
  display: flex;
  justify-content: center;
}

.story__media--dadi img {
  width: min(100%, 400px);
  height: auto;
  aspect-ratio: auto;
  object-fit: contain;
  border-radius: 0;
  box-shadow: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 84%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 84%, transparent 100%);
}

@media (max-width: 899px) {
  .story__media--dadi img { width: min(78%, 320px); }
}

.acronym {
  display: grid;
  gap: var(--sp-3);
  margin-top: var(--sp-6);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--line);
}

@media (min-width: 560px) {
  .acronym { grid-template-columns: 1fr 1fr; gap: var(--sp-3) var(--sp-6); }
}

.acronym li {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
}

.acronym b {
  width: 1.15em;
  color: var(--brand);
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 700;
  line-height: 1;
}

.acronym span { color: var(--ink-soft); font-size: var(--step--1); }

/* --------------------------------------------------------------------------
   10. Offers
   -------------------------------------------------------------------------- */

.offers {
  display: grid;
  gap: var(--sp-4);
  counter-reset: offer;
}

@media (min-width: 800px) { .offers { grid-template-columns: repeat(3, 1fr); } }

.offer-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

.offer-card::before {
  counter-increment: offer;
  content: counter(offer, decimal-leading-zero);
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-5);
  font-family: var(--font-display);
  font-size: 44px;
  font-weight: 700;
  line-height: 1;
  color: var(--sand-deep);
}

.offer-card__amount {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 700;
  color: var(--brand);
  font-variant-numeric: tabular-nums;
}

.offer-card p { color: var(--ink-soft); font-size: var(--step--1); }

.offers-note {
  margin-top: var(--sp-5);
  color: var(--muted);
  font-size: var(--step--1);
}

/* --------------------------------------------------------------------------
   11. Blog
   -------------------------------------------------------------------------- */

.blog-grid {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 290px), 1fr));
}

.blog-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: transform 220ms var(--ease), box-shadow 220ms var(--ease);
}

.blog-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }

.blog-card > img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background: var(--sand);
}

.blog-card > div {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-5);
}

.blog-card span {
  color: var(--brand);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.blog-card h3 { font-size: var(--step-1); }

.blog-card p {
  margin: 0;
  color: var(--muted);
  font-size: var(--step--1);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   12. Contact
   -------------------------------------------------------------------------- */

.contact-grid {
  display: grid;
  gap: var(--sp-5);
}

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

.contact-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.contact-card h3 {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--step-1);
}

.contact-card h3 .icon { width: 20px; height: 20px; color: var(--brand); flex: none; }

.contact-card address {
  color: var(--ink-soft);
  font-size: var(--step--1);
  font-style: normal;
  line-height: 1.7;
}

.contact-card a:not(.btn) {
  color: var(--ink);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
  transition: color 160ms var(--ease), text-decoration-color 160ms var(--ease);
}
.contact-card a:not(.btn):hover { color: var(--brand); text-decoration-color: var(--brand); }

.contact-card dl { margin: 0; display: grid; gap: var(--sp-2); }
.contact-card dt { color: var(--muted); font-size: 11px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; }
.contact-card dd { margin: 0; font-size: var(--step--1); }

.map-card { padding: 0; overflow: hidden; }

.map-card iframe {
  width: 100%;
  min-height: 300px;
  height: 100%;
  border: 0;
  display: block;
}

/* --------------------------------------------------------------------------
   13. Footer
   -------------------------------------------------------------------------- */

.site-footer {
  padding-block: var(--sp-8) var(--sp-6);
  background: var(--ink);
  color: rgba(255, 255, 255, 0.72);
}

.footer-grid {
  display: grid;
  gap: var(--sp-7);
  padding-bottom: var(--sp-7);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

@media (min-width: 760px) {
  .footer-grid { grid-template-columns: 1.6fr 1fr 1fr 1.2fr; gap: var(--sp-6); }
}

.site-footer h4 {
  margin-bottom: var(--sp-4);
  color: #fff;
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.site-footer p { font-size: var(--step--1); line-height: 1.7; }

.site-footer li { margin-bottom: var(--sp-3); font-size: var(--step--1); }

.site-footer a { transition: color 160ms var(--ease); }
.site-footer a:hover { color: #fff; }

/* The logo is red, black and white on transparent. A brightness/invert
   filter flattens all three into one white blob, so it gets a light plate
   instead and keeps its real colours. */
.footer-brand img {
  height: 46px;
  width: auto;
  margin-bottom: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  border-radius: var(--radius-sm);
  box-sizing: content-box;
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-5);
  justify-content: space-between;
  padding-top: var(--sp-5);
  font-size: var(--step--1);
}

.footer-bottom p { margin: 0; }

/* --------------------------------------------------------------------------
   14. Floating WhatsApp
   components.js injects `<a class="whatsapp-float" id="floatingWhatsapp">`
   and app.js sets its href, so both must keep working.
   -------------------------------------------------------------------------- */

.whatsapp-float {
  position: fixed;
  right: var(--sp-4);
  bottom: var(--sp-4);
  z-index: var(--z-float);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 52px;
  padding: 0 var(--sp-5);
  background: #1f8a4c;
  border-radius: var(--radius-pill);
  color: #fff;
  font-size: var(--step--1);
  font-weight: 600;
  box-shadow: 0 10px 28px rgba(31, 138, 76, 0.34);
  transition: transform 200ms var(--ease), background 200ms var(--ease);
}

.whatsapp-float::before {
  content: "";
  width: 20px;
  height: 20px;
  flex: none;
  background: currentColor;
  -webkit-mask: var(--wa-icon) center / contain no-repeat;
  mask: var(--wa-icon) center / contain no-repeat;
}

.whatsapp-float:hover { transform: translateY(-3px); background: #16713d; }

:root {
  --wa-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12.04 2C6.58 2 2.13 6.45 2.13 11.91c0 1.75.46 3.45 1.32 4.95L2 22l5.25-1.38a9.9 9.9 0 0 0 4.79 1.22h.01c5.46 0 9.91-4.45 9.91-9.91 0-2.65-1.03-5.14-2.9-7.01A9.82 9.82 0 0 0 12.04 2Zm0 18.15h-.01a8.2 8.2 0 0 1-4.19-1.15l-.3-.18-3.12.82.83-3.04-.2-.31a8.2 8.2 0 0 1-1.26-4.38c0-4.54 3.7-8.24 8.25-8.24 2.2 0 4.27.86 5.83 2.42a8.2 8.2 0 0 1 2.41 5.83c0 4.54-3.7 8.23-8.24 8.23Zm4.52-6.16c-.25-.12-1.47-.72-1.69-.81-.23-.08-.39-.12-.56.13-.16.24-.64.8-.78.97-.15.16-.29.18-.54.06-.25-.13-1.05-.39-1.99-1.23-.74-.66-1.23-1.47-1.38-1.72-.14-.25-.01-.38.11-.5.11-.11.25-.29.37-.44.12-.15.16-.25.25-.41.08-.17.04-.31-.02-.44-.06-.12-.56-1.34-.76-1.84-.2-.48-.4-.42-.56-.43h-.47c-.17 0-.44.06-.66.31-.23.25-.87.85-.87 2.07 0 1.22.89 2.4 1.01 2.56.12.17 1.75 2.67 4.23 3.74.59.26 1.05.41 1.41.52.59.19 1.13.16 1.56.1.47-.07 1.47-.6 1.68-1.18.2-.58.2-1.07.14-1.18-.06-.11-.22-.17-.47-.29Z'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   15. Form status, used by the enquiry form on the bulk page
   -------------------------------------------------------------------------- */

.form-status { margin: var(--sp-4) 0 0; font-size: var(--step--1); font-weight: 500; }
.form-status.success { color: var(--green); }
.form-status.error { color: var(--brand); }

/* --------------------------------------------------------------------------
   16. The three chapters — Retail, Bulk supply, Private label

   KSP runs three businesses and the client asked for all three to be visible
   on the homepage with their own detail, rather than one at a time behind a
   switcher. So the page runs linearly and a jump nav carries the reader
   between them.

   The nav is sticky inside .chapters only, so it stops following once the
   third chapter ends instead of trailing through the story and contact.
   -------------------------------------------------------------------------- */

.chapters { position: relative; }

.chapter-nav {
  position: sticky;
  top: 76px;                      /* .site-header__inner min-height */
  z-index: var(--z-raised);
  background: rgba(253, 251, 247, 0.92);
  border-block: 1px solid var(--line);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.chapter-nav__inner {
  display: flex;
  gap: var(--sp-2);
  overflow-x: auto;
  scrollbar-width: none;
}

.chapter-nav__inner::-webkit-scrollbar { display: none; }

.chapter-nav a {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  flex: none;
  padding: var(--sp-4) var(--sp-4);
  color: var(--ink-soft);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-decoration: none;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  transition: color 180ms var(--ease), border-color 180ms var(--ease);
}

.chapter-nav a:hover,
.chapter-nav a[aria-current="true"] {
  color: var(--brand);
  border-bottom-color: var(--brand);
}

.chapter-nav__num {
  font-family: var(--font-display);
  font-size: var(--step--1);
  color: var(--muted);
}

/* On a phone the three links overflow and "Private label" ends up off the
   right edge — the one business we are promoting, hidden behind a swipe.
   Drop the numerals and the padding so all three fit the row instead. */
@media (max-width: 559px) {
  .chapter-nav__inner { justify-content: space-between; overflow-x: visible; }
  .chapter-nav__num { display: none; }
  .chapter-nav a { padding: var(--sp-4) var(--sp-2); }
}

.chapter-nav a:hover .chapter-nav__num,
.chapter-nav a[aria-current="true"] .chapter-nav__num { color: var(--brand-light); }

/* The sticky header is 76px and this nav is about 52px, so an anchor needs
   more clearance than the 92px scroll-padding-top on <html>. The two add. */
.chapter { scroll-margin-top: 48px; }

.chapter__head {
  display: grid;
  gap: var(--sp-4);
  margin-bottom: var(--sp-7);
}

@media (min-width: 900px) {
  .chapter__head {
    grid-template-columns: auto 1fr;
    gap: var(--sp-6);
    align-items: start;
  }
}

.chapter__num {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: 600;
  line-height: 0.9;
  color: var(--brand);
  opacity: 0.28;
}

@media (min-width: 900px) {
  .chapter__num { font-size: var(--step-5); }
}

.chapter__head .section-head,
.chapter__head .lede { margin-bottom: 0; }

.chapter__foot {
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: var(--step--1);
}

.chapter__foot p { margin: 0; }
.chapter__foot a { color: var(--brand); font-weight: 600; }

/* --- The three-way chooser ------------------------------------------------
   .fork was built for two cards. Three need their own grid, and the third
   card needs to read as a peer of the other two without repeating either. */

@media (min-width: 800px) {
  .fork--three { grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); }
}

/* Three across at 800px is tight. Give the cards back their padding only
   once there is room for it, rather than letting a card span two columns —
   a full-width third card reads as the most important of the three, which
   is the opposite of what a chooser should say. */
@media (min-width: 800px) and (max-width: 1059px) {
  .fork--three .fork__card { padding: var(--sp-5); }
  .fork--three .fork__card h3 { font-size: var(--step-1); }
}

@media (min-width: 1060px) {
  .fork--three { gap: var(--sp-6); }
}

.fork__card--label { border-top: 4px solid var(--turmeric); }
.fork__card--label .fork__tag { background: rgba(176, 112, 15, 0.13); color: var(--turmeric-text); }
.fork__card--label .fork__list .icon { color: var(--turmeric-text); }

/* --- Who we supply --------------------------------------------------------- */

.audience-label {
  margin: 0 0 var(--sp-3);
  color: var(--muted);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.audience {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-7);
  padding: 0;
  list-style: none;
}

.audience li {
  padding: var(--sp-2) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  color: var(--ink-soft);
  font-size: var(--step--1);
  font-weight: 500;
}

/* --- What we supply -------------------------------------------------------- */

.supply {
  display: grid;
  gap: var(--sp-5);
}

@media (min-width: 700px) { .supply { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1060px) { .supply { grid-template-columns: repeat(4, 1fr); } }

.supply__card {
  display: flex;
  flex-direction: column;
  padding: var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition: transform 220ms var(--ease), border-color 220ms var(--ease),
              box-shadow 220ms var(--ease);
}

.supply__card:hover {
  transform: translateY(-3px);
  border-color: var(--line-strong);
  box-shadow: var(--shadow);
}

.supply__icon {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin-bottom: var(--sp-4);
  background: var(--sand);
  border-radius: var(--radius);
  color: var(--brand);
}

.supply__icon .icon { width: 22px; height: 22px; }

.supply__card h3 { margin: 0 0 var(--sp-3); font-size: var(--step-1); }
.supply__card p { margin: 0; color: var(--muted); font-size: var(--step--1); line-height: 1.6; }

.supply__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: var(--sp-5) 0 0;
  padding: var(--sp-5) 0 0;
  border-top: 1px solid var(--line);
  list-style: none;
}

.supply__tags li {
  padding: 2px var(--sp-3);
  background: var(--sand);
  border-radius: var(--radius-sm);
  color: var(--ink-soft);
  font-size: var(--step--1);
}

.supply__tags--lg { margin-top: 0; padding-top: 0; border-top: 0; }
.supply__tags--lg li { padding: var(--sp-2) var(--sp-4); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-pill); }

/* --- Bulk offers, now a panel inside the bulk chapter ---------------------- */

.offers-panel {
  margin-top: var(--sp-7);
  padding: var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}

@media (min-width: 768px) { .offers-panel { padding: var(--sp-7); } }

.offers-panel__head { margin-bottom: var(--sp-5); }
.offers-panel__head h3 { margin: 0; font-size: var(--step-2); }
.offers-panel .offers { margin: 0; }
.offers-panel .offer-card { background: var(--sand); }

/* --- Private label --------------------------------------------------------- */

.label-grid {
  display: grid;
  gap: var(--sp-7);
}

@media (min-width: 1000px) {
  .label-grid { grid-template-columns: 1.35fr 1fr; gap: var(--sp-8); align-items: start; }
}

.label-sub {
  margin: 0 0 var(--sp-5);
  font-family: var(--font-sans);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.steps {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: none;
}

.steps li {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-5);
  padding-bottom: var(--sp-6);
}

/* The connecting line between steps, stopping at the last one. */
.steps li:not(:last-child)::before {
  content: "";
  position: absolute;
  left: 21px;
  top: 46px;
  bottom: 6px;
  width: 2px;
  background: var(--line);
}

.steps li:last-child { padding-bottom: 0; }

.steps__num {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  background: var(--brand);
  border-radius: 50%;
  color: #fff;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
  line-height: 1;
}

.steps h4 {
  margin: var(--sp-2) 0 var(--sp-2);
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
  color: var(--ink);
}

.steps p { margin: 0; color: var(--muted); line-height: 1.6; }

.label-aside {
  display: grid;
  gap: var(--sp-5);
}

.label-panel {
  padding: var(--sp-6);
  background: var(--sand);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}

.label-panel .fork__list { margin: 0; }

/* --- Shared ---------------------------------------------------------------- */

.actions--center { justify-content: center; margin-top: var(--sp-7); }

/* --------------------------------------------------------------------------
   17. Motion preferences
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .btn:hover, .product-card:hover, .blog-card:hover,
  .fork__card:hover, .supply__card:hover, .sig__card:hover,
  .range__item:hover, .part__card:hover,
  .whatsapp-float:hover {
    transform: none;
  }
}

/* --------------------------------------------------------------------------
   18. Print
   -------------------------------------------------------------------------- */

@media print {
  .site-header, .whatsapp-float, .nav-toggle, .mobile-nav, .map-card { display: none !important; }
  body { background: #fff; }
}

/* ==========================================================================
   17. The moving strip                                          [2026-09-09]
   --------------------------------------------------------------------------
   The client asked for the old site's marquee back. This is not that strip:
   the old one was blue keyword soup and the loudest thing on the page. This
   one carries the real range and the real services, warm, quiet, readable.

   Motion rules, and they matter more than the effect:
     * pauses on hover AND on focus-within, so it can be read and so a
       keyboard user tabbing into a link does not have it slide away
     * prefers-reduced-motion STOPS it, rather than slowing it down. A strip
       that still moves is still unreadable to someone who asked for less
       motion, and it wraps rather than clipping the rest of the list.
   ========================================================================== */
.marquee {
  background: var(--brand-dark);
  color: #fff;
  overflow: hidden;
  border-block: 1px solid rgba(255, 255, 255, .12);
}
.marquee__track {
  display: flex;
  width: max-content;
  animation: marquee-scroll 46s linear infinite;
}
.marquee:hover .marquee__track,
.marquee:focus-within .marquee__track { animation-play-state: paused; }

.marquee__list {
  display: flex;
  align-items: center;
  gap: var(--sp-6);
  margin: 0;
  padding: var(--sp-3) var(--sp-3) var(--sp-3) 0;
  list-style: none;
  white-space: nowrap;
}
.marquee__list li {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .12em;          /* caps need air between the letters */
  text-transform: uppercase;      /* 2026-09-12: the client asked for capitals */
  opacity: .92;
}
/* The separator is decorative, so it is drawn rather than typed -- a bullet
   character would be read out between every single item. */
.marquee__list li + li::before {
  content: "";
  display: inline-block;
  width: 5px; height: 5px;
  margin-right: var(--sp-6);
  border-radius: 50%;
  background: var(--turmeric);
  vertical-align: middle;
}
@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; width: 100%; }
  .marquee__list  { flex-wrap: wrap; white-space: normal; gap: var(--sp-3) var(--sp-5); }
  .marquee__list + .marquee__list { display: none; }   /* the duplicate is only for the loop */
  .marquee__list li + li::before { margin-right: var(--sp-5); }
}

/* ==========================================================================
   18. Section foot                                               [2026-09-09]
   The line under a section that carries on somewhere else.
   ========================================================================== */
.section-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4);
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
}
.section-foot p { margin: 0; color: var(--muted); font-size: var(--step--1); }

/* ==========================================================================
   19. Testimonials                                               [2026-09-09]
   Styled and ready. The markup is commented out in index.html until real
   quotes exist -- see the note there.
   ========================================================================== */
.quotes {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
/* 2026-09-12: the client found the first cut "maximalised". The quote is now
   body text at a small size, no decorative quote marks, tighter card. */
.quote {
  margin: 0;
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.quote blockquote { margin: 0; }
.quote blockquote p {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 450;
  line-height: 1.6;
  color: var(--ink-soft);
}
.quote__stars { color: var(--turmeric); font-size: 12px; letter-spacing: 1.5px; line-height: 1; }
.quote figcaption { margin-top: auto; padding-top: var(--sp-3); border-top: 1px solid var(--line); font-size: 12.5px; line-height: 1.45; }
.quote figcaption b    { display: block; color: var(--ink); font-weight: 700; }
.quote figcaption span { color: var(--muted); }

/* ==========================================================================
   20. The range                                                  [2026-09-09]
   retail.html: the 25 real products, by category, from the client's own pack
   shots. Static markup, not the Supabase catalogue -- these are the printed
   range, and the database holds only what is actively for sale online.
   ========================================================================== */
.range + .range { margin-top: var(--sp-7); }
.range__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line);
}
.range__head h3 { margin: 0; font-size: var(--step-2); }
.range__head span { color: var(--muted); font-size: var(--step--1); }

.range__grid {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
}
.range__item {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
/* contain, not cover: these are pack shots, and cropping a pack crops the
   product name off it. */
.range__item img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: contain;
  background: #fff;
  display: block;
}
/* The pouch cut-outs (Drive renders, near-square) would touch the card's edges: give them air. */
.range__item img[src$="-cut.png"] { box-sizing: border-box; padding: 9% 8% 5%; }
.range__item b {
  display: block;
  padding: var(--sp-3) var(--sp-4) var(--sp-4);
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--ink);
}

/* A plain list of names, for the wholesale ranges that have no photography. */
.namelist {
  display: grid;
  gap: var(--sp-2) var(--sp-5);
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}
.namelist li {
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--step--1);
  color: var(--ink-soft);
}

@media (max-width: 560px) {
  .range__grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: var(--sp-3); }
}

/* ==========================================================================
   21. Signature products, homepage                                [2026-09-12]
   Replaces the Supabase catalogue on the homepage. The client asked for a
   short section of star products from a few categories, each linking to its
   category on retail.html, plus one "Order now" into the WhatsApp catalog.
   Static markup from the real pack shots, so nothing here waits on the
   database.
   ========================================================================== */
.signature {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 700px)  { .signature { grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); } }
@media (min-width: 1060px) { .signature { grid-template-columns: repeat(6, 1fr); } }

.sig__card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  color: var(--ink);
  transition: transform 220ms var(--ease), box-shadow 220ms var(--ease), border-color 220ms var(--ease);
}
.sig__card:hover { transform: translateY(-4px); border-color: var(--line-strong); box-shadow: var(--shadow-lg); }
.sig__card img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: contain;
  background: #fff;
  transition: transform 400ms var(--ease);
}
.sig__card:hover img { transform: scale(1.04); }
.sig__body { padding: var(--sp-3) var(--sp-4) var(--sp-4); }
.sig__cat {
  display: block;
  margin-bottom: 2px;
  color: var(--brand);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.sig__card b { display: block; font-size: var(--step--1); font-weight: 700; line-height: 1.3; }
.sig__card small { display: block; margin-top: 2px; color: var(--muted); font-size: 12px; }

/* The word the client asked for, set where it carries weight: as the
   section's display heading, in the display face, letter-spaced. */
.sig-title {
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1;
}
.sig-title span { color: var(--brand); }

/* ==========================================================================
   22. The range, filtered                                          [2026-09-12]
   retail.html: six buttons over the static range. The buttons reuse the
   .filters / .btn.active look of the old catalogue so the two read the same.
   Each group carries its weight badge and its own "Order now" into the
   WhatsApp Business catalog.
   ========================================================================== */
.range-filter {
  position: sticky;
  top: 76px;
  z-index: var(--z-raised);
  margin: 0 0 var(--sp-6);
  padding: var(--sp-3) 0;
  background: rgba(253, 251, 247, 0.92);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
.range-filter .filters { margin: 0; }
.range-filter .filters .btn { min-height: 40px; padding: var(--sp-2) var(--sp-4); font-size: 13px; }

/* On a phone the six buttons wrap into rows rather than scrolling sideways:
   a scrolling row hid "No onion, no garlic" and "Sachets" behind a swipe,
   the same trap the chapter nav fell into on 2026-09-08. Two rows of pills
   is too tall to keep sticky under the header, so it is not sticky there. */
@media (max-width: 559px) {
  .range-filter { position: static; }
  .range-filter .filters .btn { min-height: 38px; padding: var(--sp-1) var(--sp-3); font-size: 12.5px; }
  .range { scroll-margin-top: 92px; }
}

.range[hidden] { display: none; }
.range { scroll-margin-top: 150px; }

.range__head { align-items: center; }
.range__head .range__weight { margin-left: auto; }

.range__weight {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px var(--sp-3);
  background: var(--sand);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  white-space: nowrap;
}

.range__item { position: relative; transition: transform 220ms var(--ease), box-shadow 220ms var(--ease); }
.range__item:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.range__item b { display: flex; flex-direction: column; gap: 2px; }
.range__item .muted { font-weight: 500; color: var(--muted); font-size: 12px; }

/* Weight, on the tile itself. Empty until the client confirms it. */
.range__item .badge {
  position: absolute;
  top: var(--sp-2);
  left: var(--sp-2);
  padding: 2px 8px;
  background: var(--brand-dark);
  border-radius: var(--radius-pill);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
}
.range__item .badge:empty { display: none; }

.range__cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3) var(--sp-4);
  margin-top: var(--sp-5);
}
.range__cta p { margin: 0; color: var(--muted); font-size: var(--step--1); }

/* "Order now" is green because it is WhatsApp, and the customer should
   know that before they tap. */
.btn--wa { background: #1f8a4c; border-color: #1f8a4c; color: #fff; }
.btn--wa:hover { background: #16713d; border-color: #16713d; }
.btn--wa::before {
  content: "";
  width: 18px; height: 18px; flex: none;
  background: currentColor;
  -webkit-mask: var(--wa-icon) center / contain no-repeat;
  mask: var(--wa-icon) center / contain no-repeat;
}

/* ==========================================================================
   23. Bulk supply in three parts                                    [2026-09-12]
   bulk.html: Spices, Seasonings, Herbs, with a small jump row in the same
   pill style as the retail buttons. Each part has a strip of the real pack
   shots, because the client wanted images and stock photography was the
   thing this redesign got rid of.
   ========================================================================== */
.part-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-7);
}
.part-nav a {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-2) var(--sp-5);
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-pill);
  color: var(--ink-soft);
  font-size: var(--step--1);
  font-weight: 600;
  transition: border-color 160ms var(--ease), color 160ms var(--ease);
}
.part-nav a:hover { border-color: var(--brand); color: var(--brand); }
.part-nav a b { font-family: var(--font-display); color: var(--brand); font-weight: 600; }

.part { scroll-margin-top: 96px; }
.part + .part { margin-top: var(--sp-8); padding-top: var(--sp-8); border-top: 1px solid var(--line); }

.part__head {
  display: grid;
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
}
@media (min-width: 900px) {
  .part__head { grid-template-columns: auto 1fr; gap: var(--sp-6); align-items: start; }
}
.part__num {
  font-family: var(--font-display);
  font-size: var(--step-5);
  font-weight: 600;
  line-height: 0.9;
  color: var(--brand);
  opacity: 0.22;
}
.part__head h2 { font-size: var(--step-3); }
.part__head .lede { margin-top: var(--sp-3); font-size: var(--step-0); }

.part__body {
  display: grid;
  gap: var(--sp-6);
}
/* 2026-09-16 (client round 5): the retail pack photos that sat in a right-hand
   column are gone, so the body is one column and the name lists run across it. */
.part__lists { display: grid; gap: var(--sp-6); }
@media (min-width: 560px)  { .part__lists { grid-template-columns: repeat(2, 1fr); gap: var(--sp-6) var(--sp-7); } }
@media (min-width: 900px)  { .part__lists { grid-template-columns: repeat(3, 1fr); } }
.part__lists h3 { margin: 0 0 var(--sp-3); font-size: var(--step-1); }
.part__lists h3 span { margin-left: var(--sp-2); color: var(--muted); font-family: var(--font-sans); font-size: var(--step--1); font-weight: 500; }

.part__media {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: repeat(3, 1fr);
}
.part__media figure {
  margin: 0;
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.part__media img { width: 100%; aspect-ratio: 1; object-fit: contain; background: #fff; }
.part__media img[src$="-cut.png"] { box-sizing: border-box; padding: 7%; }
.part__media figcaption {
  padding: var(--sp-2) var(--sp-3);
  border-top: 1px solid var(--line);
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 600;
  text-align: center;
}
.part__media-note { margin: var(--sp-3) 0 0; color: var(--muted); font-size: 12px; }

/* Seasoning types as three cards rather than a tick list, with what each
   one is for. Customisation is a note under them, not a fourth type. */
.part__cards {
  display: grid;
  gap: var(--sp-4);
}
@media (min-width: 640px)  { .part__cards { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .part__cards { grid-template-columns: repeat(4, 1fr); } }   /* four since 2026-09-15: Customised joined */

.part__card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 4px solid var(--brand);
  border-radius: var(--radius);
  transition: transform 220ms var(--ease), box-shadow 220ms var(--ease);
}
.part__card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.part__card--jain { border-top-color: var(--green); }
.part__card--health { border-top-color: var(--turmeric); }
.part__card--custom { border-top-color: var(--brand-dark); }
/* Bulk filter (2026-09-15): the three parts hide like range groups. A hidden
   part must not leave its rule and gap on the next one. */
.part[hidden] { display: none; }
.part[hidden] + .part { margin-top: 0; padding-top: 0; border-top: 0; }
.part__card h3 { font-size: var(--step-1); }
.part__card p { margin: 0; color: var(--muted); font-size: var(--step--1); }
.part__card .tag {
  align-self: flex-start;
  padding: 2px var(--sp-3);
  background: var(--sand);
  border-radius: var(--radius-pill);
  color: var(--ink-soft);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* Applications: what a seasoning goes on. The client named these. */
.apps { margin-top: var(--sp-6); }
.apps h3 { margin: 0 0 var(--sp-3); font-size: var(--step-1); }
.apps ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}
.apps li {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  color: var(--ink-soft);
  font-size: var(--step--1);
  font-weight: 600;
}
.apps li::before {
  content: "";
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--turmeric);
}
.part__note {
  margin: var(--sp-5) 0 0;
  padding: var(--sp-4) var(--sp-5);
  background: var(--sand);
  border-left: 3px solid var(--brand);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: var(--ink-soft);
  font-size: var(--step--1);
}
.part__note p { margin: 0; }

/* ==========================================================================
   24. The enquiry form, buy-online.html                             [2026-09-12]
   The page is now "Get in touch": the form, the contact details, nothing
   else. The range tabs it used to carry are bulk.html's job. Field names
   and ids are unchanged, because buy.js reads them.
   ========================================================================== */
.enquiry {
  display: grid;
  gap: var(--sp-7);
}
@media (min-width: 960px) {
  .enquiry { grid-template-columns: 1.3fr 1fr; gap: var(--sp-8); align-items: start; }
}
.enquiry__aside { display: grid; gap: var(--sp-5); }
.enquiry__aside .contact-card dl { gap: var(--sp-3); }

.form {
  display: grid;
  gap: var(--sp-4);
  padding: var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
@media (min-width: 640px) {
  .form { grid-template-columns: 1fr 1fr; padding: var(--sp-7); }
  .form .field--full, .form h3, .form .btn, .form .form-status { grid-column: 1 / -1; }
}
.form h3 { font-size: var(--step-2); }
.field { display: grid; gap: var(--sp-2); }
.field label {
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.field label span { color: var(--brand); }
.field input, .field select, .field textarea {
  width: 100%;
  min-height: 48px;
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg);
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font: inherit;
  font-size: var(--step-0);
  transition: border-color 160ms var(--ease), box-shadow 160ms var(--ease);
}
.field textarea { min-height: 120px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 4px rgba(161, 48, 40, 0.12);
}
.field input::placeholder, .field textarea::placeholder { color: #9a8f88; }
.form .btn { justify-self: start; }
@media (max-width: 639px) { .form .btn { width: 100%; } }
.form-status:empty { display: none; }

/* ==========================================================================
   25. Motion                                                       [2026-09-12]
   The client: "right now it's looking very static". Three things, all
   transform and opacity, all off under prefers-reduced-motion:
     * hero enters in sequence on load
     * [data-reveal] rises into place as it scrolls in; a data-reveal-group
       staggers its children by --reveal-i
     * the hero image drifts a few pixels with the scroll (ksp.js)
   The reveal classes only bite once ksp.js adds .has-reveal to <html>, so
   with scripting off nothing is ever hidden.
   ========================================================================== */
.has-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 640ms var(--ease), transform 640ms var(--ease);
  transition-delay: calc(var(--reveal-i, 0) * 70ms);
  will-change: opacity, transform;
}
.has-reveal [data-reveal].is-in { opacity: 1; transform: none; }
.has-reveal [data-reveal="fade"] { transform: none; }
.has-reveal [data-reveal="left"] { transform: translateX(-24px); }
.has-reveal [data-reveal="right"] { transform: translateX(24px); }
.has-reveal [data-reveal="scale"] { transform: scale(0.96); }

/* A sideways offset on an element that has not revealed yet extends the
   document's scrollable width -- the 390px harness measured 398 -- and on
   a phone that is a page that wiggles. Below the two-column breakpoints the
   sideways variants rise instead, and the root clips what is left. */
@media (max-width: 999px) {
  .has-reveal [data-reveal="left"],
  .has-reveal [data-reveal="right"] { transform: translateY(22px); }
}
html { overflow-x: clip; }

@keyframes rise-in {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}
@keyframes drift-in {
  from { opacity: 0; transform: translateX(28px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
@keyframes seal-in {
  from { opacity: 0; transform: rotate(-12deg) scale(0.7); }
  to   { opacity: 1; transform: none; }
}
.hero .eyebrow, .hero__title, .hero__sub, .hero .actions, .hero__proof {
  animation: rise-in 700ms var(--ease) both;
}
.hero__title    { animation-delay: 80ms; }
.hero__sub      { animation-delay: 180ms; }
.hero .actions  { animation-delay: 280ms; }
.hero__proof    { animation-delay: 380ms; }
.hero__media img { animation: drift-in 900ms var(--ease) 120ms both; }
.seal { animation: seal-in 700ms var(--ease) 700ms both; }

/* A slow warm glow behind the hero, so the page breathes even at rest. */
.hero::before {
  content: "";
  position: absolute;
  inset: -20% -10%;
  background:
    radial-gradient(40% 40% at 80% 20%, rgba(176, 112, 15, 0.12), transparent 70%),
    radial-gradient(35% 35% at 10% 90%, rgba(197, 67, 65, 0.10), transparent 70%);
  animation: glow 14s ease-in-out infinite alternate;
  pointer-events: none;
}
.hero > .wrap { position: relative; }
@keyframes glow {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(3%, 4%, 0) scale(1.06); }
}

/* Marquee separators pulse gently, so the strip reads as alive even when
   paused on hover. */
.marquee__list li + li::before { animation: pulse 3s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: 0.45; transform: scale(0.8); } }

@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1 !important; transform: none !important; transition: none !important; }
  .hero .eyebrow, .hero__title, .hero__sub, .hero .actions, .hero__proof,
  .hero__media img, .seal, .hero::before, .marquee__list li + li::before { animation: none !important; }
  .hero__media img { transform: none !important; }
}

/* ==========================================================================
   26. Odds and ends                                                [2026-09-12]
   ========================================================================== */

/* The journal links out to LinkedIn. Hidden until the URL exists. */
.btn--linkedin { gap: var(--sp-2); }
.btn--linkedin .icon { width: 18px; height: 18px; }

/* Testimonials, once they exist, say where they came from. */
.quote figcaption i { display: block; margin-top: 3px; color: var(--muted); font-size: 10px; font-style: normal; letter-spacing: 0.08em; text-transform: uppercase; }

/* ==========================================================================
   27. Hero C — the poster                                          [2026-09-12]
   Chosen by the client from three mockups. One pack, one word, one button.
   The hero takes the colour of the product on screen and changes with it;
   ksp.js drives the switch, the tilt and the 5 s cycle. The three packs
   are the cut-out pouch PNGs in assets/products/ (made by
   hero-mockups/cutout.py in the task folder).
   ========================================================================== */
/* ===== Direction C: the poster. One pack, one word, one button.
   The whole hero takes the colour of the product on screen and changes
   with it: chilli red for Kashmiri, turmeric for Haldi, coriander green
   for Dhaniya. Auto-cycles every 5s; the dots switch it by hand. ===== */
.heroC {
  --c1: #7a1712; --c2: #c54341; --ink-on: #fff;
  position: relative;
  overflow: hidden;
  min-height: min(calc(100svh - 76px), 880px);
  display: grid;
  align-items: center;
  color: var(--ink-on);
  background: radial-gradient(120% 90% at 20% 10%, var(--c2), var(--c1) 70%);
  transition: background 900ms var(--ease);
  isolation: isolate;
}
/* Two colour layers crossfade, because a gradient cannot transition. */
.heroC__bg {
  position: absolute; inset: 0; z-index: -3;
  background: radial-gradient(120% 90% at 20% 10%, var(--c2), var(--c1) 70%);
  opacity: 0;
  transition: opacity 900ms var(--ease);
}
.heroC__bg.is-on { opacity: 1; }
.heroC__bg--kashmiri { --c1: #6e1410; --c2: #c9463f; }
.heroC__bg--haldi    { --c1: #8a5809; --c2: #e0a531; }
.heroC__bg--dhaniya  { --c1: #244f2b; --c2: #6aa457; }
.heroC__bg--deggi    { --c1: #5c3b06; --c2: #d6a023; }   /* 2026-09-16: golden, at the client's request (was brick red #5e2210/#b8552a) */

/* Soft light and grain so the flat colour has depth. */
.heroC__light {
  position: absolute; z-index: -2; pointer-events: none;
  width: 80vmax; height: 80vmax; right: -25vmax; top: -30vmax;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,0.22), transparent 60%);
  animation: lightC 12s ease-in-out infinite alternate;
}
@keyframes lightC { to { transform: translate3d(-8%, 10%, 0) scale(1.1); } }
.heroC__grain {
  position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: 0.18; mix-blend-mode: soft-light;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* The giant word behind the pack. 2026-09-15: the client found the serif
   outline "not coming completely" (KASHMIRI ran off both edges) and asked
   for a different face. Now the sans at its heaviest weight, filled at a low
   opacity with a thin stroke, and ksp.js sets the font-size so the whole
   word fits inside the hero with a margin either side. The clamp here is
   the ceiling the script starts from. */
.heroC__word {
  position: absolute;
  left: 50%; top: 30%;
  z-index: 0;
  translate: -50% -50%;
  font-family: var(--font-sans);
  font-weight: 800;
  font-size: clamp(5rem, 22vw, 20rem);
  line-height: 1;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(255,255,255,0.10);
  -webkit-text-stroke: 1.5px rgba(255,255,255,0.45);
  pointer-events: none;
  user-select: none;
  max-width: none;
}
.heroC__word span { display: block; animation: word-rise 900ms var(--ease) both; }
@keyframes word-rise { from { opacity: 0; transform: translateY(6%); letter-spacing: 0.1em; } to { opacity: 1; transform: none; letter-spacing: 0.02em; } }

.heroC__grid {
  position: relative; z-index: 1;
  display: grid;
  gap: var(--sp-6);
  align-items: center;
  min-height: inherit;
  padding-block: var(--sp-7) var(--sp-8);
}
@media (min-width: 900px) {
  .heroC__grid { grid-template-columns: 1fr auto 1fr; gap: var(--sp-7); }
  .heroC__copy, .heroC__meta { align-self: end; padding-bottom: 6px; }
}

.heroC__copy { max-width: 22rem; }
.heroC__eyebrow {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  margin: 0 0 var(--sp-4);
  font-size: 12px; font-weight: 700; letter-spacing: 0.2em; text-transform: uppercase;
  color: rgba(255,255,255,0.8);
  animation: rise-in 700ms var(--ease) both;
}
/* 2026-09-12: the short line before the eyebrow is gone at the client's request. */
.heroC__title {
  color: #fff;
  font-size: clamp(2.6rem, 1.6rem + 3.6vw, 4.6rem);
  line-height: 0.98;
  letter-spacing: -0.03em;
  font-weight: 500;
  margin: 0 0 var(--sp-5);
  text-wrap: balance;
  animation: rise-in 700ms var(--ease) 100ms both;
}
.heroC__title em { font-style: italic; font-weight: 500; font-variation-settings: "opsz" 144; }
.heroC__line {
  margin: 0 0 var(--sp-6);
  color: rgba(255,255,255,0.82);
  font-size: var(--step-0);
  animation: rise-in 700ms var(--ease) 200ms both;
}
.heroC .actions { margin: 0; animation: rise-in 700ms var(--ease) 300ms both; }
.heroC .btn.primary { background: #fff; border-color: #fff; color: #1c1614; }
.heroC .btn.primary:hover { background: #fff3e0; border-color: #fff3e0; }

/* The pack: perspective tilt follows the pointer, floats at rest. */
.heroC__stage {
  position: relative;
  width: min(68vw, 380px);
  aspect-ratio: 1110 / 1228;              /* the Drive renders (2026-09-15): angled pack, near-square */
  margin-inline: auto;
  perspective: 1200px;
}
@media (min-width: 900px) { .heroC__stage { width: clamp(300px, 29vw, 450px); } }
.heroC__pack {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform 500ms var(--ease);
  animation: floatC 6s ease-in-out infinite alternate;
}
@keyframes floatC { from { translate: 0 0; } to { translate: 0 -14px; } }
.heroC__pack img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 34px 34px rgba(0,0,0,0.38));
  opacity: 0;
  transform: translateY(30px) scale(0.96);
  transition: opacity 600ms var(--ease), transform 700ms var(--ease);
}
.heroC__pack img.is-on { opacity: 1; transform: none; }
/* 2026-09-15: the gloss that slid across the pack as it tilted is gone --
   the client wants the mocks matte. The tilt itself stays. */
.heroC__shadow {
  position: absolute; left: 12%; right: 12%; bottom: -8%;
  height: 10%;
  border-radius: 50%;
  background: rgba(0,0,0,0.35);
  filter: blur(14px);
  animation: shadowC 6s ease-in-out infinite alternate;
}
@keyframes shadowC { from { transform: scale(1); opacity: .9; } to { transform: scale(0.85); opacity: .6; } }

/* Right column: the product's name and the switcher. */
.heroC__meta { justify-self: end; text-align: right; display: grid; justify-items: end; }
@media (max-width: 899px) { .heroC__meta { justify-self: stretch; text-align: left; } }
.heroC__name {
  font-family: var(--font-display);
  font-size: var(--step-3);
  line-height: 1.05;
  color: #fff;
  margin: 0;
}
.heroC__name small { display: block; margin-top: 4px; font-family: var(--font-sans); font-size: 12px; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: rgba(255,255,255,0.75); }

.switch {
  display: flex; gap: var(--sp-3);
  margin: var(--sp-5) 0 0;
  padding: 0; list-style: none;
}
@media (min-width: 900px) { .switch { justify-content: flex-end; } }
.switch button {
  position: relative;
  width: 52px; height: 52px;
  padding: 3px;
  background: rgba(255,255,255,0.12);
  border: 1.5px solid rgba(255,255,255,0.3);
  border-radius: 50%;
  cursor: pointer;
  overflow: hidden;
  transition: border-color 200ms var(--ease), transform 200ms var(--ease);
}
.switch button img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block; }
.switch button:hover { transform: translateY(-2px); border-color: #fff; }
.switch button[aria-pressed="true"] { border-color: #fff; box-shadow: 0 0 0 4px rgba(255,255,255,0.18); }
/* Progress ring on the active dot: fills over the 5s until the next one. */
.switch button[aria-pressed="true"]::after {
  content: "";
  position: absolute; inset: -1.5px;
  border-radius: 50%;
  background: conic-gradient(#fff var(--p, 0%), transparent 0);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
  animation: ring 5s linear forwards;
}
@keyframes ring { from { --p: 0%; } to { --p: 100%; } }
@property --p { syntax: "<percentage>"; inherits: false; initial-value: 0%; }

.heroC__scroll {
  position: absolute; z-index: 1; left: 50%; bottom: var(--sp-4); translate: -50% 0;
  width: 26px; height: 42px; border: 1.5px solid rgba(255,255,255,0.45); border-radius: 14px;
  display: none;
}
@media (min-width: 900px) { .heroC__scroll { display: block; } }
.heroC__scroll::after { content: ""; position: absolute; left: 50%; top: 8px; width: 3px; height: 8px; margin-left: -1.5px; border-radius: 2px; background: #fff; animation: wheel 1.8s ease-in-out infinite; }
@keyframes wheel { 50% { transform: translateY(12px); opacity: 0.3; } }

/* ---- Phone: one screen. Headline on top, the pack filling the middle,
   name + thumbnails + button at the bottom. The desktop's subline and
   button are hidden here; a full-width button sits at the end instead. ---- */
@media (max-width: 899px) {
  .heroC { min-height: min(calc(100svh - 76px), 880px); }
  .heroC__grid {
    grid-template-rows: auto minmax(0, 1fr) auto;
    gap: var(--sp-4);
    /* 84px at the bottom clears the floating WhatsApp button, which
       otherwise sits exactly on the hero's own button on a phone. */
    padding-block: var(--sp-5) 84px;
    text-align: center;
    min-height: min(calc(100svh - 76px), 880px);
  }
  .heroC__copy { max-width: none; }
  .heroC__eyebrow { justify-content: center; margin-bottom: var(--sp-3); }
  .heroC__title { font-size: clamp(2.3rem, 1.2rem + 7vw, 3.4rem); margin-bottom: 0; }
  .heroC__line, .heroC__copy .actions { display: none; }
  .heroC__stage {
    width: auto;
    max-width: 78vw;          /* a very tall viewport must not widen the pack past the screen */
    height: 100%;
    max-height: 46svh;
    aspect-ratio: 460 / 637;
    margin-inline: auto;
  }
  .heroC__word { top: 50%; font-size: 26vw; -webkit-text-stroke-width: 1px; }
  .heroC__meta { justify-self: stretch; text-align: center; justify-items: center; }
  .heroC__name { font-size: var(--step-2); }
  .switch { justify-content: center; margin-top: var(--sp-4); }
  .switch button { width: 46px; height: 46px; }
  .heroC__cta { display: block; width: 100%; margin-top: var(--sp-5); }
  .heroC__cta .btn { width: 100%; }
  .heroC__scroll { display: none; }
}
@media (min-width: 900px) { .heroC__cta { display: none; } }
@media (prefers-reduced-motion: reduce) {
  .heroC__light, .heroC__pack, .heroC__shadow, .heroC__word span, .heroC__eyebrow, .heroC__title, .heroC__line, .heroC .actions, .heroC__scroll::after, .switch button::after { animation: none !important; }
  .heroC__pack { transform: none !important; }
}

/* ==========================================================================
   28. The page is a pouch                                          [2026-09-12]
   The client: the white should look like the packaging material. His 500 g
   pouch is a matte laminated film -- soft folds catching the light, a fine
   grain, and small flower marks scattered across it. All of that is drawn
   here in CSS with SVG filters, so there is no texture image to download
   and it never visibly repeats.

   Three layers on the light grounds:
     folds   a low-frequency noise lit from the top-left (feDiffuseLighting),
             blended soft-light, so the surface gently rises and falls
     grain   a high-frequency noise, overlay, barely there
     flowers the pack's tiny flower mark, turmeric, at ~5% on sand sections
   Kept subtle on purpose: it should read as material only when looked for.
   ========================================================================== */
:root {
  --tx-folds: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='900'%3E%3Cfilter id='f' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.008 0.004' numOctaves='5' seed='3' stitchTiles='stitch'/%3E%3CfeDiffuseLighting lighting-color='%23ffffff' surfaceScale='9' diffuseConstant='1'%3E%3CfeDistantLight azimuth='35' elevation='68'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
  --tx-gather: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='300'%3E%3Cfilter id='f' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.006 0.03' numOctaves='4' seed='21' stitchTiles='stitch'/%3E%3CfeDiffuseLighting lighting-color='%23ffffff' surfaceScale='12' diffuseConstant='1'%3E%3CfeDistantLight azimuth='80' elevation='60'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
  --tx-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.95' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.5 0 0 0 0 0.5 0 0 0 0 0.5 0 0 0 0.9 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  --tx-flower: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='320' viewBox='0 0 320 320'%3E%3Cg fill='%23b0700f' fill-opacity='0.11'%3E%3Cg transform='translate(58 74)'%3E%3Ccircle r='2.6'/%3E%3Ccircle cx='0' cy='-5' r='2.3'/%3E%3Ccircle cx='4.8' cy='-1.6' r='2.3'/%3E%3Ccircle cx='3' cy='4.1' r='2.3'/%3E%3Ccircle cx='-3' cy='4.1' r='2.3'/%3E%3Ccircle cx='-4.8' cy='-1.6' r='2.3'/%3E%3C/g%3E%3Cg transform='translate(226 214) scale(0.85)'%3E%3Ccircle r='2.6'/%3E%3Ccircle cx='0' cy='-5' r='2.3'/%3E%3Ccircle cx='4.8' cy='-1.6' r='2.3'/%3E%3Ccircle cx='3' cy='4.1' r='2.3'/%3E%3Ccircle cx='-3' cy='4.1' r='2.3'/%3E%3Ccircle cx='-4.8' cy='-1.6' r='2.3'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
}

body {
  background-color: var(--bg);
  background-image: var(--tx-folds), var(--tx-grain);
  background-size: 900px 900px, 240px 240px;
  background-blend-mode: multiply, overlay;
}

.section--sand {
  background-color: var(--sand);
  background-image: var(--tx-flower), var(--tx-folds), var(--tx-grain);
  background-size: 320px 320px, 900px 900px, 240px 240px;
  background-position: 30px 40px, 0 0, 0 0;
  background-blend-mode: normal, multiply, overlay;
}

/* The header keeps its frosted plate; it sits over the texture, not in it. */

/* Cards stay clean white so the texture reads as the ground they rest on. */

@media print {
  body, .section--sand { background-image: none; }
}

/* ==========================================================================
   29. The sealed edge                                              [2026-09-12]
   The client: the homepage should END the way the pouch ends. The pouch's
   bottom is a heat seal -- a ribbed strip with fine horizontal crimp lines,
   and the film gathering into it just above. This sits between the last
   section and the footer, full width, so the whole page reads as one pouch
   standing on the dark footer.

   Two parts: .pouch-seal__gather (the film crumpling, lit) and
   .pouch-seal__crimp (the ribs, drawn as alternating light and shade lines,
   with a soft vignette so the strip looks pressed rather than printed).
   ========================================================================== */
.pouch-seal {
  position: relative;
  height: 118px;
  overflow: hidden;
  background: var(--sand);
}
.pouch-seal__gather {
  position: absolute; inset: 0 0 46px;
  background-color: var(--sand);
  background-image:
    linear-gradient(180deg, rgba(120, 90, 60, 0) 0%, rgba(120, 90, 60, 0.08) 55%, rgba(120, 90, 60, 0.2) 100%),
    var(--tx-folds);
  background-size: auto, 900px 900px;
  background-blend-mode: normal, multiply;
}
/* Horizontal crumples pinched toward the crimp: strongest at the seal,
   fading to nothing at the top so the page's own film runs into it. */
.pouch-seal__gather::after {
  content: "";
  position: absolute; inset: 0;
  background: var(--tx-gather) 0 0 / 600px 300px;
  mix-blend-mode: multiply;
  opacity: 0.55;
  -webkit-mask: linear-gradient(180deg, transparent 0%, rgba(0,0,0,0.5) 55%, #000 100%);
  mask: linear-gradient(180deg, transparent 0%, rgba(0,0,0,0.5) 55%, #000 100%);
}
.pouch-seal__crimp {
  position: absolute; left: 0; right: 0; bottom: 0; height: 46px;
  background:
    linear-gradient(90deg, rgba(60, 40, 25, 0.16), transparent 12%, transparent 88%, rgba(60, 40, 25, 0.16)),
    repeating-linear-gradient(180deg,
      #f3ebdc 0 2px,
      #d9ccb6 2px 3px,
      #fbf6ec 3px 4.5px,
      #cfc0a8 4.5px 5.5px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 -2px 6px rgba(60, 40, 25, 0.12);
}
/* A thin dark line where the seal meets the footer: the pouch's cut edge. */
.pouch-seal::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  background: linear-gradient(180deg, #b8a88f, #7d6d58);
}
@media (max-width: 559px) {
  .pouch-seal { height: 84px; }
  .pouch-seal__gather { inset: 0 0 34px; }
  .pouch-seal__crimp { height: 34px; }
}


/* ==========================================================================
   30. Client round 4                                              [2026-09-15]
   ========================================================================== */

/* The one "Order now" on the range page, under the filters, instead of a
   button after every category (the client counted them). */
.order-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.order-bar p { margin: 0; color: var(--ink-soft); font-size: var(--step--1); }
@media (max-width: 559px) { .order-bar .btn { width: 100%; } }

/* Applications as photographs (bulk.html). */
.apps--photos ul { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); }
@media (min-width: 640px) { .apps--photos ul { grid-template-columns: repeat(6, 1fr); } }
.apps--photos li {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.apps--photos li::before { display: none; }
.apps--photos img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; }
.apps--photos span { padding: var(--sp-2) var(--sp-3); font-size: 13px; font-weight: 600; text-align: center; }

/* The Spice Diary page's head. */
.diary-head { max-width: 46rem; }

/* Private label: the pitch, in three short cards. */
.label-points { display: grid; gap: var(--sp-4); margin-top: var(--sp-6); }
@media (min-width: 700px) { .label-points { grid-template-columns: repeat(3, 1fr); } }
.label-point {
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 3px solid var(--brand);
  border-radius: var(--radius);
}
.label-point b { display: block; margin-bottom: var(--sp-2); font-family: var(--font-display); font-size: var(--step-1); font-weight: 600; }
.label-point p { margin: 0; color: var(--muted); font-size: var(--step--1); }

/* The cursor is a red chilli (his suggestion). Only where there is a fine
   pointer -- a phone has no cursor and a coarse pointer would get the
   fallback anyway. Links and buttons keep the pointing hand, so "this is
   clickable" still reads. */
@media (hover: hover) and (pointer: fine) {
  html, body { cursor: url("assets/chilli-cursor.svg") 3 3, auto; }
}

/* Click burst: a pinch of chilli and turmeric thrown where the page was
   clicked. Particles are made by ksp.js and remove themselves. */
.pinch {
  position: fixed; z-index: 9999; left: 0; top: 0;
  width: 6px; height: 6px;
  border-radius: 50%;
  pointer-events: none;
  will-change: transform, opacity;
  animation: pinch-fall var(--t, 900ms) cubic-bezier(.2,.6,.3,1) forwards;
}
.pinch--chilli   { background: #c9463f; }
.pinch--deep     { background: #8a1d17; }
.pinch--turmeric { background: #e0a531; }
.pinch--gold     { background: #f1c766; }
@keyframes pinch-fall {
  0%   { transform: translate(0, 0) scale(1); opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) scale(0.3); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .pinch { display: none; } }


/* ==========================================================================
   31. The Signature showcase                            [2026-09-15, redone]
   The client wanted this section to look unlike the rest ("something
   unique"), then found the first dark version cheap. This is the second:
   one deep, near-flat ink band with a gold hairline frame, an editorial
   split header (serif title left, lede right, a rule under both), and the
   six products as large light portrait tiles: the renders cover the tile,
   the cut-out pouches sit on a cream plate. Numbered "No 01" like a menu.
   Replaces the .signature / .sig__card grid of section 21, which stays.
   ========================================================================== */
.sig-stage {
  --gold: #e0a531;
  --cream: #f6efe4;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  padding-block: var(--sp-9);
  /* 2026-09-16: light again at the client's request ("black color is not
     looking good"). Was #171110 with a maroon glow; the frame, grain and
     tiles are unchanged. */
  background: var(--sand);
  background-image: radial-gradient(110% 70% at 50% 115%, rgba(224, 165, 49, 0.14), transparent 62%);
  color: var(--ink);
}
.sig-stage::before {                       /* a whisper of the pouch grain */
  content: "";
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  opacity: 0.16; mix-blend-mode: multiply;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.sig-stage::after {                        /* the hairline frame, as on a tin */
  content: "";
  position: absolute; inset: 12px; z-index: -1; pointer-events: none;
  border: 1px solid rgba(138, 88, 9, 0.28);
  border-radius: 6px;
}
@media (min-width: 768px) { .sig-stage::after { inset: 22px; } }

/* Header: title left, lede right, one rule under both */
.sig-stage__head {
  display: grid;
  gap: var(--sp-5);
  margin-bottom: var(--sp-7);
  padding-bottom: var(--sp-6);
  border-bottom: 1px solid var(--line-strong);
}
@media (min-width: 900px) {
  .sig-stage__head { grid-template-columns: 1.15fr 1fr; align-items: end; gap: var(--sp-8); }
}
.sig-stage__eyebrow {
  display: block;
  margin-bottom: var(--sp-4);
  color: var(--gold);
  font-size: 11px; font-weight: 700; letter-spacing: 0.22em; text-transform: uppercase;
}
.sig-stage__title {
  color: var(--ink);
  font-size: var(--step-5);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.02em;
}
.sig-stage__title em { font-style: italic; font-weight: 400; color: var(--turmeric-text); }
.sig-stage__lede {
  max-width: 46ch;
  margin: 0;
  color: var(--ink-soft);
  font-size: var(--step-0);
  line-height: 1.65;
}
@media (min-width: 900px) { .sig-stage__lede { justify-self: end; } }

/* The six tiles */
.sig-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-6) var(--sp-4);
}
@media (min-width: 620px)  { .sig-grid { grid-template-columns: repeat(3, 1fr); gap: var(--sp-7) var(--sp-5); } }
@media (min-width: 1060px) { .sig-grid { gap: var(--sp-7) var(--sp-6); } }

.sig-tile { display: block; color: inherit; text-decoration: none; }
.sig-tile__art {
  display: block;
  position: relative;
  aspect-ratio: 1;
  border-radius: 14px;
  overflow: hidden;
  background: #f1e8d9;
  border: 1px solid var(--line);
  box-shadow: 0 24px 40px -30px rgba(60, 30, 20, 0.45);
  transition: transform 500ms var(--ease), box-shadow 500ms var(--ease);
}
.sig-tile__art::after {                    /* gold ring on hover */
  content: "";
  position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 0 0 1.5px rgba(224, 165, 49, 0);
  transition: box-shadow 400ms var(--ease);
}
.sig-tile__art img {
  display: block; width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 800ms var(--ease);
}
.sig-tile__art--pouch { background: radial-gradient(70% 55% at 50% 42%, #fffaf0, #eee3cf); }
.sig-tile__art--pouch img {
  box-sizing: border-box;
  padding: 9% 12%;
  object-fit: contain;
  filter: drop-shadow(0 20px 22px rgba(60, 30, 20, 0.28));
}
.sig-tile:hover .sig-tile__art, .sig-tile:focus-visible .sig-tile__art {
  transform: translateY(-6px);
  box-shadow: 0 34px 50px -30px rgba(60, 30, 20, 0.55);
}
.sig-tile:hover .sig-tile__art::after { box-shadow: inset 0 0 0 1.5px rgba(224, 165, 49, 0.65); }
.sig-tile:hover .sig-tile__art img { transform: scale(1.04); }
.sig-tile:focus-visible { outline: 2px solid var(--gold); outline-offset: 4px; border-radius: 14px; }
.sig-tile__num {
  position: absolute; left: 12px; top: 12px;
  padding: 5px 11px 4px;
  border: 1px solid rgba(138, 88, 9, 0.22);
  border-radius: var(--radius-pill);
  background: rgba(255, 252, 246, 0.82);
  backdrop-filter: blur(6px);
  color: var(--turmeric-text);
  font-family: var(--font-display);
  font-style: italic;
  font-size: 13px;
  letter-spacing: 0.04em;
  line-height: 1;
}
.sig-tile__num sup { font-size: 0.6em; vertical-align: super; font-style: normal; }
.sig-tile__meta { display: block; padding-top: var(--sp-4); }
.sig-tile__cat {
  display: block;
  color: var(--turmeric-text);
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase;
}
.sig-tile b {
  display: block; margin-top: 6px;
  color: var(--ink);
  font-family: var(--font-display); font-weight: 500;
  font-size: var(--step-2); line-height: 1.15; letter-spacing: -0.01em;
}
.sig-tile small { display: block; margin-top: 4px; font-size: 13px; color: var(--muted); }
@media (max-width: 619px) {
  .sig-tile b { font-size: var(--step-1); }
  .sig-tile__num { left: 8px; top: 8px; padding: 4px 8px 3px; font-size: 11px; }
}

.sig-stage__foot { margin-top: var(--sp-8); border-top-color: var(--line-strong); }
.sig-stage__foot p { color: var(--ink-soft); }
.sig-stage__foot p a { color: var(--brand); }
.btn--on-dark { background: transparent; border-color: rgba(255,255,255,0.55); color: #fff; }
.btn--on-dark:hover { background: rgba(255,255,255,0.08); border-color: #fff; color: #fff; box-shadow: none; }
@media (max-width: 559px) { .sig-stage__foot .btn { width: 100%; } }

/* ==========================================================================
   31b. Spice plates                                              [2026-10-09]
   Kushal (on a call) wanted the Signature range to look amazing; Parth chose
   this from the Awwwards research: La Revoltosa's coloured product cards +
   Bucks Sauce's ingredients bursting out of the pack. Each product sits on a
   plate the colour of its spice; its raw ingredients peek out from behind
   the pack and fly outward on hover/focus (desktop) or when the card is the
   centred one in the swipe row (phone, class .is-live set by ksp.js).
   Each .plate__bit carries its own geometry as unitless custom properties:
   --w width, --x0/--y0/--r0 at rest, --x1/--y1/--r1 burst, all in % of the
   card's width (cqw), measured from the card's centre.
   ========================================================================== */
.plates {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-8) var(--sp-6);
  padding-top: var(--sp-4);
}
@media (min-width: 1060px) { .plates { gap: var(--sp-8) var(--sp-7); } }

.plate { display: block; color: inherit; text-decoration: none; -webkit-tap-highlight-color: transparent; }
.plate__card {
  container-type: inline-size;
  display: block;
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: 22px;
  background:
    radial-gradient(62% 48% at 50% 44%, rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0) 70%),
    var(--plate);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.35),
    0 28px 44px -32px color-mix(in srgb, var(--plate-deep) 70%, transparent);
  transition: transform 600ms var(--ease), box-shadow 600ms var(--ease);
}
.plate__card::before {                     /* the pouch grain, faintly */
  content: "";
  position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: var(--tx-grain);
  opacity: 0.18; mix-blend-mode: multiply;
}
.plate__card::after {                      /* a soft disc under the pack */
  content: "";
  position: absolute; left: 50%; top: 47%;
  width: 70cqw; aspect-ratio: 1;
  border-radius: 50%;
  translate: -50% -50%;
  background: color-mix(in srgb, var(--plate-deep) 22%, transparent);
  scale: 0.9;
  transition: scale 700ms var(--ease);
  pointer-events: none;
}
.plate__pack {
  position: absolute; left: 50%; top: 47%; z-index: 2;
  height: 64%; width: auto; max-width: 62%;
  object-fit: contain;
  translate: -50% -50%;
  filter: drop-shadow(0 22px 20px rgba(50, 25, 10, 0.32));
  transition: transform 700ms var(--ease);
}
.plate--bottle .plate__pack { height: 58%; }
.plate--sachet .plate__pack { height: 60%; }
.plate__bit {
  position: absolute; left: 50%; top: 47%; z-index: 1;
  width: calc(var(--w) * 1cqw); height: auto;
  translate: -50% -50%;
  transform: translate(calc(var(--x0) * 1cqw), calc(var(--y0) * 1cqw)) rotate(var(--r0)) scale(0.82);
  filter: drop-shadow(0 12px 12px rgba(50, 25, 10, 0.28));
  transition: transform 800ms cubic-bezier(0.22, 1.4, 0.36, 1);
  pointer-events: none;
}
.plate__bit--front { z-index: 3; }
.plate__num {
  position: absolute; left: 14px; top: 14px; z-index: 4;
  padding: 5px 11px 4px;
  border-radius: var(--radius-pill);
  background: rgba(255, 252, 246, 0.86);
  color: var(--ink);
  font-family: var(--font-display); font-style: italic;
  font-size: 13px; letter-spacing: 0.04em; line-height: 1;
}
.plate__num sup { font-size: 0.6em; vertical-align: super; font-style: normal; }

/* The burst: hover and keyboard focus on desktop, .is-live on touch */
.plate:hover .plate__card, .plate:focus-visible .plate__card, .plate.is-live .plate__card {
  transform: translateY(-8px);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.35),
    0 40px 56px -30px color-mix(in srgb, var(--plate-deep) 80%, transparent);
}
.plate:hover .plate__card::after, .plate:focus-visible .plate__card::after, .plate.is-live .plate__card::after { scale: 1.06; }
.plate:hover .plate__pack, .plate:focus-visible .plate__pack, .plate.is-live .plate__pack { transform: translateY(-3%) rotate(-3deg) scale(1.05); }
.plate:hover .plate__bit, .plate:focus-visible .plate__bit, .plate.is-live .plate__bit {
  transform: translate(calc(var(--x1) * 1cqw), calc(var(--y1) * 1cqw)) rotate(var(--r1)) scale(1);
}
.plate:focus-visible { outline: none; }
.plate:focus-visible .plate__card { outline: 2px solid var(--plate-deep); outline-offset: 4px; }

.plate__meta { display: block; padding-top: var(--sp-5); text-align: center; }
.plate__cat {
  display: block;
  color: var(--turmeric-text);
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase;
}
.plate b {
  display: block; margin-top: 6px;
  color: var(--ink);
  font-family: var(--font-display); font-weight: 500;
  font-size: var(--step-2); line-height: 1.15; letter-spacing: -0.01em;
}
.plate small { display: block; margin-top: 4px; font-size: 13px; color: var(--muted); }

/* Phone and small tablet: one swipe row, the centred plate bursts */
@media (max-width: 859px) {
  .plates {
    --plate-gutter: 16px;
    display: flex;
    gap: var(--sp-4);
    margin-inline: calc(var(--plate-gutter) * -1);
    padding: var(--sp-5) var(--plate-gutter) var(--sp-3);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--plate-gutter);
    scrollbar-width: none;
  }
  .plates::-webkit-scrollbar { display: none; }
  .plate { flex: 0 0 min(72vw, 300px); scroll-snap-align: center; }
  .plate:first-child { scroll-snap-align: start; }
  .plate:last-child { scroll-snap-align: end; }
  .plate b { font-size: var(--step-1); }
  .plate__num { left: 10px; top: 10px; font-size: 11px; padding: 4px 9px 3px; }
}

@media (min-width: 768px) and (max-width: 859px) { .plates { --plate-gutter: 32px; } }   /* .wrap's gutter there */

@media (prefers-reduced-motion: reduce) {
  .plate__card, .plate__card::after, .plate__pack, .plate__bit { transition: none; }
}

/* ==========================================================================
   32. Private-label banner                                       [2026-09-16]
   Client round 5: "still less visible 'private label'" on Our Range and Bulk
   Supply. One bold brand-red band at the foot of both pages, the words
   PRIVATE LABEL in the display face, the whole thing a link.
   ========================================================================== */
.pl-banner {
  display: grid;
  gap: var(--sp-2);
  margin-top: var(--sp-6);
  padding: var(--sp-6) var(--sp-6);
  border-radius: 18px;
  background: var(--brand);
  background-image: radial-gradient(90% 120% at 100% 0%, rgba(255, 255, 255, 0.14), transparent 60%);
  color: #fff;
  text-decoration: none;
  box-shadow: 0 30px 50px -34px rgba(122, 23, 18, 0.7);
  transition: transform 400ms var(--ease), box-shadow 400ms var(--ease);
}
.pl-banner:hover, .pl-banner:focus-visible { transform: translateY(-3px); box-shadow: 0 40px 60px -34px rgba(122, 23, 18, 0.8); color: #fff; }
.pl-banner:focus-visible { outline: 2px solid var(--gold); outline-offset: 4px; }
.pl-banner__eyebrow { font-size: 11px; font-weight: 700; letter-spacing: 0.22em; text-transform: uppercase; color: #f3d38a; }
.pl-banner__title {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--step-4);
  line-height: 1;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}
.pl-banner__text { font-size: var(--step-0); line-height: 1.5; color: rgba(255, 255, 255, 0.9); }
@media (min-width: 760px) {
  .pl-banner { grid-template-columns: auto 1fr; grid-template-rows: auto auto; column-gap: var(--sp-7); align-items: center; padding: var(--sp-6) var(--sp-8); }
  .pl-banner__eyebrow { grid-column: 1; }
  .pl-banner__title { grid-column: 1; grid-row: 2; }
  .pl-banner__text { grid-column: 2; grid-row: 1 / span 2; max-width: 44ch; justify-self: end; text-align: right; }
}

/* ==========================================================================
   33. The foot of the pouch -- the village strip                   [2026-09-19]
   Client round 6: the Dadi mascot and the pouch design at the bottom of the
   page. First cut was the pack face at full width -- "too big"; what he
   wants is the pack's own ending: the whole page is the pouch and this is
   its foot. So: no band of its own -- the page film continues (the scene's
   cream sky is keyed out), the scene sits at a modest width with its ground
   fading into the film at the sides, the lockup is a small stamp above it,
   and the sealed edge follows. On phones the scene is full width, as on the
   pack. Both images are vector cuts from the packaging SVG at 2x.
   ========================================================================== */
.village {
  position: relative;
  padding: clamp(28px, 4vw, 56px) 0 0;
  text-align: center;
}
.village__mascot {
  display: inline-block;
  width: clamp(120px, 12vw, 168px);
  height: auto;
  margin-bottom: clamp(6px, 1.4vw, 18px);
  filter: drop-shadow(0 10px 18px rgba(120, 60, 20, 0.16));
}
.village__scene {
  /* The asset is the scene with its own hill and earth extended flat on both
     sides (5000 x 1051). One fluid rule, no breakpoints: the height follows the
     viewport (30vw between 300 and 460px) but never exceeds 47.8vw, which is
     the height at which the scene (2.09 x height wide) exactly fills the
     viewport -- so it is never cropped, and on a phone it is edge to edge. */
  display: block;
  width: 100%;
  height: min(max(300px, 36vw), 760px, 47.8vw);   /* ~75% of the width on desktop -- was 30vw/460px, "zoomed out" */
  object-fit: cover;
  object-position: 50% 100%;
}
/* The film's crumple over the earth, the same textures the sealed edge uses
   (§29), multiplied over the scene and fading in from the hills down, so the
   ground reads as print on the pouch film -- "make the texture of this brown
   sand just like its bottom". Sits over the scene only; the mascot above is
   untouched. */
.village::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: min(max(300px, 36vw), 760px, 47.8vw);
  pointer-events: none;
  background-image:
    linear-gradient(180deg, rgba(120, 90, 60, 0) 0%, rgba(120, 90, 60, 0.10) 60%, rgba(120, 90, 60, 0.22) 100%),
    var(--tx-gather),
    var(--tx-folds);
  background-size: auto, 600px 300px, 900px 900px;
  background-blend-mode: normal, multiply, multiply;
  mix-blend-mode: multiply;
  opacity: 0.75;
  /* the earth only -- "the brown sand only, not the whole image": an alpha
     mask built from the scene's own earth and hill colours, placed exactly
     like the scene (scaled to the height, centred), so the women, the pots
     and the huts stay clean */
  -webkit-mask: url("assets/village-ground-mask.png") center bottom / auto 100% no-repeat;
  mask: url("assets/village-ground-mask.png") center bottom / auto 100% no-repeat;
}
/* The sealed edge after the village: the print runs into the pinch, as on
   the real pouch -- the gather takes the ground's earth (#b57146, sampled)
   under its crumple texture, so the scene meets the crimp with no pale
   strip between them. */
.pouch-seal--earth,
.pouch-seal--earth .pouch-seal__gather {
  background-color: #b57146;
}

/* ==========================================================================
   32. Spice Diary posts                                         [2026-10-09]
   The posts moved off Supabase (the project is gone) into the admin panel;
   render.php writes the cards server side, and each card now opens its own
   page, post.html?s=<slug>. The whole card is the link (a stretched ::after
   on the title's link), so the markup stays a plain article.
   ========================================================================== */
.blog-card { position: relative; }
.blog-card h3 a { color: inherit; text-decoration: none; }
.blog-card h3 a::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.blog-card h3 a:focus-visible { outline: none; }
.blog-card:focus-within { outline: 2px solid var(--brand); outline-offset: 3px; }
.blog-card__noimg { aspect-ratio: 3 / 2; background: var(--sand-deep); }

.post { padding-top: clamp(32px, 6vw, 72px); }
.post__wrap { max-width: var(--wrap-narrow); }
.post__eyebrow a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.post__title { font-size: var(--step-5); line-height: 1.08; letter-spacing: -0.02em; margin-top: var(--sp-3); }
.post__date { margin-top: var(--sp-3); color: var(--muted); font-size: var(--step--1); }
.post__date:empty { display: none; }
.post__lede { margin-top: var(--sp-5); }
.post__media { margin: var(--sp-7) 0; }
.post__media:empty { display: none; }
.post__media img { width: 100%; height: auto; border-radius: var(--radius-lg); }
.post__body { font-size: var(--step-0); line-height: 1.8; color: var(--ink-soft); }
.post__body > * + * { margin-top: 1em; }
.post__body h2, .post__body h3 { color: var(--ink); font-size: var(--step-2); margin-top: 1.6em; line-height: 1.2; }
.post__body ul, .post__body ol { padding-left: 1.3em; }
.post__body li + li { margin-top: 0.4em; }
.post__body a { color: var(--brand); }
.post__body blockquote { margin: 1.4em 0; padding-left: 1em; border-left: 3px solid var(--turmeric); font-style: italic; }
.post .section-foot { margin-top: var(--sp-8); }
