/* ============================================================================
   Upali's — design system entry  ·  "Forest & Gold" (sage-green heritage)
   ----------------------------------------------------------------------------
   Architecture (per the 2026 research): the scattered legacy CSS is quarantined
   in a low @layer so it can't fight us; the new brand system is built on top in
   tokens → base → components → util layers. One token redefinition re-skins the
   whole legacy site; overrides stop warring.

   Type:  Fraunces (variable display serif, optical sizing) · Newsreader (body)
          · Bricolage Grotesque (labels / prices).  Cormorant + Montserrat retired.
   Colour: warm Sri Lankan heritage — brick-claret + saffron-turmeric on ivory,
           authored in OKLCH so tints/states stay perceptually even.
   ========================================================================== */

@layer legacy, tokens, base, components, util;

/* Font Awesome lives in the legacy layer so brand layers (and the printed
   theme's own icon-hiding) win over its unlayered display rules. */
@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css") layer(legacy);
@import url("main.css?v=5.6") layer(legacy);
@import url("menu.css?v=4.6") layer(legacy);
@import url("portal-printed.css?v=5.11") layer(legacy);

/* ─────────────────────────────  TOKENS  ───────────────────────────────── */
@layer tokens {
  :root {
    /* primitives — OKLCH · "Field Catalogue": silvery white + sage, mono-led */
    --paper:        oklch(96% 0.004 106);       /* silvery white                */
    --paper-2:      oklch(92.5% 0.006 106);     /* faint silver band            */
    --surface:      oklch(98.5% 0.003 106);     /* raised surface — cards / inputs */
    --ink:          oklch(27% 0.012 92);        /* warm charcoal                */
    --ink-2:        oklch(45% 0.014 100);       /* muted (secondary)            */
    --ink-3:        oklch(52% 0.013 100);       /* faint (metadata) — AA on paper */
    --ink-deep:     oklch(21% 0.011 96);        /* near-black warm charcoal — bands */
    --forest:       oklch(48% 0.062 150);       /* sage — surfaces / buttons    */
    --forest-deep:  oklch(40% 0.058 150);       /* pressed                      */
    --forest-hover: oklch(53% 0.07 150);
    --sage:         oklch(66% 0.045 150);        /* lighter sage — leaders/accents */
    --turmeric:     oklch(43% 0.062 150);       /* sage accent text — AA (4.5+) on paper */
    --turmeric-2:   oklch(46% 0.062 150);
    --rule:         oklch(27% 0.012 92 / .16);  /* neutral hairline             */
    --rule-soft:    oklch(27% 0.012 92 / .10);

    /* type families — JetBrains Mono led, Caveat for hand annotations */
    --font-display: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
    --font-text:    "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
    --font-label:   "JetBrains Mono", ui-monospace, monospace;
    --font-hand:    "Caveat", cursive;

    /* ── remap legacy token names so the whole legacy layer re-skins here ── */
    --font-primary:        var(--font-text);     /* legacy serif → readable body */
    --font-secondary:      var(--font-label);     /* legacy sans  → grotesque     */
    --color-primary:       var(--forest);
    --color-primary-dark:  var(--forest-deep);
    --color-primary-light: var(--sage);
    --color-sage-gradient: var(--forest);
    --color-cream:         var(--paper);
    --color-off-white:     var(--paper-2);
    --color-white:         var(--paper);
    --color-dark:          var(--ink);
    --color-text:          var(--ink);
    --color-text-light:    var(--ink-2);
    --color-text-muted:    var(--ink-3);
    --color-brass:         var(--turmeric);
    --color-forest:        var(--forest);          /* prior "forest" buttons → claret */
    --color-forest-hover:  var(--forest-hover);
    --gold:                var(--turmeric);
    --gold-deep:           var(--turmeric);
    --paper-deep:          var(--paper-2);
    --ink-soft:            var(--ink-2);
    --rule-strong:         var(--rule);

    /* ── Utopia fluid type scale · 360→1240px · 18→20px base · 1.2→1.25 ── */
    --step--1: clamp(0.94rem, 0.91rem + 0.13vw, 1.05rem);
    --step-0:  clamp(1.125rem, 1.08rem + 0.22vw, 1.25rem);
    --step-1:  clamp(1.35rem, 1.27rem + 0.41vw, 1.6rem);
    --step-2:  clamp(1.62rem, 1.48rem + 0.69vw, 2.05rem);
    --step-3:  clamp(1.94rem, 1.72rem + 1.12vw, 2.62rem);
    --step-4:  clamp(2.33rem, 1.97rem + 1.78vw, 3.36rem);
    --step-5:  clamp(2.8rem, 2.24rem + 2.78vw, 4.3rem);
    --step-6:  clamp(3.4rem, 2.5rem + 4.5vw, 5.8rem);

    /* fluid space */
    --space-2xs: clamp(0.5rem, 0.46rem + 0.18vw, 0.63rem);
    --space-xs:  clamp(0.75rem, 0.69rem + 0.27vw, 0.94rem);
    --space-s:   clamp(1rem, 0.93rem + 0.36vw, 1.25rem);
    --space-m:   clamp(1.5rem, 1.39rem + 0.54vw, 1.88rem);
    --space-l:   clamp(2rem, 1.86rem + 0.72vw, 2.5rem);
    --space-xl:  clamp(3rem, 2.79rem + 1.07vw, 3.75rem);
    --space-2xl: clamp(4rem, 3.71rem + 1.43vw, 5rem);
  }

  /* dark mode — warm near-black + SAGE (NOT forest-green canvas, NOT gold accent),
     a true inverse of the silvery-paper light theme. Only primitives flip. */
  [data-theme="dark"] {
    --paper:        oklch(17% 0.006 96);     /* warm near-black canvas   */
    --paper-2:      oklch(21% 0.007 96);
    --surface:      oklch(23% 0.008 96);     /* raised surface — cards / inputs (dark) */
    --ink:          oklch(91% 0.012 96);     /* warm off-white text      */
    --ink-2:        oklch(72% 0.013 96);
    --ink-3:        oklch(56% 0.013 96);
    --ink-deep:     oklch(11% 0.005 96);     /* darkest — bands grounded */
    --forest:       oklch(62% 0.078 150);    /* lifted sage for dark     */
    --forest-deep:  oklch(52% 0.072 150);
    --forest-hover: oklch(70% 0.088 150);
    --sage:         oklch(70% 0.06 150);
    --turmeric:     oklch(66% 0.06 150);     /* sage accent (no gold)    */
    --turmeric-2:   oklch(74% 0.055 150);
    --rule:         oklch(90% 0.01 96 / .16);
    --rule-soft:    oklch(90% 0.01 96 / .09);
  }
}

/* ──────────────────────────────  BASE  ────────────────────────────────── */
@layer base {
  body {
    background: var(--paper);
    color: var(--ink);
    font-family: var(--font-text);
    font-size: var(--step-0);
    line-height: 1.6;
    font-optical-sizing: auto;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    font-variant-numeric: oldstyle-figures proportional-nums;  /* warm prose figures */
  }

  h1, h2, h3, .hero-title, .section-title, .featured-item-name {
    font-family: var(--font-display);
    font-optical-sizing: auto;
    text-wrap: balance;
    letter-spacing: -0.01em;
  }
  p { text-wrap: pretty; }

  ::selection { background: var(--turmeric); color: #1a120a; }

  a { color: var(--forest); }

  /* film-grain / paper atmosphere — a single fixed, GPU-cheap overlay.
     Procedural SVG noise, no image asset. Subtle multiply over the whole page. */
  body::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 50;
    pointer-events: none;
    opacity: 0.05;
    mix-blend-mode: multiply;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size: 160px 160px;
  }
  [data-theme="dark"] body::after { mix-blend-mode: screen; opacity: 0.04; }
  @media (prefers-reduced-motion: reduce) { body::after { opacity: 0.035; } }
}

/* ───────────────────────────  COMPONENTS  ─────────────────────────────── */
@layer components {

  /* ── top utility bar + header ── */
  .top-bar { background: var(--ink-deep); border-bottom: 1px solid oklch(100% 0 0 / .08); font-style: normal; }
  .header-content .logo,
  .logo {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 500;
    font-size: clamp(1.55rem, 2.4vw, 2rem);
    letter-spacing: 0;
    color: var(--ink);
    line-height: 1;
  }
  .nav-link, .header .nav a { font-family: var(--font-label); font-size: 0.86rem; letter-spacing: 0.02em; }

  /* ── HERO — asymmetric editorial, type anchored lower-left (kills the
        centered-over-dimmed-photo template formula) ── */
  .hero {
    align-items: flex-end;
    justify-content: flex-start;
    min-height: 86vh;
    height: auto;
    max-height: 960px;
  }
  .hero-overlay {
    background:
      linear-gradient(102deg, oklch(18% 0.03 38 / 0.74) 0%, oklch(18% 0.03 38 / 0.18) 50%, transparent 76%),
      linear-gradient(to top, oklch(14% 0.03 38 / 0.85) 0%, oklch(14% 0.03 38 / 0.1) 42%, transparent 60%);
  }
  .hero-content {
    text-align: left;
    align-items: flex-start;
    max-width: min(40rem, 92vw);
    margin: 0;
    padding: 0 0 clamp(2.5rem, 6vw, 5rem) clamp(1.5rem, 6vw, 5.5rem);
  }
  .hero-subtitle {
    font-family: var(--font-label);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.34em;
    text-transform: uppercase;
    color: var(--turmeric-2);
    margin-bottom: 0.9rem;
  }
  .hero-title {
    font-family: var(--font-display);
    font-weight: 470;
    font-style: normal;
    font-size: var(--step-6);
    /* was line-height:0.9 — too tight: the display font's caps (≈1.11em) overflowed
       the line-box and got clipped at the top by `.hero { overflow:hidden }`. The title
       is always one line ("Upali's"), so a fuller line-box + small top pad costs nothing
       visually and contains the glyphs at every viewport. (Ryan, 2026-06-04) */
    line-height: 1;
    padding-top: 0.16em;
    letter-spacing: -0.025em;
    color: #FBF3E4;
    margin: 0 0 0.7rem;
    text-shadow: 0 2px 36px rgba(0,0,0,0.4);
  }
  .hero-tagline {
    font-family: var(--font-text);
    font-style: italic;
    font-weight: 400;
    font-size: var(--step-1);
    line-height: 1.3;
    color: rgba(251,243,228,0.9);
    max-width: 26ch;
    margin: 0 0 clamp(1.5rem, 3vw, 2.2rem);
  }
  .hero-features { justify-content: flex-start; align-items: center; gap: 0; margin: 0 0 clamp(1.6rem, 3vw, 2.4rem); flex-wrap: wrap; }
  .hero-feature {
    font-family: var(--font-label);
    font-size: 0.7rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: rgba(251,243,228,0.78);
    gap: 0;
  }
  .hero-feature i { display: none; }
  .hero-feature:not(:first-child)::before { content: "·"; color: var(--turmeric-2); margin: 0 0.85rem; opacity: 0.9; }
  .hero .btn.btn-primary {
    background: var(--forest);
    color: #FBF3E4;
    border: 1px solid var(--turmeric-2);
    border-radius: 2px;
    padding: 0.95rem 2rem;
    font-family: var(--font-label);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    box-shadow: 0 14px 34px -14px rgba(0,0,0,0.55);
  }
  .hero .btn.btn-primary:hover { background: var(--forest-hover); transform: translateY(-2px); }

  /* ── section headers ── */
  .section-label, .section-header .section-label {
    font-family: var(--font-label);
    font-weight: 600;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: var(--turmeric);
    font-size: 0.74rem;
  }
  .section-title { font-family: var(--font-display); font-weight: 500; letter-spacing: -0.015em; }

  /* ── printed editorial menu — real typesetting ── */
  body.theme-printed .menu-item-name {
    font-family: var(--font-display);
    font-weight: 500;
    font-style: normal;
    font-optical-sizing: auto;
    letter-spacing: -0.005em;
  }
  body.theme-printed .menu-item-price {
    font-family: var(--font-label);
    font-variant-numeric: tabular-nums lining-nums;   /* prices align in a column */
    letter-spacing: 0.01em;
    color: var(--forest);
    font-weight: 600;
  }
  body.theme-printed .menu-item-description {
    font-family: var(--font-text);
    font-style: italic;
    font-variant-numeric: oldstyle-figures;
  }
  body.theme-printed .category-tab { font-family: var(--font-text); }
  body.theme-printed .category-tab.active { color: var(--forest); }

  /* signature carousel + order-type */
  .featured-label { font-family: var(--font-label); background: var(--turmeric); color: #1d1408; letter-spacing: 0.14em; }
  .featured-item-name { font-family: var(--font-display); }
  body.theme-printed .order-type-btn .type-title { font-family: var(--font-display); }
  body.theme-printed .order-type-btn.active .type-title { color: var(--forest); }
  body.theme-printed .order-type-btn .type-desc { font-family: var(--font-label); }

  /* ── footer ── */
  .footer { background: var(--ink-deep); }
  .footer-brand, .footer h3, .footer h4 { font-family: var(--font-display); }

  /* ── buttons (non-hero) inherit claret via legacy token edit; refine type ── */
  .btn, .btn-primary, .order-type-btn, .checkout-btn { font-family: var(--font-label); letter-spacing: 0.04em; }
}

/* ───────────────────────────────  UTIL  ──────────────────────────────── */
@layer util {
  .u-tabular { font-variant-numeric: tabular-nums lining-nums; }
  .u-balance { text-wrap: balance; }
}

/* ════════════════════════════════════════════════════════════════════════
   MODERN LAYER — contemporary energy on the heritage base: a kinetic brand
   ribbon, a dark cinematic Signature band, oversized broken-grid headers.
   ════════════════════════════════════════════════════════════════════════ */
@layer components {

  /* ── Kinetic brand marquee ── */
  .brand-marquee {
    background: var(--ink-deep);
    overflow: hidden;
    border-block: 1px solid color-mix(in oklch, var(--turmeric) 28%, transparent);
    padding: clamp(0.6rem, 1.4vw, 1rem) 0;
    /* edge fade removed per Ryan (2026-06-04): no side fades anywhere on the site.
       overflow:hidden still clips the scrolling track cleanly at the band edges. */
  }
  .brand-marquee__track {
    display: inline-flex;
    align-items: center;
    gap: clamp(1.4rem, 3vw, 2.6rem);
    white-space: nowrap;
    will-change: transform;
    animation: up-marquee 38s linear infinite;
  }
  .brand-marquee:hover .brand-marquee__track { animation-play-state: paused; }
  .brand-marquee span:not(.dot) {
    font-family: var(--font-label);
    text-transform: uppercase;
    font-weight: 600;
    font-size: clamp(0.95rem, 2vw, 1.5rem);
    letter-spacing: 0.14em;
    color: color-mix(in oklch, var(--turmeric) 88%, #fff);
  }
  .brand-marquee .dot { color: var(--turmeric); font-size: 0.7em; opacity: 0.8; }
  @keyframes up-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
  @media (prefers-reduced-motion: reduce) { .brand-marquee__track { animation: none; transform: translateX(-2%); } }

  /* ── Dark cinematic Signature band — breaks the all-light rhythm ── */
  .featured-section {
    background:
      radial-gradient(120% 90% at 85% 0%, oklch(34% 0.05 150 / 0.6), transparent 60%),
      linear-gradient(180deg, oklch(23% 0.028 150), oklch(18% 0.024 152));
    color: oklch(92% 0.02 95);
    position: relative;
  }
  .featured-section .section-header { text-align: left; max-width: 1180px; margin-inline: auto; }
  .featured-section .section-label { color: var(--turmeric-2); }
  .featured-section .section-title {
    color: var(--ink);                 /* was cream for a dark band — paper now, so ink */
    font-size: var(--step-5);
    letter-spacing: -0.025em;
    margin-top: 0.2rem;
  }
  .featured-section .section-title::after { display: none; }   /* drop the centered swash rule */
  .featured-section .section-desc { color: var(--ink-2); margin-inline: 0; max-width: 42ch; }
  /* the cards stay cream so they read like plates on a dark table (both themes) */
  .featured-section .featured-item-card { background: #F4ECDB; box-shadow: 0 24px 60px -28px rgba(0,0,0,0.7); }
  .featured-section .featured-item-name,
  .featured-section .featured-item-content,
  .featured-section .featured-item-content :not(.featured-label):not(.featured-add-btn) { color: #21291f; }
  .featured-section .featured-item-price { color: var(--forest); }

  /* ── Oversized display — give the editorial type more contemporary scale ── */
  .hero-title { font-weight: 480; letter-spacing: -0.03em; }
  .menu-section .section-header .section-title { font-size: var(--step-4); }

  /* keep every Signature card fully lit — the carousel dims off-focus slides,
     which read as a broken/greyed card on the dark band */
  .featured-section .featured-item-card,
  .featured-section .carousel-track > * { opacity: 1 !important; filter: none !important; }

  /* ════════════════════ THE TASTING JOURNEY — category chapters ════════════ */
  #menuGrid { display: block; }                 /* chapters stack full-width, not a card grid */
  .chapter { position: relative; padding-block: clamp(2.5rem, 6vw, 5.5rem); }
  .chapter + .chapter { border-top: 1px solid var(--rule); }

  .chapter-head {
    max-width: 1080px;
    margin: 0 auto;
    padding-inline: clamp(1.2rem, 4vw, 2rem);
  }
  .chapter-index {
    display: block;
    font-family: var(--font-label); font-weight: 600;
    font-size: 0.74rem; letter-spacing: 0.3em; text-transform: uppercase;
    color: var(--turmeric); margin-bottom: 0.7rem;
  }
  .chapter-title {
    font-family: var(--font-display); font-weight: 480; font-optical-sizing: auto;
    font-size: var(--step-5); line-height: 0.98; letter-spacing: -0.025em;
    color: var(--ink); margin: 0; text-wrap: balance;
  }
  .chapter-lede {
    font-family: var(--font-text); font-style: italic; color: var(--ink-2);
    font-size: var(--step-1); line-height: 1.4; max-width: 46ch; margin: 0.9rem 0 0;
  }
  .chapter-count {
    display: inline-block; margin-top: 1rem;
    font-family: var(--font-label); font-size: 0.7rem; letter-spacing: 0.16em;
    text-transform: uppercase; color: var(--ink-3);
  }

  /* cinematic photo band — the category's hero dish, full container width */
  .chapter-plate {
    height: clamp(220px, 40vh, 440px);
    margin: clamp(1.6rem, 4vw, 2.6rem) auto 0;
    max-width: 1280px;
    background-size: cover; background-position: center;
    position: relative; overflow: hidden;
    border-radius: 2px;
  }
  .chapter-plate::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(180deg, oklch(20% 0.03 150 / 0.05), oklch(18% 0.03 150 / 0.3));
  }

  .chapter-dishes {
    max-width: 1080px; margin: clamp(1.6rem, 4vw, 2.6rem) auto 0;
    padding-inline: clamp(1.2rem, 4vw, 2rem);
  }
}

/* ──────────────────────────  MOTION + FIXES  ──────────────────────────── */
@layer base {
  /* hero is ALWAYS visible — the entrance fade was removed ("i dont like the
     fades"); the .has-motion hide is neutralised here so there's never a fade-in. */
  .has-motion .hero-content { opacity: 1; }
  .hero-content, .hero-carousel { will-change: transform; }
}

@layer components {
  /* leftover-green cleanup — carousel pager + any sage that slipped the tokens */
  .carousel-dot { background: var(--rule); }
  .carousel-dot.active, .carousel-dots .active { background: var(--forest); }

  /* candlelit dark mode: flip the cards that carry an explicit light surface so
     the token-driven ink stays legible (fixes the low-contrast Signature cards). */
  [data-theme="dark"] .featured-item-card,
  [data-theme="dark"] .card,
  [data-theme="dark"] .delivery-panel,
  [data-theme="dark"] .order-summary { background: var(--paper-2); border-color: var(--rule); }
  [data-theme="dark"] .featured-item-name,
  [data-theme="dark"] .featured-item-content,
  [data-theme="dark"] .featured-item-content * { color: var(--ink); }
  [data-theme="dark"] .featured-item-price { color: var(--turmeric); }
  /* The cream-plate text colour (#21291f, set for the LIGHT Signature card) is more
     specific (0,4,0) than the plain dark override above, so on the candlelit (dark)
     card the description / price / "Add to Order" render dark-on-dark — unreadable.
     Re-assert legible ink at higher specificity (html[] prefix + the :not chain → 0,4,1)
     so all Signature text is readable in dark. Light mode (dark-on-cream) is untouched. */
  html[data-theme="dark"] .featured-section .featured-item-name,
  html[data-theme="dark"] .featured-section .featured-item-content,
  html[data-theme="dark"] .featured-section .featured-item-content :not(.featured-label) { color: var(--ink); }
}

/* ───────────────────  ARRIVAL CUE + STICKY ORDER BAR  ─────────────────── */
@layer components {
  /* ── Hero "arrival" cue — a quiet invitation to begin the descent. Sits at
        the foot of the hero, fades away the moment you start scrolling. ── */
  .hero-scroll {
    position: absolute; left: 50%; bottom: clamp(1.4rem, 4vh, 2.6rem);
    transform: translateX(-50%);
    display: inline-flex; flex-direction: column; align-items: center; gap: 0.7rem;
    text-decoration: none; z-index: 3;
  }
  .hero-scroll__label {
    font-family: var(--font-label); font-weight: 600;
    font-size: 0.66rem; letter-spacing: 0.34em; text-transform: uppercase;
    color: oklch(95% 0.02 84 / 0.9);
  }
  .hero-scroll__line {
    width: 1px; height: 44px; overflow: hidden;
    background: oklch(95% 0.02 84 / 0.25); position: relative;
  }
  .hero-scroll__line::after {
    content: ""; position: absolute; left: 0; top: -60%;
    width: 100%; height: 60%; background: var(--turmeric-2);
  }
  @media (prefers-reduced-motion: no-preference) {
    .hero-scroll__line::after { animation: hero-scroll-drop 2.1s cubic-bezier(.7,0,.3,1) infinite; }
  }
  @keyframes hero-scroll-drop {
    0%   { transform: translateY(0); opacity: 0; }
    25%  { opacity: 1; }
    100% { transform: translateY(166%); opacity: 0; }
  }

  /* ── Sticky order bar — your table travels with you down the journey.
        Hidden until the cart has something in it (body.has-order). ── */
  .order-bar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    background: var(--ink-deep); color: oklch(95% 0.02 84);
    border-top: 1px solid color-mix(in oklch, var(--turmeric) 32%, transparent);
    box-shadow: 0 -12px 44px -18px rgba(0,0,0,0.55);
    transform: translateY(110%);
    transition: transform 0.42s cubic-bezier(0.22, 0.61, 0.36, 1);
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  body.has-order .order-bar { transform: none; }
  .order-bar__inner {
    max-width: 1180px; margin: 0 auto;
    display: flex; align-items: center; gap: clamp(0.9rem, 3vw, 1.6rem);
    padding: 0.8rem clamp(1.1rem, 4vw, 2rem);
  }
  .order-bar__meta { display: flex; flex-direction: column; line-height: 1.15; margin-right: auto; min-width: 0; }
  .order-bar__label {
    font-family: var(--font-label); font-weight: 600;
    font-size: 0.6rem; letter-spacing: 0.24em; text-transform: uppercase;
    color: var(--turmeric-2);
  }
  .order-bar__count {
    font-family: var(--font-display); font-style: italic; font-weight: 450;
    font-size: clamp(1.05rem, 2.6vw, 1.3rem); line-height: 1.1;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .order-bar__total {
    font-family: var(--font-label); font-weight: 600; font-variant-numeric: tabular-lining;
    font-size: clamp(0.95rem, 2.4vw, 1.15rem); letter-spacing: 0.01em; white-space: nowrap;
  }
  .order-bar__btn {
    flex: none; cursor: pointer; border: none; border-radius: 2px;
    background: var(--turmeric); color: oklch(22% 0.04 70);
    font-family: var(--font-label); font-weight: 700;
    font-size: 0.74rem; letter-spacing: 0.13em; text-transform: uppercase;
    padding: 0.72rem clamp(1rem, 3vw, 1.5rem);
    display: inline-flex; align-items: center; gap: 0.5rem;
    transition: background 0.18s ease, transform 0.18s ease;
  }
  .order-bar__btn:hover { background: var(--turmeric-2); }
  .order-bar__btn:active { transform: translateY(1px); }
  @media (max-width: 540px) { .order-bar__total { display: none; } }

  /* lift the chat launcher above the order bar when it's showing */
  body.has-order #upChatLauncher { bottom: 88px !important; }
}

/* ============================================================================
   MOBILE APP SHELL — a fixed bottom tab bar gives phones a native-app feel.
   Desktop is untouched (the bar is display:none above the phone breakpoint).
   Unlayered, so it wins the legacy @layer cascade.
   ========================================================================== */
.app-tabbar { display: none; }

@media (max-width: 640px) {
  /* room so content never hides behind the fixed tab bar (+ the home indicator) */
  body { padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }

  .app-tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 200;
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
    background: color-mix(in oklch, var(--ink-deep) 86%, #000 14%);
    -webkit-backdrop-filter: blur(16px) saturate(1.2);
            backdrop-filter: blur(16px) saturate(1.2);
    border-top: 1px solid color-mix(in oklch, var(--turmeric) 20%, transparent);
    box-shadow: 0 -12px 32px -18px rgba(0, 0, 0, 0.7);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .app-tab {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; min-height: 56px; padding: 6px 2px 4px;
    text-decoration: none; border: none; background: transparent; cursor: pointer;
    color: var(--ink-soft);
    font-family: var(--font-label); font-size: 0.56rem; font-weight: 600;
    letter-spacing: 0.07em; text-transform: uppercase;
    position: relative; -webkit-tap-highlight-color: transparent;
    transition: color 0.18s ease, transform 0.12s ease;
  }
  .app-tab i { font-size: 1.18rem; line-height: 1; }
  .app-tab:active { color: var(--ink); transform: scale(0.94); }
  .app-tab.is-active { color: var(--turmeric); }
  .app-tab.is-active::before {
    content: ""; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
    width: 26px; height: 2px; border-radius: 0 0 2px 2px; background: var(--turmeric);
  }
  .app-tab--cart i { color: var(--turmeric); }
  .app-tab__badge {
    position: absolute; top: 5px; left: calc(50% + 7px);
    min-width: 16px; height: 16px; padding: 0 4px; border-radius: 9px;
    background: var(--turmeric); color: #1a120a;
    font-family: var(--font-label); font-size: 0.6rem; font-weight: 800;
    line-height: 16px; text-align: center;
  }

  /* the slide-up cart bar must sit ABOVE the tab bar, not behind it */
  .order-bar { bottom: calc(56px + env(safe-area-inset-bottom, 0px)); padding-bottom: 0; }
  body.has-order { padding-bottom: calc(118px + env(safe-area-inset-bottom, 0px)); }

  /* float the chat launcher above the tab bar (and the order bar when shown) */
  /* Mobile: the chat launcher folds INTO the bottom tab bar (the "Chat" tab),
     so hide the floating bubble. The chat panel still opens from the tab and
     sits full-width just above the bar. */
  #upChatLauncher { display: none !important; }
  #uchatPanel {
    bottom: calc(64px + env(safe-area-inset-bottom, 0px)) !important;
    left: 8px !important; right: 8px !important; width: auto !important; max-width: none !important;
  }
}

/* ============================================================================
   NATIVE-APP MOBILE POLISH — hide-on-scroll header + bottom-sheet cart.
   Unlayered so these win over the legacy @layer (main.css / menu.css).
   ========================================================================== */
@media (max-width: 640px) {
  /* Header slides away on scroll-down, returns on scroll-up (theme.js toggles
     .header-hidden). Only transform animates; the sticky slot is unchanged. */
  .header {
    transition: transform 0.34s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s ease;
    will-change: transform;
  }
  .header.header-hidden { transform: translateY(-100%); }

  /* Cart: right-side drawer → bottom sheet (thumb-natural slide-up + grabber). */
  .cart-panel {
    top: auto; bottom: 0; left: 0; right: 0;
    width: 100%; max-width: 100%;
    height: auto; max-height: 86dvh;
    border-radius: 18px 18px 0 0;
    transform: translateY(110%);
    box-shadow: 0 -18px 44px -16px rgba(0, 0, 0, 0.5);
    overscroll-behavior: contain;
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .cart-panel.active { transform: translateY(0); }
  .cart-panel::before {
    content: ""; position: absolute; top: 8px; left: 50%; transform: translateX(-50%);
    width: 40px; height: 4px; border-radius: 999px;
    background: rgba(255, 255, 255, 0.35); z-index: 3; pointer-events: none;
  }
  .cart-header { border-radius: 18px 18px 0 0; padding-top: 22px; }
  .cart-body { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
}
@media (prefers-reduced-motion: reduce) {
  .header { transition: none; }
  .header.header-hidden { transform: none; }   /* never hide when motion-reduced */
  .cart-panel { transition: none; }
}

/* ============================================================================
   FIELD CATALOGUE ground — unlayered so it wins the legacy @layer cascade.
   Silvery-white surfaces everywhere; sage stays the single accent (via tokens).
   ========================================================================== */
html, body, body.theme-printed { background: var(--paper); color: var(--ink); }
/* Sticky footer: short pages (track, confirmation) were leaving a canvas gap below
   the footer that rendered as a stray dark band. Pin the footer to the viewport
   bottom so content fills and there's never a gap. Long pages are unaffected. */
body.theme-printed { min-height: 100dvh; display: flex; flex-direction: column; }
body.theme-printed > .site-footer { margin-top: auto; }
.menu-section, .featured-section, .order-type-section, .status-bar, main, .chapter { background: var(--paper); }
/* Cart sheet header is a dark structural band in BOTH themes (like the top bar /
   footer). The legacy --color-dark/--color-white tokens INVERT in dark mode, which
   left it light-on-light (the "Your Order" title vanished). Pin to the stable band
   tokens so it's a charcoal band with light text in both modes; icon keeps the sage. */
.cart-header { background: var(--ink-deep); }
.cart-header h3, .cart-close { color: oklch(95% 0.02 84); }
.cart-header h3 i { color: var(--sage); }
.card, input, select, textarea, .menu-item-card, .featured-item-card { background: var(--surface); color: var(--ink); }

/* ── sub-pages (reservations / track / confirmation / error) ──
   These link app.css but carry bespoke CSS (reservations.css / pages.css /
   checkout.css) with leftover green hero bands and floating drop-shadow cards.
   Those sheets are unlayered AND load after app.css, so we out-specify them
   with a body.theme-printed prefix (every sub-page now carries that class).
   Normalise to the printed aesthetic: paper heroes with an ink heading +
   hairline rule, flat hairline panels. Sage stays reserved for buttons + the
   progress bar (kept via their own tokens). */
body.theme-printed .reservation-hero,
body.theme-printed .order-header,
body.theme-printed .confirmation-card-header {
  background: var(--paper); color: var(--ink);
  border-bottom: 1px solid var(--rule); box-shadow: none;
}
body.theme-printed .reservation-hero::before,
body.theme-printed .order-header::before,
body.theme-printed .confirmation-card-header::before { display: none; }
body.theme-printed .reservation-hero h1, body.theme-printed .reservation-hero p,
body.theme-printed .order-header h1, body.theme-printed .order-header h2,
body.theme-printed .order-header p, body.theme-printed .order-header span,
body.theme-printed .confirmation-card-header h1,
body.theme-printed .confirmation-card-header h2,
body.theme-printed .confirmation-card-header p { color: var(--ink); }
/* a quiet ink numeral, not a green slab */
body.theme-printed .error-code { background: none; color: var(--ink); -webkit-text-fill-color: currentColor; }
/* flatten floating cards → printed hairline panels */
body.theme-printed .res-card, body.theme-printed .track-card,
body.theme-printed .order-card, body.theme-printed .confirmation-card,
body.theme-printed .error-card, body.theme-printed .status-card,
body.theme-printed .res-status-card {
  box-shadow: none; border: 1px solid var(--rule); border-radius: 3px;
}
body.theme-printed .res-card-header i, body.theme-printed .res-card-header h2 { color: var(--ink); }

/* ── Mask-Catalogue flourishes — hand-drawn sage underline + Caveat margin notes.
   Pure CSS (no menu markup change → SSR stays byte-identical to the hydrate).
   Restraint: a marker stroke under chapter headings + signature prices only,
   two handwritten annotations (hero + the signature chapter). ── */
/* inline-block so the box hugs the TEXT (the heading is text-align:center); the
   underline then tracks the actual words instead of anchoring to the full-width
   block's left edge — fixes the stroke sitting under "Signature" only. (Ryan, 2026-06-04) */
.chapter-title { position: relative; display: inline-block; }
.chapter-title::after,
.menu-item-card:has(.badge-signature) .menu-item-price::after {
  content: ""; position: absolute; left: 0; bottom: -0.45rem;
  width: 100%; height: 7px; pointer-events: none; opacity: 0.8;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='7' viewBox='0 0 240 7' preserveAspectRatio='none'%3E%3Cpath d='M1 4 C 30 1.5, 60 6, 92 3.4 S 150 1.8, 188 4.2 S 226 5.5, 239 3' fill='none' stroke='%234e6a45' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat;
  background-size: 100% 100%;
}
.menu-item-card:has(.badge-signature) .menu-item-price { position: relative; }
.menu-item-card:has(.badge-signature) .menu-item-price::after { width: 100%; bottom: -0.3rem; opacity: 0.7; }

/* handwritten margin notes (Caveat, sage) */
.hero-annot {
  font-family: var(--font-hand); color: var(--forest); font-weight: 600;
  font-size: clamp(1.35rem, 3.6vw, 2.2rem); line-height: 1;
  /* "since 1979" reads as a unit with the title (tight above) but must clear the
     tagline below — was margin-bottom:0 so it collided with "Premium Sri Lankan…".
     transform-origin:left keeps the rotation from drifting the text leftward. (2026-06-04) */
  display: inline-block; transform: rotate(-5deg); transform-origin: left center;
  margin: 0.35rem 0 1.05rem;
}
#chapter-signature-dishes .chapter-head { position: relative; }
#chapter-signature-dishes .chapter-head::after {
  content: "the ones we're known for"; font-family: var(--font-hand);
  color: var(--forest); font-weight: 600; font-size: clamp(1.1rem, 2.6vw, 1.6rem);
  line-height: 0.95; position: absolute; right: 2%; top: -0.4rem;
  transform: rotate(-6deg); pointer-events: none; max-width: 36%; text-align: center;
}
@media (max-width: 760px) {
  #chapter-signature-dishes .chapter-head::after {
    position: static; display: block; transform: rotate(-3deg);
    margin-top: 0.4rem; right: auto; max-width: none; text-align: left;
  }
}
@media (prefers-reduced-motion: no-preference) {
  .chapter-title::after { transition: width 0.5s cubic-bezier(0.2, 0.6, 0.3, 1); }
}

/* ── Signature section: NO carousel/swipe. The Mask Catalogue has no carousels —
   this is a clean faded editorial column. Must beat main.css's
   `flex-direction:row !important` (legacy layer), so we go unlayered + important.
   The carousel JS is also bailed for theme-printed (lang-switch.js); these rules
   neutralise any chrome that a cached build may have injected. ── */
body.theme-printed .carousel-wrap { display: contents; }
body.theme-printed .carousel-btn,
body.theme-printed .carousel-dots { display: none !important; }
body.theme-printed .featured-grid {
  display: flex !important; flex-direction: column !important; overflow: visible !important;
  max-width: 660px; margin: 1.6rem auto 0; gap: 0; cursor: auto !important;
  scroll-snap-type: none !important; -webkit-mask-image: none !important; mask-image: none !important;
}
body.theme-printed .featured-grid > *,
body.theme-printed .featured-item-card {
  width: auto !important; min-width: 0 !important; flex: 0 0 auto !important;
  scroll-snap-align: none !important; white-space: normal; transform: none !important;
  background: transparent !important; border: none !important; box-shadow: none !important;
  border-radius: 0 !important; padding: 1.5rem 0 !important; text-align: left;
}
body.theme-printed .featured-grid > *:not(:last-child),
body.theme-printed .featured-item-card:not(:last-child) { border-bottom: 1px solid var(--rule) !important; }
/* drop the green placeholder image block + corner badge → text-led printed row */
body.theme-printed .featured-item-image { display: none !important; }
/* (the Signature column fade-in was removed — content is just present) */

/* ── No entrance/scroll FADES (Ryan: "i dont like the fades"). Force every
   reveal-class element visible so reveal.js / leftover CSS never fade content in.
   Unlayered beats the legacy-layer reveal states (which are normal, not !important). ── */
.reveal, .card-animate, .reveal-up,
.featured-section .section-header, .carousel-wrap {
  opacity: 1 !important;
  transform: none !important;
  animation: none !important;
  transition: none !important;
}

/* ── dark mode: retire the legacy [data-theme=dark] cool-grey / green hardcodes
   and point them at the warm-charcoal + sage tokens so dark mode is coherent.
   Unlayered beats the legacy layer (normal declarations). ── */
[data-theme="dark"] .site-footer { background: var(--ink-deep); }
[data-theme="dark"] .featured-section,
[data-theme="dark"] .delivery-info-section,
[data-theme="dark"] .order-type-section,
[data-theme="dark"] .menu-section { background: var(--paper); }
[data-theme="dark"] .featured-section::before { background: none; }
[data-theme="dark"] .section-title,
[data-theme="dark"] .featured-item-name,
[data-theme="dark"] .delivery-panel-header .section-title,
[data-theme="dark"] .logo { color: var(--ink); }
[data-theme="dark"] .section-desc { color: var(--ink-2); }
[data-theme="dark"] .section-label { color: var(--turmeric-2); }

/* ── a11y: AA text contrast (Lighthouse). Token-based so both modes stay safe. ── */
.search-input, #menuSearch, #deliveryAreaSelector, #deliveryAreaSelector select,
.order-type-wrapper select, .menu-filters select { color: var(--ink); }
.search-input::placeholder, #menuSearch::placeholder { color: var(--ink-2); opacity: 1; }
.chapter-count { color: var(--ink-2); }
body.theme-printed .order-type-btn, body.theme-printed .order-type-btn .type-title { color: var(--ink); }
body.theme-printed .order-type-btn.active .type-title { color: var(--forest-deep); }
[data-theme="dark"] body.theme-printed .order-type-btn.active .type-title { color: var(--sage); } /* lighter sage on the dark canvas */
body.theme-printed .order-type-btn .type-desc { color: var(--ink-2); opacity: 1; }  /* was opacity .7 → failed AA */
/* marquee text rides the charcoal band — needs a LIGHT sage, not the darkened label sage */
.brand-marquee span:not(.dot) { color: oklch(80% 0.06 150); }

/* ── retire the heritage ❦ fleurons — the catalogue uses hairlines + hand-drawn
   notes, not dingbats. (unlayered normal beats the legacy-layer content) ── */
body.theme-printed .reservation-hero::after,
body.theme-printed .order-type-wrapper::before,
body.theme-printed .menu-section + .menu-section::before,
body.theme-printed .featured-section + .menu-section::before,
body.theme-printed .res-status-card h3::before { content: none; }

/* reservations: match the home — ink heading + a centered hand-drawn sage
   underline, plus one handwritten margin note for warmth. */
body.theme-printed .reservation-hero h1 { position: relative; display: inline-block; color: var(--ink); }
body.theme-printed .reservation-hero h1::before {
  content: ""; position: absolute; left: 50%; transform: translateX(-50%); bottom: -0.5rem;
  width: min(82%, 460px); height: 7px; pointer-events: none; opacity: 0.8;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='7' viewBox='0 0 240 7' preserveAspectRatio='none'%3E%3Cpath d='M1 4 C 30 1.5, 60 6, 92 3.4 S 150 1.8, 188 4.2 S 226 5.5, 239 3' fill='none' stroke='%234e6a45' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat;
  background-size: 100% 100%;
}
body.theme-printed .res-card-header { position: relative; }
body.theme-printed .res-card-header::after {
  content: "we'll call to confirm"; font-family: var(--font-hand); color: var(--forest);
  font-weight: 600; font-size: clamp(1rem, 2.4vw, 1.45rem); line-height: 0.95;
  position: absolute; right: 1.25rem; bottom: 0.45rem; top: auto;
  transform: rotate(-4deg); transform-origin: right bottom; white-space: nowrap; pointer-events: none;
}
@media (max-width: 760px) {
  /* below the title, centered, in normal flow — never clips on small cards */
  body.theme-printed .res-card-header::after { position: static; display: block; text-align: center; transform: rotate(-3deg); margin-top: 0.3rem; right: auto; bottom: auto; }
}
