@charset "utf-8";
/* Zen Pizza — Port Orange, FL
   Palette taken off their own wall: the teal of the dining room, the gold of
   the crust, ink for type.  All type in rem so browser text-resize works. */

:root{
  --ink:#12262c;
  --ink-2:#42585f;
  --sea:#0b5566;          /* deep teal — 8.9:1 on --sand */
  --sea-2:#0e7c93;
  --surf:#57c3d4;         /* decoration only -- 4.06:1 on --sea, under AA */
  --surf-t:#7ad5e2;       /* the text-safe one: 4.97:1 on --sea */
  --surf-p:#d6f1f6;       /* paler still, for type over the photograph */
  --foam:#e3f3f5;
  --sand:#fdfaf5;
  --paper:#ffffff;
  --crust:#a8360a;        /* 5.9:1 on --sand; white on it is 6.6:1 */
  --crust-2:#8c2c06;
  /* The header is teal, and --crust on --sea is 1.28:1 -- a button nobody
     would see. Gold separates from the bar at 5.47:1 and carries ink type at
     10.24:1, and it is the colour already on the rating stars. */
  --gold:#ffc94d;
  --gold-2:#ffd873;
  --deep:#083f4d;         /* the bottom of the header gradient */
  /* Sampled out of their own logo file, not chosen. By pixel count the mark
     is 59% teal (the wave), 21% red (the pepperoni) and 17% gold (the
     cheese), so the rule under the header is the wave running into the
     cheese -- their two dominant inks, one sweep. */
  --mark-wave:#009090;
  --mark-foam:#90d8d8;
  --mark-cheese:#f0d860;
  /* The primary button, taken from the wave in their own logo. Dark type on
     powder blue reads at 9.71:1 -- half again as legible as the white-on-red
     it replaces (6.57). The catch is the button's OWN edge: powder blue on a
     cream page is 1.55:1 and the shape disappears, so it carries a visible
     border in the deeper tone from the same wave (4.55:1). WCAG 1.4.11 asks
     for 3:1 on a control's boundary *or* a border it provides itself. */
  --powder:#90d8d8;
  --powder-2:#a9e2e2;
  --powder-edge:#0b7f8c;
  --line:#dfe6e6;
  --rule:color-mix(in srgb, var(--sea) 16%, transparent);

  --shell:74rem;
  --gut:clamp(1rem, 4vw, 2.5rem);
  --r:0.875rem;
  --shadow:0 1px 2px rgba(18,38,44,.06), 0 8px 24px -12px rgba(18,38,44,.22);
  --shadow-lg:0 2px 6px rgba(18,38,44,.08), 0 24px 60px -24px rgba(18,38,44,.34);

  --serif:"Iowan Old Style","Palatino Linotype",Palatino,"Book Antiqua",Georgia,serif;
  --sans:ui-sans-serif,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;

  /* Sticky geometry. JS measures the real heights into these on load and on
     resize; the values here are the fallbacks that have to be right on their
     own, because a mis-sized --stick means a sticky bar sitting on top of the
     thing you just tabbed to (WCAG 2.4.11). */
  --topbar-h:2.5rem;      /* layout: what these bars are sized to */
  --mast-h:7.75rem;       /* raised WITH the logo, not after it */
  --logo-h:5.6rem;        /* No longer capped: the source is the 2000px
                             original off their own server (1491px after the
                             white box is cropped off), not the 330px
                             rendition their pages reference. */
  --rail-h:3.25rem;
  --m-topbar:2.5rem;      /* measured: what they actually came out at */
  --m-mast:4.25rem;
  --m-filters:3.9rem;
  --m-rail:3.25rem;
  --stick:var(--m-mast);
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important}
}
body{
  margin:0;background:var(--sand);color:var(--ink);
  font:400 1.0625rem/1.65 var(--sans);
  font-synthesis-weight:none;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img,picture,svg{max-width:100%}
img{height:auto;display:block}
a{color:var(--sea);text-underline-offset:.18em}
h1,h2,h3{font-family:var(--serif);font-weight:600;line-height:1.12;
  letter-spacing:-.012em;text-wrap:balance;margin:0 0 .5em}
p{text-wrap:pretty;margin:0 0 1em}
address{font-style:normal}
/* Two rings, not one. No single colour clears 3:1 (WCAG 1.4.11) against both
   the sand ground and the teal/ink grounds, so the ring carries both: a white
   inner line that shows on the dark headers, topbar and footer, and a crust
   outer line that shows on everything light. One of the two is always
   visible, whatever the focus lands on. */
:focus-visible{outline:3px solid var(--crust);outline-offset:2px;
  box-shadow:0 0 0 2px #fff;border-radius:4px}

.shell{width:min(100% - (var(--gut)*2),var(--shell));margin-inline:auto}
.muted{color:var(--ink-2)}
/* Progressive enhancement, stated once and stated strongly: with no script
   these controls would be dead furniture, so they are not rendered at all.
   !important because .add and .tray set their own display later in the file
   and would otherwise win on source order. */
body.no-js .js-only{display:none !important}

.skip{position:absolute;left:-9999px;top:0;z-index:100;background:var(--crust);
  color:#fff;padding:.75rem 1.25rem;border-radius:0 0 var(--r) 0;font-weight:600}
.skip:focus{left:0}

/* ---------------------------------------------------------------- chrome */
.topbar{background:var(--ink);color:#cfe3e6;font-size:.8125rem;min-height:var(--topbar-h);
  display:flex;align-items:center}
.topbar__in{display:flex;gap:.75rem;align-items:center;
  flex-wrap:wrap;padding-block:.35rem}
.topbar__dir{display:inline-flex;align-items:center;gap:.35rem;
  color:#cfe3e6 !important;font-weight:600}
.topbar__dir svg{width:.95rem;height:.95rem;fill:currentColor;flex:0 0 auto}
.socs{display:inline-flex;align-items:center;gap:.15rem}
.soc{display:inline-flex;align-items:center;justify-content:center;
  width:2.1rem;height:2.1rem;border-radius:.55rem;
  transition:background-color .15s ease, color .15s ease}
.soc svg{width:1.05rem;height:1.05rem;fill:currentColor}
/* Two sets, one shown. On a wide screen they belong in the teal masthead --
   that is the bar people read as the header, and 34px marks in a 45px utility
   strip were invisible enough that they were reported missing twice. On a
   phone the masthead has no room, so the strip keeps them. display:none takes
   the hidden set out of the tab order and the accessibility tree entirely, so
   the same three links are never reachable twice. */
.socs--mast{display:none}
@media (min-width:56rem){
  .socs--bar{display:none}
  .socs--mast{display:inline-flex;gap:.25rem;margin-right:.35rem}
  .socs--mast .soc{width:2.5rem;height:2.5rem;border-radius:.6rem;
    color:#e6f2f4;background:rgba(255,255,255,.10)}
  .socs--mast .soc svg{width:1.3rem;height:1.3rem}
  .socs--mast .soc:hover{background:var(--gold);color:var(--ink)}
}
.socs--bar{margin-left:auto}
.socs--bar .soc{color:#e4f0f2;background:rgba(255,255,255,.08)}
.socs--bar .soc svg{width:1.15rem;height:1.15rem}
.socs--bar .soc:hover{background:var(--gold);color:var(--ink)}
.socs--foot{margin-top:.75rem;margin-left:-.4rem}
.socs--foot .soc{width:2.5rem;height:2.5rem;color:#b9ced2}
.socs--foot .soc svg{width:1.25rem;height:1.25rem}
.socs--foot .soc:hover{background:rgba(255,255,255,.1);color:#fff}
/* Visually hidden, still read aloud. */
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
/* The static line is the no-JS answer; once the live pill appears it is the
   pill that carries the fact, and the line would just repeat it. */
body:not(.no-js) .topbar__hrs:has(+ .pill:not([hidden])){display:none}
.topbar a{color:#fff;font-weight:600;text-decoration:none;white-space:nowrap;
  display:inline-flex;align-items:center;min-height:1.75rem}
.topbar a:hover{text-decoration:underline}

.topsentinel{position:absolute;top:0;height:1px;width:1px}
/* The header is the same deep teal as the page heads and the hero scrim, so
   the top of every page reads as one piece rather than a light toolbar
   balanced on a dark picture. The 3px rule underneath is the warm note: it
   runs crust into gold into the surf blue, which is the whole palette in one
   line and stops the bar ending on a dull border. */
.mast{position:sticky;top:0;z-index:40;
  background:linear-gradient(165deg,var(--sea) 0%,var(--deep) 100%);
  border-bottom:0;transition:box-shadow .2s ease, padding .2s ease}
.mast::after{content:"";position:absolute;left:0;right:0;bottom:0;height:3px;
  background:linear-gradient(90deg,var(--mark-wave) 0%,var(--mark-foam) 45%,
    var(--mark-cheese) 100%)}
/* Once the page has left the top the bar tightens, gains a shadow and the
   logo steps down a little -- so the header reads as a layer over the page
   rather than a band stuck to it. */
.mast.is-stuck{box-shadow:0 14px 34px -24px rgba(6,26,32,.9)}
.mast.is-stuck .mast__in{min-height:4.25rem}
.mast.is-stuck .brand img{height:calc(var(--logo-h) * .82)}
.mast__in,.brand img{transition:min-height .2s ease, height .2s ease}
.mast__in{display:flex;align-items:center;gap:1rem;min-height:var(--mast-h)}
.brand{display:inline-flex;align-items:center;text-decoration:none;
  margin-right:auto;min-height:44px;padding-block:.25rem}
.brand img{height:var(--logo-h);width:auto;object-fit:contain}
.nav{display:flex;gap:.15rem;flex-wrap:wrap}
.nav a{position:relative;text-decoration:none;color:#e6f2f4;font-weight:600;
  font-size:.9375rem;padding:.6rem .8rem;border-radius:.5rem;letter-spacing:.01em;
  display:inline-flex;align-items:center;min-height:44px;transition:color .16s ease}
.nav a::after{content:"";position:absolute;left:.8rem;right:.8rem;bottom:.5rem;
  height:2px;background:var(--gold);border-radius:2px;
  transform:scaleX(0);transform-origin:left;transition:transform .22s ease}
.nav a:hover{color:#fff}
.nav a:hover::after{transform:scaleX(1)}
.nav a[aria-current=page]{color:#fff}
.nav a[aria-current=page]::after{transform:scaleX(1)}
.btn--mast{padding-inline:1.25rem;background:var(--gold);color:var(--ink);
  box-shadow:0 6px 18px -8px rgba(255,201,77,.6)}
.btn--mast:hover{background:var(--gold-2)}
/* On a phone the masthead is 1/3 of the screen if it sticks, so it doesn't.
   The ink topbar sticks instead: it is 40px, and it carries the phone number,
   which is the one control a hungry person actually wants within reach. */
@media (max-width:56rem){
  .mast .btn--mast{display:none}
  .mast{position:relative}      /* NOT static: ::after is absolute and needs
                                   a containing block, or the gradient rule
                                   floats off to the bottom of the page */
  .topbar{position:sticky;top:0;z-index:41}
  .topbar__in{flex-wrap:nowrap;gap:.4rem}
  .topbar__hrs{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .topbar__dirt{display:none}
  /* 🔴 23px WIDE. The word "Directions" is hidden on a phone, so the
     pin IS the whole target -- and .95rem of icon plus .25rem of padding
     came out 23px, under the 24px floor in WCAG 2.5.8 AA. The social
     icons beside it are 27px; this one was smaller only because nobody
     measured it again after the label was taken away. */
  .topbar__dir{padding:.25rem;flex:0 0 auto;justify-content:center;
    min-width:1.75rem;min-height:1.75rem}
  .socs--bar{margin-left:0;flex:0 0 auto}
  /* At 375px the bar fits with two pixels to spare, which is luck, not a
     margin. So one item is allowed to give: the status text, because the same
     hours are in the band under the hero and in the footer of every page.
     The number never shrinks -- it is the whole reason the bar is sticky. */
  .topbar__tel{flex:0 0 auto}
  .pill--bar{flex:0 1 auto;min-width:0;overflow:hidden}
  .pill--bar .pill__t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .pill--bar .pill__dot{flex:0 0 auto}
  .socs--bar .soc:last-child{display:none}   /* Yelp; it is in the footer */
  .soc{width:1.85rem;height:1.85rem}
  .topbar__tel{margin-left:auto}
  .pill--bar{padding:.3rem .55rem;font-size:.7rem;gap:.35rem}
  .topbar{font-size:.75rem}
  .soc{width:1.7rem;height:1.7rem}
  .soc svg{width:1rem;height:1rem}
  .mast__in{flex-wrap:wrap;padding-block:.4rem;min-height:0}
  /* Centred and larger on a phone: with the nav on its own scrolling row
     below, the logo has the whole first row to itself, and centring it is
     what makes the header read as a masthead rather than a toolbar. */
  :root{--logo-h:5.2rem}
  .brand{margin:0 auto;min-height:5.2rem;padding-block:.2rem}
  .nav{justify-content:safe center}
  /* Five items in 375px. At the desktop size they run 53px over, so the
     padding comes in and the type comes down a step -- all five fit from
     about 345px up, which is every phone still in use bar the original SE.
     Below that it scrolls, and the fade tells you so instead of the last
     item just being sliced in half. */
  .nav{width:100%;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;gap:.1rem;
    padding-bottom:.15rem;margin-inline:calc(var(--gut) * -1);
    padding-inline:var(--gut);scroll-padding-inline:var(--gut)}
  .nav::-webkit-scrollbar{display:none}
  .nav a{white-space:nowrap;min-height:2.75rem;flex:0 0 auto;
    font-size:.875rem;padding:.5rem .5rem}
  .nav a::after,.nav a[aria-current=page]::after{left:.5rem;right:.5rem;bottom:.3rem}
  .nav.is-scrollable{
    -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 2.25rem),transparent);
    mask-image:linear-gradient(90deg,#000 calc(100% - 2.25rem),transparent)}
}

/* ------------------------------------------------------------------ btns */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  min-height:44px;padding:.7rem 1.4rem;border-radius:999px;border:2px solid transparent;
  font:600 1rem/1 var(--sans);text-decoration:none;cursor:pointer;
  transition:transform .12s ease, background-color .16s ease, box-shadow .16s ease}
.btn:active{transform:translateY(1px)}
.btn--go{background:var(--powder);color:var(--ink);
  border-color:var(--powder-edge);box-shadow:var(--shadow)}
.btn--go:hover{background:var(--powder-2);border-color:var(--sea)}
.btn--ghost{background:transparent;color:var(--sea);border-color:currentColor}
.btn--ghost:hover{background:var(--foam)}
.tlink{color:var(--sea);font-weight:600;text-decoration:underline;
  text-decoration-thickness:2px;text-underline-offset:.2em;
  display:inline-flex;align-items:center;min-height:44px}
.tlink.big{font-size:1.5rem;font-family:var(--serif)}

/* ------------------------------------------------- status pill / rating */
/* "Open now, until 8pm" worked out in the browser from the published hours.
   Hidden until script fills it: a pill that says "Open" when the kitchen is
   shut is worse than no pill. */
.pill{display:inline-flex;align-items:center;gap:.45rem;border-radius:999px;
  font-weight:700;font-size:.8125rem;line-height:1;padding:.4rem .75rem;
  white-space:nowrap}
.pill[hidden]{display:none}
.pill__dot{width:.5rem;height:.5rem;border-radius:50%;background:currentColor;
  flex:0 0 auto;position:relative}
.pill--open .pill__dot::after,.pill--soon .pill__dot::after{
  content:"";position:absolute;inset:-.25rem;
  border-radius:50%;border:1.5px solid currentColor;opacity:.55;
  animation:ping 2.4s ease-out infinite}
.pill--soon .pill__dot::after{animation-duration:1.1s}
@keyframes ping{0%{transform:scale(.7);opacity:.7}70%,100%{transform:scale(1.5);opacity:0}}
/* Three states, three colours: green while there is time, amber once the
   count is under an hour, red when the door is shut. Every one of them is
   measured against the ground it sits on -- see the CONTRAST table. */
.pill--bar{background:rgba(255,255,255,.13);color:#cfe3e6}
.pill--bar.pill--open{color:#8be0a8}
.pill--bar.pill--soon{color:var(--gold);background:rgba(255,201,77,.16)}
.pill--bar.pill--shut{color:#e9b3a3}
.pill--hero{background:rgba(255,255,255,.14);color:#eaf5f7;
  backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.22);
  padding:.5rem .9rem;font-size:.875rem}
.pill--hero.pill--open{color:#b6f0c9}
.pill--hero.pill--soon{color:var(--gold-2)}
.pill--hero.pill--shut{color:#f6ccbe}

.hero__trust{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap;
  margin:0 0 1.6rem}
.rating{display:inline-flex;align-items:center;gap:.5rem;text-decoration:none;
  color:#fff;background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.22);
  backdrop-filter:blur(8px);border-radius:999px;padding:.5rem .9rem;
  min-height:44px;font-size:.875rem;transition:background-color .16s ease}
.rating:hover{background:rgba(255,255,255,.24)}
.rating__stars{display:inline-flex;gap:.1rem}
.rating__stars svg{width:.85rem;height:.85rem;fill:#ffc94d}
.rating__n{font-weight:800;font-size:1rem}
.rating__c{color:#d3e6ea}

/* ------------------------------------------------------- hero (wide) ---- */
.hero{position:relative;isolation:isolate;display:block;
  min-height:clamp(30rem,78svh,44rem);overflow:hidden;background:var(--ink)}
.hero__img{position:absolute;inset:0;z-index:0;overflow:hidden}
.hero__img img{width:100%;height:100%;object-fit:cover;object-position:50% 46%;
  transform-origin:50% 46%;animation:heroPush 24s ease-out both}
/* A slow push in. 24s, once, no loop -- a hero that breathes rather than one
   that paces. The global prefers-reduced-motion rule turns it off. */
@keyframes heroPush{from{transform:scale(1.001)}to{transform:scale(1.07)}}

/* Film grain. A 120px tile of feTurbulence as a data URI -- about 700 bytes,
   no request, and it stops a big flat gradient from banding on cheap panels. */
.hero__grain{position:absolute;inset:0;z-index:2;pointer-events:none;opacity:.16;
  mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  background-size:120px 120px}
/* Two gradients, two jobs. The vertical one seats the frame; the horizontal
   one is what actually protects the type, because on a wide hero the copy
   lives in the left third and the pie lives on the right — so the left gets
   deepened and the photograph does not go grey. Every stop here was set by
   compositing the real photo under the real gradient and reading the pixels
   behind the glyphs (tools/hero-contrast.js), never by eye. Lowest measured
   ratio at 1440px: 5.85:1. */
.hero__scrim{position:absolute;inset:0;z-index:1;
  background:
    linear-gradient(to right,rgba(6,26,32,.76) 0%,rgba(6,26,32,.60) 34%,
      rgba(6,26,32,.16) 62%,rgba(6,26,32,.02) 82%),
    linear-gradient(to top,rgba(6,26,32,.58) 0%,rgba(6,26,32,.44) 34%,
      rgba(6,26,32,.30) 62%,rgba(6,26,32,.24) 100%)}
.hero__in{position:relative;z-index:3;min-height:inherit;display:flex;
  align-items:flex-end;padding-block:clamp(3rem,9vw,6rem)}
.hero__eyebrow{color:var(--surf-p);font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;font-size:.8125rem;margin-bottom:.85rem}
.hero h1{color:#fff;font-size:clamp(2.75rem,9vw,5.25rem);line-height:1.02;
  margin-bottom:.4em;max-width:14ch}
.hero__sub{color:#e4eff1;font-size:clamp(1.0625rem,2.1vw,1.25rem);
  max-width:44ch;margin-bottom:1.75rem}
.hero__cta{display:flex;gap:.75rem;flex-wrap:wrap;margin-bottom:.7rem}
.hero__pickup{color:#e4eff1;font-weight:600;font-size:.9375rem;line-height:1.4;
  max-width:44ch;margin:0 0 1.25rem}
/* The outline button carries its own ground rather than borrowing the
   photograph's. Over the bright steel rim its white label measured 3.61:1;
   with this fill the composite behind the text is rgb(89,103,107) and the
   label clears 5.7:1. It also stops the button reading as a thin wire over a
   busy picture. */
.hero__cta .btn--ghost{color:#fff;background:rgba(6,26,32,.55);
  border-color:rgba(255,255,255,.85);backdrop-filter:blur(6px)}
.hero__cta .btn--ghost:hover{background:rgba(6,26,32,.72);border-color:#fff}

/* ------------------------------------------------------ hero (phone) ---- *
 * A separate hero, not the wide one squeezed. It is a different picture (the
 * portrait crop, the whole pie), a different shape, a different order of
 * business. Everything mobile-specific lives in this one block and it sits
 * AFTER the rules it overrides — an earlier version of it was placed above
 * them and align-items silently lost to the base rule at equal specificity.
 * Seventy per cent of the searches land here; this is the real hero. */
@media (max-width:48rem){
  /* Exactly the screen left under the header, so both calls to action land
     above the fold and nothing is sliced in half by it. */
  /* Leave room for the guest dock so Call / Directions / pickup are not
     sitting underneath it on a short phone. */
  .hero{min-height:calc(100svh - var(--m-topbar) - var(--m-mast));
    padding-bottom:calc(4.75rem + env(safe-area-inset-bottom))}

  /* Name first. The copy sits at the top of the frame and the pie fills
     everything beneath it, rather than the copy sinking to the bottom. */
  /* Top-aligned, but not jammed under the header: a proportion of the screen
     rather than a fixed pad, so the breathing room holds on a small phone and
     a large one. */
  .hero__in{align-items:flex-start;padding-block:6svh 1.5rem}

  /* The source is 3:4 and the box is taller than it is wide, so object-fit
     matches the HEIGHT and object-position has nothing left to move
     vertically — the only lever on how much pie shows is the box itself.
     The filter puts back the punch the scrim takes out. */
  .hero__img img{filter:saturate(1.18) contrast(1.06)}

  /* One gradient, not two: at this width the copy spans the full column, so
     there is no quiet side to protect -- only a quiet END. The copy is at the
     top now, so the cover is at the top: heavy from 100% (the top) down
     through the type, then clearing hard across the bottom third where the
     pie is. Written as "to top" with reversed stops rather than "to bottom",
     because getComputedStyle drops the default direction and anything reading
     the computed value back then has no idea which way it ran.
     With the copy at the top and the cover still at the bottom, the headline
     measured 1.75:1. */
  .hero__scrim{background:
    linear-gradient(to top,
      rgba(6,26,32,.05) 0%, rgba(6,26,32,.15) 8%, rgba(6,26,32,.56) 19%,
      rgba(6,26,32,.64) 40%, rgba(6,26,32,.68) 100%)}

  /* The delivery apps stay in the hero -- people arrive already knowing which
     one they use. What goes is the "Ring the kitchen" card, because the Call
     button directly above it is the same action twice. The two that remain
     become one compact row instead of three stacked cards. */
  .hero__in{padding-block:4.5svh 1.15rem}
  .hero__trust{margin:0 0 1.1rem}
  .hero h1{margin-bottom:.28em}
  .hero__sub{margin-bottom:.65rem}
  .hero__pickup{margin:0 0 .55rem;font-size:.875rem}
  /* Call + Directions share a row so both land above the fold; the menu
     button keeps the full width underneath. Pickup sits with them. */
  .hero__cta{display:grid;grid-template-columns:1fr 1fr;gap:.5rem;margin-bottom:.55rem}
  .hero__cta .btn{flex:unset;min-height:48px}
  .hero__call{order:1}
  .hero__dir{order:2}
  .hero__menu{order:3;grid-column:1 / -1}
  .hero .ords--c{display:flex;gap:.5rem;margin-top:.55rem}
  .hero .ords--c .ord--p{display:none}
  .hero .ords--c .ord{flex:1 1 0;min-width:0;padding:.5rem .7rem;min-height:44px;
    justify-content:center;gap:0}
  .hero .ords--c .ord__l{font-size:.9375rem;line-height:1.2}
  .hero .ords--c .ord__n{font-size:.6875rem;line-height:1.2}
}

/* ----------------------------------------------------------- order links */
.ords{display:grid;gap:.75rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))}
.ords--c{display:flex;gap:.5rem;flex-wrap:wrap}
.ord{display:flex;flex-direction:column;gap:.1rem;text-decoration:none;
  min-height:44px;justify-content:center;padding:.75rem 1.1rem;border-radius:var(--r);
  background:var(--paper);border:1px solid var(--line);color:var(--ink)}
.ord:hover{border-color:var(--sea);box-shadow:var(--shadow)}
.ord__l{font-weight:700}
.ord__n{font-size:.8125rem;color:var(--ink-2)}
.ord--p{background:var(--sea);border-color:var(--sea);color:#fff}
.ord--p .ord__n{color:#c9e8ee}
.ord--p:hover{background:var(--sea-2);border-color:var(--sea-2)}
/* Same reasoning as the outline button: a 10% white wash over a photograph
   is a tint, not a ground. "Uber Eats" measured 4.14:1 sitting on the bright
   steel; a dark glass fill carries its own contrast wherever it lands. */
.ords--c .ord{background:rgba(6,26,32,.55);border-color:rgba(255,255,255,.28);
  color:#fff;backdrop-filter:blur(6px)}
.ords--c .ord__n{color:#c9e8ee}
.ords--c .ord--p{background:rgba(255,255,255,.94);color:var(--ink);border-color:transparent}
.ords--c .ord--p .ord__n{color:var(--ink-2)}

/* --------------------------------------------------------------- glance */
/* The band directly under the hero. It answers the three things somebody
   arrives with -- are you open, where are you, how do I order -- instead of
   four decorative facts. Light, because it comes straight after a dark hero
   and a dark header and the page needs to breathe somewhere. */
.glance{background:linear-gradient(180deg,#fbf4e9 0%,var(--sand) 100%);
  padding-block:clamp(1.5rem,4vw,2.5rem);border-bottom:1px solid var(--line)}
.glance__g{display:grid;gap:1rem;align-items:stretch;
  grid-template-columns:repeat(auto-fit,minmax(17rem,1fr))}
.gcard{background:var(--paper);border:1px solid var(--line);border-radius:var(--r);
  padding:1.25rem 1.35rem 1.35rem;display:flex;flex-direction:column;
  box-shadow:var(--shadow)}
.glance__g{grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))}
@media (min-width:64rem){.glance__g{grid-template-columns:repeat(4,1fr)}}
.gcard--craft{background:linear-gradient(165deg,var(--sea) 0%,var(--deep) 100%);
  border-color:transparent;color:#e6f2f4}
.gcard--craft .gcard__k{color:var(--surf-t)}
.gcard--craft .gcard__big{color:#fff}
.gcard--craft .gcard__note{color:#c6dde2}
.gcard--craft .tlink{color:var(--gold)}
.gcard__score{display:flex;align-items:center;gap:.6rem;margin:0 0 .15rem}
.gcard__stars{display:inline-flex;gap:.1rem}
.gcard__stars svg{width:1.05rem;height:1.05rem;fill:var(--gold)}
.gcard__score b{font-family:var(--serif);font-size:2.25rem;line-height:1;
  color:var(--ink)}
.gcard__alt{margin:.35rem 0 0;font-size:.8125rem}
/* 🔴 16px TALL, AND NOT EXEMPT. WCAG 2.5.8 AA wants 24x24, and its "inline"
   get-out only covers a link sitting inside a sentence — this one is the whole
   paragraph, so it is a standalone target and the exception does not apply.
   Padding, not font-size: the line has to stay quiet next to the button above
   it. The margin above comes down by the same amount the padding adds. */
.gcard__alt a{color:var(--ink-2);display:inline-block;padding-block:.3rem}
.tlink--card{margin-top:auto;align-self:flex-start;min-height:2.75rem}
.gcard__k{font-size:.6875rem;font-weight:800;letter-spacing:.1em;
  text-transform:uppercase;color:var(--sea);margin:0 0 .5rem}
.gcard__big{font-family:var(--serif);font-size:1.75rem;line-height:1.15;
  margin:0 0 .25rem;color:var(--ink)}
.gcard__big--sm{font-size:1.25rem;line-height:1.3}
.gcard__big--sm span{display:inline-block;font-family:var(--sans);
  font-size:.9375rem;color:var(--ink-2);margin-top:.2rem}
.gcard__big.is-open{color:#14713f}
.gcard__big.is-soon{color:#8a5e00}
.gcard__big.is-shut{color:var(--crust)}
.gcard__sub{font-size:.9375rem;color:var(--ink-2);margin:0 0 1rem}
.gcard__note{font-size:.875rem;color:var(--ink-2);margin:.5rem 0 1rem}
.btn--card{margin-top:auto;align-self:flex-start}

/* The whole week, seven columns. Today lights up; the closed day is stated
   rather than hidden, because "are they shut on Mondays" is a real question. */
.wk{display:grid;grid-template-columns:repeat(7,1fr);gap:.25rem;margin-top:auto}
.wk__d{display:flex;flex-direction:column;align-items:center;gap:.15rem;
  padding:.5rem .15rem;border-radius:.5rem;background:var(--sand);
  border:1px solid transparent;text-align:center}
.wk__d abbr{text-decoration:none;font-weight:800;font-size:.75rem;
  color:var(--ink);letter-spacing:.02em}
.wk__d span{font-size:.625rem;line-height:1.25;color:var(--ink-2);
  font-variant-numeric:tabular-nums}
.wk__d--shut{background:transparent}
.wk__d--shut abbr,.wk__d--shut span{color:#54696f}
.wk__d.is-today{background:var(--sea);border-color:var(--sea);
  box-shadow:0 6px 16px -10px rgba(11,85,102,.9)}
.wk__d.is-today abbr{color:#fff}
.wk__d.is-today span{color:#bfe4ec}
@media (max-width:30rem){
  .wk__d span{font-size:.5625rem}
  .wk__d{padding:.45rem .1rem}
}

/* --------------------------------------------------------------- revues */
.revs{padding-block:clamp(2.5rem,6vw,4.5rem);background:var(--sand);
  border-top:1px solid var(--rule)}
.revs__head{max-width:52ch;margin-bottom:1.75rem}
.revs__k{font-size:.6875rem;font-weight:800;letter-spacing:.1em;
  text-transform:uppercase;color:var(--sea);margin:0 0 .5rem}
.revs h2{font-size:clamp(1.6rem,3.6vw,2.25rem)}
.revs__p{color:var(--ink-2);margin:0;font-size:.9375rem}
.rev{flex:0 0 auto;width:min(80vw,22rem);margin:0;display:flex;
  flex-direction:column;gap:.75rem;padding:1.35rem 1.5rem;
  background:var(--paper);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--shadow)}
.rev__stars{display:flex;gap:.12rem}
.rev__stars svg{width:.9rem;height:.9rem;fill:var(--gold)}
.rev__q{margin:0}
.rev__q p{margin:0;font-family:var(--serif);font-size:1.0625rem;line-height:1.45;
  color:var(--ink)}
.rev__by{font-size:.8125rem;font-weight:700;letter-spacing:.04em;
  text-transform:uppercase;color:var(--ink-2);margin-top:auto}
@media (min-width:56rem){.rev{width:24rem}}

/* ---------------------------------------------------------------- beach */
/* Their own footage, as a texture. The poster is the layer that always
   loads; the video sits on top at zero opacity and fades in only once it is
   actually playing, so a blocked or refused video is simply a still photo
   rather than a black rectangle. */
.beach{position:relative;isolation:isolate;overflow:hidden;background:var(--deep);
  min-height:clamp(26rem,64svh,40rem);display:grid}
.beach__poster,.beach__v{position:absolute;inset:0;z-index:0}
.beach__poster img,.beach__v{width:100%;height:100%;object-fit:cover}
.beach__v{z-index:1;opacity:0;transition:opacity .9s ease}
.beach__v.is-playing{opacity:1}
/* Lighter than it was: the footage is graded up in prep_video.py now, and
   the old cover was sized for an ungraded dusk shot. Bottom-weighted so the
   sky and the water stay open and the type still has its ground. */
.beach__scrim{position:absolute;inset:0;z-index:2;
  background:linear-gradient(to top,rgba(6,26,32,.84) 0%,rgba(6,26,32,.78) 26%,
    rgba(6,26,32,.68) 44%,rgba(6,26,32,.24) 64%,rgba(6,26,32,.05) 100%)}
.beach__in{position:relative;z-index:3;align-self:end;
  padding-block:clamp(2.5rem,7vw,4.5rem)}
.beach__k{color:var(--surf-p);font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;font-size:.8125rem;margin-bottom:.6rem}
.beach h2{color:#fff;font-size:clamp(2.25rem,6vw,4rem);margin-bottom:.35em}
.beach__p{color:#e4eff1;font-size:clamp(1rem,2vw,1.1875rem);max-width:46ch;margin:0}

/* --------------------------------------------------------------- spread */
/* 🔴 THE QUOTE UNDER THE RAIL WAS ALWAYS HALF-CUT. Owner: "the paragraph under
   scrolls to soon and cant read because the pics are still to big". Measured:
   it started 652px into the section, on a 900px screen, under a 124px sticky
   header — so it could never be read in the same breath as the pictures it
   belongs to. The pictures come down and every gap closes with them: heading,
   rail and quote now come to ~780px and read as ONE screenful. */
.spread{padding-block:clamp(2rem,3.4vw,2.75rem);background:var(--foam);
  border-block:1px solid var(--rule)}
.spread__head{max-width:46ch;margin-bottom:1.25rem}
.spread__head h2{font-size:clamp(1.75rem,4vw,2.5rem)}
.spread__lede{color:var(--ink-2);margin:0;font-size:1.0625rem}
.spread__num{font-family:var(--serif);font-size:2.5rem;line-height:1;
  color:var(--sea);font-weight:600;margin-right:.15em;
  vertical-align:-.18em;font-variant-numeric:tabular-nums}

/* A phone gets a rail it can flick through; anything wide gets a grid, and
   the signature pies take a double cell because ten of the forty-seven are
   in there. The rail bleeds to the screen edge on purpose -- a card half cut
   off at the right is what tells you there is more of it. */
.rail--revs{overflow-x:auto;scrollbar-width:none;padding-block:.25rem;
  -webkit-overflow-scrolling:touch}
.rail--revs::-webkit-scrollbar{display:none}
.rail--revs .rail__track{display:flex;gap:.75rem;width:max-content;
  padding-inline:var(--gut);align-items:stretch}
.rail--revs.is-drifting{
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 var(--gut),
    #000 calc(100% - var(--gut)),transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 var(--gut),
    #000 calc(100% - var(--gut)),transparent 100%)}

.spread__rail{overflow-x:auto;scrollbar-width:none;
  scroll-snap-type:x mandatory;scroll-padding-inline:var(--gut);
  padding-block:.25rem;-webkit-overflow-scrolling:touch}
/* while it is drifting, snapping would drag it back a tile at a time */
.spread__rail.is-drifting{scroll-snap-type:none}
/* A continuous rail always has a tile half in and half out at each edge.
   Cut hard, that reads as broken -- "Strombolis" arriving as "trombolis".
   Faded, the same slice reads as the row continuing past the screen, which
   is what it is doing. Only while drifting: on a rail at rest the fade
   would just be dimming the thing you are trying to read. */
.spread__rail.is-drifting{
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 var(--gut),
    #000 calc(100% - var(--gut)),transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 var(--gut),
    #000 calc(100% - var(--gut)),transparent 100%)}
.spread__rail::-webkit-scrollbar{display:none}
/* 🔴 align-items DEFAULTED TO STRETCH AND ATE THE ASPECT RATIO. Every tile
   asked for 4/5 and the narrow ones rendered at 0.47: flex stretched all of
   them to the tallest item, which was the 32rem wide tile at 640px, and an
   `aspect-ratio` on a stretched flex item is simply ignored. The whole band
   came out 1302px on a 1440x900 screen — 1.45 SCREENS for one menu rail.
   ⭐ A rail reads clean when the height is CONSTANT and only the width varies,
   so that is what it does now: one --tile-h for the row, flex-start so nothing
   can stretch past it, and no aspect-ratio left to be overruled. */
.spread__g{display:flex;gap:.75rem;align-items:flex-start;
  width:max-content;padding-inline:var(--gut)}

.tile{--tile-h:13rem;
  position:relative;isolation:isolate;display:block;overflow:hidden;
  border-radius:var(--r);text-decoration:none;scroll-snap-align:start;
  flex:0 0 auto;width:min(52vw,11rem);height:var(--tile-h);
  background:var(--deep);box-shadow:var(--shadow);
  transition:transform .22s ease, box-shadow .22s ease}
.tile:hover{transform:translateY(-4px);box-shadow:var(--shadow-lg)}
.tile__i{position:absolute;inset:0;z-index:0}
.tile__i img{width:100%;height:100%;object-fit:cover;
  transition:transform .5s cubic-bezier(.2,.7,.3,1)}
.tile:hover .tile__i img{transform:scale(1.06)}
.tile__scrim{position:absolute;inset:0;z-index:1;
  background:linear-gradient(to top,rgba(6,26,32,.92) 0%,rgba(6,26,32,.72) 30%,
    rgba(6,26,32,.30) 62%,rgba(6,26,32,.12) 100%)}
.tile__t{position:absolute;left:0;right:0;bottom:0;z-index:2;
  display:flex;align-items:center;gap:.6rem;padding:.9rem 1rem}
.tile__n{margin-right:auto}
/* the arrow only arrives on a device that can hover -- on a phone the whole
   tile is obviously tappable and a permanent arrow is just clutter */
.tile__a{width:1.1rem;height:1.1rem;color:#fff;flex:0 0 auto;
  opacity:0;transform:translateX(-.35rem);
  transition:opacity .24s ease, transform .24s ease}
@media (hover:hover){
  .tile:hover .tile__a,.tile:focus-visible .tile__a{opacity:1;transform:none}
}
@media (hover:none){.tile__a{display:none}}
.tile__n{color:#fff;font-weight:700;font-size:1.0625rem;line-height:1.2;
  text-wrap:balance;margin-right:auto}
.tile__c{flex:0 0 auto;min-width:1.75rem;height:1.75rem;border-radius:999px;
  background:rgba(255,255,255,.92);color:var(--ink);display:grid;
  place-items:center;font-size:.75rem;font-weight:800;
  font-variant-numeric:tabular-nums}

/* A rail at every width, not a grid on big screens: the slow drift is the
   point, and it only reads as cinematic if it runs the full width of the
   screen. The wide tiles stay wide -- they give the row its rhythm. */
.tile--wide{width:min(66vw,15rem)}
@media (min-width:56rem){
  .tile{--tile-h:13rem;width:11.5rem}
  .tile--wide{width:19rem}
  .tile--wide .tile__n{font-size:1.125rem}
}

/* The pause control. Built by script, because with no script there is no
   motion to pause -- but once the drift exists this is not optional:
   WCAG 2.2.2 wants a way to stop anything that moves on its own for more
   than five seconds, and hovering is not a thing a phone can do. */
.spread__bar{display:flex;align-items:center;gap:.75rem;margin-top:.8rem}
.spread__ctl{display:inline-flex;align-items:center;gap:.5rem;min-height:44px;
  padding:.5rem 1rem;border-radius:999px;border:1.5px solid var(--line);
  background:var(--paper);color:var(--ink);font:600 .875rem/1 var(--sans);
  cursor:pointer;transition:border-color .15s ease, background-color .15s ease}
.spread__ctl:hover{border-color:var(--sea);background:var(--foam)}
.spread__ctl svg{width:.85rem;height:.85rem;fill:currentColor}
.spread__hint{font-size:.8125rem;color:var(--ink-2)}
@media (max-width:36rem){.spread__hint{display:none}}
.spread .pull--wide{margin-top:1.25rem;max-width:56ch}

/* --------------------------------------------------------------- section */
.feats,.story-tease,.ordering,.visit{padding-block:clamp(3rem,7vw,5.5rem)}
.feats h2,.ordering h2,.visit h2,.story-tease h2{font-size:clamp(1.75rem,4vw,2.5rem)}
.feats__g{display:grid;gap:1.5rem;grid-template-columns:repeat(auto-fit,minmax(17rem,1fr))}
.feat a{display:block;text-decoration:none;color:inherit;border-radius:var(--r);
  overflow:hidden;background:var(--paper);border:1px solid var(--line);height:100%;
  transition:transform .18s ease, box-shadow .18s ease}
.feat a:hover{transform:translateY(-3px);box-shadow:var(--shadow-lg)}
.feat__i img{width:100%;aspect-ratio:3/2;object-fit:cover}
.feat__t{padding:1.15rem 1.25rem 1.4rem;text-align:center}
.feat__t p{margin-inline:auto;max-width:32ch}
.feat__t h3{font-size:1.3rem;margin-bottom:.3em}
.feat__t p{font-size:.9375rem;color:var(--ink-2);margin-bottom:.6em}
.feat__p{font-weight:700;color:var(--crust)}
.feats__more{margin-top:2rem}
.diet-line{max-width:52ch;margin:0 0 1.25rem;color:var(--ink-2);font-size:.9375rem}
.diet-line--sec{margin:-.5rem 0 1.25rem}

.story-tease{background:var(--foam)}
/* The photograph leads on a wide screen and the words follow; on a phone the
   order reverses, because a heading is what tells you what you are looking at
   before you have scrolled far enough to see it. */
.story-tease__shot{margin:0}
.story-tease__shot img{width:100%;display:block;border-radius:var(--r);
  box-shadow:var(--shadow)}
.story-tease__shot figcaption{margin-top:.6rem;font-size:.9375rem;
  color:var(--ink-2)}
@media (max-width:59.99rem){.story-tease__shot{order:2}}
.story-tease__in,.visit__in{display:grid;gap:clamp(1.5rem,4vw,3.5rem);
  grid-template-columns:repeat(auto-fit,minmax(19rem,1fr));align-items:start}
.pull{margin:0;border-left:4px solid var(--surf);padding-left:1.4rem}
.pull p{font-family:var(--serif);font-size:clamp(1.25rem,3vw,1.75rem);
  line-height:1.32;color:var(--sea)}
.pull cite{font-style:normal;font-weight:700;font-size:.875rem;color:var(--ink-2);
  letter-spacing:.04em;text-transform:uppercase}
.ordering__p{max-width:48ch;color:var(--ink-2)}
.visit{background:var(--paper);border-top:1px solid var(--line)}
.visit address{font-size:1.25rem;line-height:1.7;font-weight:600}
.visit__note{color:var(--ink-2);max-width:44ch}
.visit__acts{display:flex;gap:.6rem;flex-wrap:wrap;margin-top:1.25rem}
@media (max-width:30rem){.visit__acts .btn{flex:1 1 100%}}
.visit__shot img{width:100%;border-radius:var(--r);box-shadow:var(--shadow);
  aspect-ratio:3/2;object-fit:cover}

.hours{margin:0;font-size:.9375rem}
.hoursh{font-size:1.125rem;font-family:var(--sans);font-weight:700;margin-bottom:.6em}
.hr{display:flex;justify-content:space-between;gap:1rem;padding:.45rem 0;
  border-bottom:1px dashed var(--rule)}
.hr:last-child{border-bottom:0}
.hr dt{font-weight:600}
.hr dd{margin:0;color:var(--ink-2);font-variant-numeric:tabular-nums}
.hr--shut dt,.hr--shut dd{color:#54696f;font-weight:400}
.hr[data-today]{background:var(--foam);margin-inline:-.6rem;padding-inline:.6rem;
  border-radius:.4rem;border-bottom-color:transparent}
.hr[data-today] dt::after{content:" · today";font-weight:400;color:var(--sea);
  font-size:.8125rem}

/* ------------------------------------------------------- page furniture */
.pagehead,.menuhead{background:var(--sea);color:#fff;
  padding-block:clamp(2.5rem,6vw,4.25rem)}
.menuhead{background:linear-gradient(160deg,var(--sea),#083f4d)}
.pagehead h1,.menuhead h1{color:#fff;font-size:clamp(2.25rem,6.5vw,4rem);margin-bottom:.28em}
.eyebrow{color:var(--surf-t);font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;font-size:.8125rem;margin-bottom:.7rem}
.lede{font-size:clamp(1.0625rem,2vw,1.25rem);color:#d9edf1;max-width:56ch;margin:0}

/* ------------------------------------------------------------- FILTERS */
/* Pure CSS. The checkboxes drive :has() on the form, and the sections carry
   a data-has union so an emptied section hides its own heading. No script. */
.filters{position:sticky;top:var(--stick);z-index:30;background:var(--paper);
  border-bottom:1px solid var(--line)}
.filters__in{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;
  padding-block:.7rem}
@media (max-width:56rem){
  :root{--stick:var(--m-topbar)}
  /* One scrolling row rather than two wrapped ones -- 44px back on a phone. */
  .filters__in{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;
    margin-inline:calc(var(--gut) * -1);padding-inline:var(--gut)}
  .filters__in::-webkit-scrollbar{display:none}
  .chip{flex:0 0 auto}
  .filters__lbl{display:none}
  .filters__count{flex:0 0 auto;margin-left:.25rem}
}
.filters__lbl{font-size:.8125rem;font-weight:700;text-transform:uppercase;
  letter-spacing:.07em;color:var(--ink-2);margin-right:.15rem}
.chip{position:relative;display:inline-flex;align-items:center;min-height:44px;
  padding:.4rem 1rem;border-radius:999px;border:1.5px solid var(--line);
  background:var(--sand);font-size:.9375rem;font-weight:600;color:var(--ink-2);
  cursor:pointer;user-select:none;transition:background-color .15s,border-color .15s}
.chip input{position:absolute;opacity:0;width:100%;height:100%;left:0;top:0;
  margin:0;cursor:pointer}
.chip:hover{border-color:var(--sea)}
.chip:has(input:checked){background:var(--sea);border-color:var(--sea);color:#fff}
.chip:has(input:focus-visible){outline:3px solid var(--crust);outline-offset:2px}
.chip--reset{border-style:dashed;font-weight:500;background:transparent}
.filters__count{font-size:.875rem;color:var(--ink-2);margin-left:auto}

#filters:has([value=nomeat]:checked) ~ .menu .item:not([data-tags~=nomeat]),
#filters:has([value=nopork]:checked) ~ .menu .item:not([data-tags~=nopork]),
#filters:has([value=heat]:checked)   ~ .menu .item:not([data-tags~=heat]),
#filters:has([value=value]:checked)  ~ .menu .item:not([data-tags~=value]){display:none}
#filters:has([value=nomeat]:checked) ~ .menu .sec:not([data-has~=nomeat]),
#filters:has([value=nopork]:checked) ~ .menu .sec:not([data-has~=nopork]),
#filters:has([value=heat]:checked)   ~ .menu .sec:not([data-has~=heat]),
#filters:has([value=value]:checked)  ~ .menu .sec:not([data-has~=value]){display:none}
/* Hide the scale + small-print blocks while a filter is on: they are not
   filtered, so leaving them visible reads as "these survived the filter". */
#filters:has(input:checked) ~ .menu .scale,
#filters:has(input:checked) ~ .menu .extras{display:none}
@supports not selector(:has(*)){
  .filters{display:none}          /* no :has, no promise we cannot keep */
}

/* ---------------------------------------------------------------- rail */
.rail{position:sticky;top:calc(var(--stick) + var(--m-filters));z-index:29;
  background:color-mix(in srgb,var(--sand) 94%,transparent);
  backdrop-filter:blur(8px);border-bottom:1px solid var(--line)}
.rail__in{display:flex;gap:.25rem;overflow-x:auto;scrollbar-width:none;
  width:min(100% - (var(--gut)*2),var(--shell));margin-inline:auto;
  min-height:var(--rail-h);align-items:center}
.rail__in::-webkit-scrollbar{display:none}
.rail__a{white-space:nowrap;text-decoration:none;color:var(--ink-2);font-weight:600;
  font-size:.875rem;padding:.5rem .8rem;border-radius:999px;
  display:inline-flex;align-items:center;min-height:44px}
.rail__a:hover{background:var(--foam);color:var(--sea)}
.rail__a[aria-current=true]{background:var(--sea);color:#fff}

/* -------------------------------------------------------------- the menu */
.menu{padding-block:clamp(2rem,5vw,3.5rem)}
.sec{
  /* WCAG 2.4.11 Focus Not Obscured: the masthead, the filter bar and the rail
     are all sticky. Anything scrolled or tabbed to must clear all three. */
  scroll-margin-top:calc(var(--stick) + var(--m-filters) + var(--m-rail) + 1rem);
  padding-block:clamp(2rem,4vw,3rem);border-top:1px solid var(--rule)}
.sec:first-child{border-top:0;padding-top:0}
.sec__head{display:flex;align-items:baseline;gap:.9rem;margin-bottom:1.5rem}
.sec__head h2{font-size:clamp(1.6rem,4vw,2.25rem);margin:0}
.sec__n{font-size:.8125rem;color:var(--ink-2);font-weight:600;letter-spacing:.05em;
  text-transform:uppercase}
.sec__body{display:grid;gap:clamp(1.5rem,4vw,3rem);align-items:start;
  grid-template-columns:minmax(0,1fr)}
/* A section with no photograph is one column at every width — not a column
   of list beside an empty 22rem of nothing. */
.sec--nopic .sec__body{grid-template-columns:minmax(0,1fr)}
/* A rail tile with no photograph sits on the brand ground. No scrim over it:
   the scrim exists to hold type off a picture, and there is no picture. */
.tile--plain{background:linear-gradient(160deg,var(--sea),var(--deep))}
.tile--plain .tile__scrim{display:none}
@media (min-width:60rem){
  .sec__body{grid-template-columns:22rem minmax(0,1fr)}
  /* 🔴 `order` MOVES A CHILD, IT DOES NOT MOVE THE COLUMN WIDTH. Sending the
     photograph to the right put it in the 1fr column and squeezed the MENU
     ITSELF into 22rem: in four of the nine sections the item list rendered at
     352px while the other five had 784px — names wrapping, prices crowding
     their buttons — and the photograph was blown up to 784px from a file as
     small as 400px (Strombolis, a 1.96x upscale). The alternation was meant to
     swap which SIDE the picture is on, never which one gets the room.
     ⭐ So the columns swap with it: the picture is 22rem on both sides and the
     menu keeps the rest, every section. */
  .sec:nth-of-type(even) .sec__body{grid-template-columns:minmax(0,1fr) 22rem}
  .sec:nth-of-type(even) .sec__shot{order:2}
}
.sec__shot{position:sticky;top:calc(var(--stick) + var(--m-filters) + var(--m-rail) + 1.5rem)}
.sec__shot img{width:100%;border-radius:var(--r);box-shadow:var(--shadow)}
@media (max-width:59.99rem){.sec__shot{position:static}
  .sec__shot img{aspect-ratio:16/9;object-fit:cover}}

.items{list-style:none;margin:0;padding:0;display:grid;gap:.25rem;
  container-type:inline-size}
.item{display:flex;gap:1rem;align-items:flex-start;justify-content:space-between;
  padding:.95rem .25rem;border-bottom:1px dashed var(--rule);
  scroll-margin-top:calc(var(--stick) + var(--m-filters) + var(--m-rail) + 1rem)}
.item:last-child{border-bottom:0}
.item__text{min-width:0}
.item h3{font-family:var(--sans);font-size:1.0625rem;font-weight:700;
  letter-spacing:0;margin:0 0 .15em}
.desc{font-size:.9375rem;color:var(--ink-2);margin:0;max-width:52ch}
.tags{list-style:none;display:flex;flex-wrap:wrap;gap:.35rem;margin:.45rem 0 0;padding:0}
.tag{font-size:.6875rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  padding:.2rem .5rem;border-radius:.3rem;background:var(--foam);color:var(--sea)}
.tag--heat{background:#fde9e2;color:var(--crust)}
.tag--pork{background:#f2efe9;color:#6b6256}
.item__buy{display:flex;flex-direction:column;align-items:flex-end;gap:.35rem;
  flex-shrink:0}
.opt{display:flex;align-items:center;gap:.55rem;font-variant-numeric:tabular-nums}
.sz{font-size:.75rem;color:var(--ink-2);font-weight:700;letter-spacing:.02em}
.amt{font-weight:700;font-size:1.0625rem;white-space:nowrap;
  min-width:4.25rem;text-align:right}
.add{width:44px;min-height:44px;border-radius:.6rem;border:1.5px solid var(--line);
  background:var(--paper);color:var(--sea);font-size:1.35rem;font-weight:600;
  line-height:1;cursor:pointer;display:grid;place-items:center;
  transition:background-color .14s,border-color .14s,transform .1s}
.add:hover{background:var(--sea);border-color:var(--sea);color:#fff}
.add:active{transform:scale(.94)}
.add.is-in{background:var(--sea);border-color:var(--sea);color:#fff}
@container (max-width:30rem){
  .item{flex-wrap:wrap;gap:.35rem}
  .item__buy{width:100%;flex-direction:row;flex-wrap:wrap;
    justify-content:flex-end;gap:.35rem .9rem}
}

/* ---------------------------------------------------------------- scale */
.scale{padding-block:clamp(2.5rem,5vw,4rem);border-top:1px solid var(--rule);
  text-align:center}
.scale h2{font-size:clamp(1.6rem,4vw,2.25rem)}
.scale > p{max-width:46ch;margin-inline:auto;color:var(--ink-2)}
.scale__pair{display:flex;gap:clamp(1.5rem,6vw,4rem);justify-content:center;
  align-items:flex-end;flex-wrap:wrap;margin-top:2rem}
.scale__f{margin:0}
.disc{border-radius:50%;display:grid;place-items:center;margin-inline:auto;
  background:radial-gradient(circle at 50% 42%,#f2c879 0 62%,#e0a84f 63%,#c4823a 100%);
  box-shadow:inset 0 0 0 .55rem #d9a558,var(--shadow);color:#5c3a13;
  font:700 1.05rem/1 var(--sans)}
.disc--14{width:min(11rem,38vw);aspect-ratio:1}
.disc--16{width:min(12.57rem,43.4vw);aspect-ratio:1}
.scale figcaption{font-size:.875rem;color:var(--ink-2);margin-top:.9rem}

/* --------------------------------------------------------------- extras */
.extras{padding-block:clamp(2.5rem,5vw,4rem);border-top:1px solid var(--rule)}
.extras h2{font-size:clamp(1.5rem,3.5vw,2rem)}
.extras__grid{display:grid;gap:1.5rem 2.5rem;
  grid-template-columns:repeat(auto-fit,minmax(16rem,1fr))}
.extras h3{font-family:var(--sans);font-size:.8125rem;font-weight:800;
  text-transform:uppercase;letter-spacing:.08em;color:var(--sea);margin-bottom:.4em}
.extras p{font-size:.9375rem;color:var(--ink-2);margin:0}

/* ----------------------------------------------------------------- tray */
.tray{position:fixed;left:0;right:0;bottom:0;z-index:45;
  background:var(--ink);color:#fff;box-shadow:0 -8px 30px -12px rgba(0,0,0,.5);
  padding-bottom:env(safe-area-inset-bottom)}
.tray[hidden]{display:none!important}
.tray__in{width:min(100% - (var(--gut)*2),var(--shell));margin-inline:auto;
  display:flex;align-items:center;gap:1rem;justify-content:space-between;
  padding-block:.7rem;flex-wrap:wrap}
.tray__sum{margin:0;font-weight:600;font-size:.9375rem}
.tray__sum b{font-size:1.125rem}

.sheet{border:0;padding:0;border-radius:var(--r);max-width:32rem;width:calc(100% - 2rem);
  box-shadow:var(--shadow-lg);background:var(--paper);color:var(--ink)}
.sheet::backdrop{background:rgba(6,26,32,.55);backdrop-filter:blur(3px)}
.sheet__in{padding:1.5rem}
.sheet__top{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem}
.sheet__top h2{font-size:1.6rem;margin:0}
.sheet__x{width:44px;height:44px;border:0;background:transparent;font-size:1.75rem;
  line-height:1;cursor:pointer;color:var(--ink-2);border-radius:.5rem}
.sheet__x:hover{background:var(--foam);color:var(--ink)}
.sheet__list{list-style:none;margin:1rem 0;padding:0;max-height:45vh;overflow:auto}
.sheet__list li{display:flex;align-items:center;gap:.75rem;padding:.6rem 0;
  border-bottom:1px dashed var(--rule)}
.sheet__list .n{flex:1;min-width:0;font-size:.9375rem}
.sheet__list .n small{display:block;color:var(--ink-2)}
.sheet__list .q{display:flex;align-items:center;gap:.35rem}
.sheet__list .q button{width:36px;height:44px;border:1.5px solid var(--line);
  background:var(--paper);border-radius:.5rem;cursor:pointer;font-size:1.1rem;
  color:var(--sea)}
.sheet__list .q button:hover{background:var(--foam)}
.sheet__list .c{min-width:1.5rem;text-align:center;font-weight:700;
  font-variant-numeric:tabular-nums}
.sheet__list .s{font-weight:700;min-width:4rem;text-align:right;
  font-variant-numeric:tabular-nums}
/* Remove-a-line and Undo. The × is quieter than the −/+ pair beside it --
   it is the rarer action and it should not compete for the thumb -- but it is
   the same 44px target, because "quieter" is a matter of colour, never size. */
.sheet__x-item{flex:0 0 auto;width:44px;height:44px;display:flex;
  align-items:center;justify-content:center;border:0;background:none;
  border-radius:.5rem;cursor:pointer;font-size:1.25rem;line-height:1;
  color:var(--ink-2)}
.sheet__x-item:hover{background:var(--foam);color:var(--ink)}
.sheet__undo{background:none;border:0;color:var(--sea);font:inherit;
  font-weight:800;text-decoration:underline;cursor:pointer;padding:.2rem .35rem;
  min-height:44px}
/* 🔴 ADDING THE × BROKE THE ROW AT 375px: it took 44px off a line that had
   none spare, and "Garlic Knots & Marinara" wrapped to FOUR lines beside a
   two-character quantity. On a narrow phone the name takes the whole first
   line and the controls sit under it, which is also the order you read them
   in: what it is, then how many, then what it costs, then take it off. */
@media (max-width:26rem){
  .sheet__list li{flex-wrap:wrap}
  .sheet__list .n{flex:1 0 100%;margin-bottom:.35rem}
  .sheet__list .s{margin-left:auto}
}
.sheet__total{display:flex;justify-content:space-between;align-items:baseline;
  font-size:1.125rem;margin:.5rem 0;padding-top:.5rem;border-top:2px solid var(--ink)}
.sheet__total b{font-size:1.5rem;font-family:var(--serif)}
.sheet__note{font-size:.8125rem;color:var(--ink-2)}
.sheet__diet{font-size:.8125rem;color:var(--ink-2);margin:.15rem 0 0}
.sheet__acts{display:flex;gap:.6rem;flex-wrap:wrap;margin-top:1rem}
.sheet__acts .btn{flex:1 1 10rem}
.sheet__hint{font-size:.875rem;color:var(--sea);font-weight:600;min-height:1.4em;margin:.6rem 0 0}
.sheet__clear{background:none;border:0;color:var(--ink-2);text-decoration:underline;
  cursor:pointer;font-size:.875rem;padding:.6rem 0;min-height:44px}
.sheet__empty{color:var(--ink-2);padding:1.5rem 0;text-align:center}

/* ---------------------------------------------------------------- prose */
.prose{padding-block:clamp(2.5rem,6vw,4.5rem);max-width:42rem}
.chap{margin-bottom:clamp(2rem,5vw,3.5rem)}
.chap h2{font-size:clamp(1.5rem,3.5vw,2.15rem)}
.chap p{font-size:1.0625rem}
.chap--commit{background:var(--foam);border-radius:var(--r);padding:1.75rem}
.commit{font-family:var(--serif);font-size:1.1875rem;line-height:1.55;margin-bottom:.6em}
.chap--commit cite{font-style:normal;font-weight:700;font-size:.875rem;
  text-transform:uppercase;letter-spacing:.05em;color:var(--sea)}
.src{font-size:.8125rem;color:var(--ink-2);border-top:1px solid var(--line);
  padding-top:1rem}

/* ---------------------------------------------------------------- order */
.order,.visitp{padding-block:clamp(2.5rem,6vw,4.5rem)}
/* The shop's own photographs: the family, the room, the counter. Full-bleed
   inside the page shell, caption under, no crop games — they were taken for
   this and they can carry their own frame. */
.storyshot,.whyshot{margin:2rem 0}
.storyshot img,.whyshot img{width:100%;display:block;border-radius:var(--r);
  box-shadow:var(--shadow)}
.storyshot figcaption,.whyshot figcaption{margin-top:.6rem;font-size:.9375rem;
  color:var(--ink-2)}
.storyshot--room{max-width:34rem;margin-inline:auto}
/* The counter, on Find us. Wide enough that the boards are readable, capped so
   it does not become the page. */
.visitshot{margin:0 0 2.5rem;max-width:40rem}
.visitshot img{width:100%;display:block;border-radius:var(--r);
  box-shadow:var(--shadow)}
.visitshot figcaption{margin-top:.6rem;font-size:.9375rem;color:var(--ink-2)}
.whyshot{max-width:50rem}
.why{max-width:52rem;margin-block:2.5rem}
/* The crowd block with its photograph beside it. One column on a phone, where
   the picture belongs UNDER the words it illustrates, not above them. */
.why--pic{max-width:none;display:grid;gap:clamp(1.25rem,3vw,2.5rem);
  align-items:start}
@media (min-width:60rem){.why--pic{grid-template-columns:minmax(0,34rem) 20rem}}
.why__shot{margin:0}
.why__shot img{width:100%;border-radius:var(--r);box-shadow:var(--shadow);
  display:block}
.why h2{font-size:clamp(1.5rem,3.5vw,2rem)}
.notice{background:var(--paper);border:1px solid var(--line);border-left:4px solid var(--sea);
  border-radius:var(--r);padding:1.25rem 1.5rem;margin-bottom:1.5rem}
.notice h3{font-family:var(--sans);font-size:1rem;font-weight:800;margin-bottom:.4em}
.notice p:last-child{margin-bottom:0}
.notice--hold{border-left-color:var(--crust);background:#fff8f4}
.fees{margin:.5rem 0 0;padding-left:1.1rem}
.visit__in--order{margin-top:2.5rem}
.visitp__g{display:grid;gap:1.5rem;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));
  margin-bottom:2.5rem}
.card{background:var(--paper);border:1px solid var(--line);border-radius:var(--r);
  padding:1.5rem}
.card h2{font-size:1.25rem;font-family:var(--sans);font-weight:800}
/* A photo tile in the same row as the information tiles: same border and
   radius, but the picture runs to the edges, so padding goes on the caption. */
.card--shot{padding:0;overflow:hidden;margin:0;display:flex;
  flex-direction:column}
.card--shot img{width:100%;display:block}
.card--shot figcaption{padding:1rem 1.25rem;font-size:.9375rem;
  color:var(--ink-2)}

/* --------------------------------------------------------------- footer */
.foot{background:var(--ink);color:#b9ced2;margin-top:auto;
  padding-block:clamp(2.5rem,5vw,3.5rem) 0}
.foot__in{display:grid;gap:2rem;grid-template-columns:repeat(auto-fit,minmax(14rem,1fr))}
.foot h2{font-size:.8125rem;font-family:var(--sans);font-weight:800;color:#fff;
  text-transform:uppercase;letter-spacing:.08em}
.foot__logo{height:4rem;width:auto;margin-bottom:1rem}
.foot a{color:#fff;text-decoration:none;display:inline-flex;align-items:center;min-height:2rem}
.foot a:hover{text-decoration:underline}
.foot nav{display:flex;flex-direction:column}
.foot .hr{border-bottom-color:rgba(255,255,255,.12)}
.foot .hr dt{color:#fff;font-weight:500}
.foot .hr dd{color:#9fb6bb}
.foot .hr--shut dt,.foot .hr--shut dd{color:#8499a0}
.foot .hr[data-today]{background:rgba(255,255,255,.07)}
.foot .hr[data-today] dt::after{color:var(--surf-t)}
.foot__soc{display:flex;gap:1rem;flex-wrap:wrap;margin-top:.75rem}
.foot__law{border-top:1px solid rgba(255,255,255,.12);margin-top:2.5rem;padding-block:1.25rem}
.foot__law p{font-size:.8125rem;color:#8fa6ab;margin:0;max-width:72ch}

/* --------------------------------------------------------------- reveal */
/* The class is added BY SCRIPT, never in the markup. If the script does not
   run -- blocked, errored, disabled -- nothing ever gets opacity:0, so the
   page is simply a page. A reveal that can strand content invisible is worse
   than no reveal. */
.reveal{opacity:0;transform:translateY(1.5rem);
  transition:opacity .7s cubic-bezier(.2,.7,.3,1),
             transform .7s cubic-bezier(.2,.7,.3,1)}
.reveal.is-in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .reveal,.reveal.is-in{opacity:1;transform:none;transition:none}
}

/* ---------------------------------------------- guest dock (phone) ---- *
 * Call + Directions, always in the thumb zone. Wide screens already have
 * both in the header and the visit band, so this is phones only. */
.dock{display:none}
@media (max-width:56rem){
  /* The pills FLOAT. They used to sit in a full-width sand bar with a border
     along the top, which reads as a second footer bolted to the screen and
     cuts the page off at a hard line. No bar: the two pills hover over the
     content with an inset all round, and the content runs under them.
     ⭐ pointer-events on the nav is off and back on for the pills, or the
     invisible strip between and around them would swallow taps on whatever
     is underneath — a full-width fixed element with nothing drawn in it is
     still a full-width fixed element. */
  .dock{display:flex;gap:.6rem;align-items:stretch;
    position:fixed;z-index:44;pointer-events:none;
    left:var(--gut);right:var(--gut);
    bottom:calc(.9rem + env(safe-area-inset-bottom))}
  .dock a{pointer-events:auto;
    flex:1 1 0;display:inline-flex;align-items:center;justify-content:center;
    min-height:48px;padding:.7rem 1rem;border-radius:999px;
    font:700 1rem/1 var(--sans);text-decoration:none;
    /* Two shadows: a soft long one to lift it off the page, a tight one to
       keep the edge crisp against a photograph. */
    box-shadow:0 12px 28px -10px rgba(18,38,44,.45),
               0 2px 6px rgba(18,38,44,.18)}
  /* 🔴 `flex:1.35` HAS NEVER APPLIED. `.dock a` is (0,1,1) and `.dock__go` is
     (0,1,0), so the descendant selector won and both pills came out the same
     width — Call kitchen was meant to be the wider of the two and never was.
     Found by measuring the rendered pills, not by reading the file: the rule
     is right there and looks like it works. */
  .dock a.dock__go{flex:1.35 1 0;background:var(--powder);color:var(--ink);
    border:2px solid var(--powder-edge)}
  .dock a.dock__go:hover{background:var(--powder-2);border-color:var(--sea)}
  .dock__dir{background:var(--paper);color:var(--sea);border:2px solid var(--sea)}
  .dock__dir:hover{background:var(--foam)}
  /* Out of the way while the hero owns the screen, and genuinely gone —
     visibility, so a tucked pill is not left in the tab order. */
  .dock a{transition:transform .28s ease, opacity .22s ease, visibility .28s,
    background-color .15s ease, border-color .15s ease}
  .dock.is-tucked a{opacity:0;visibility:hidden;transform:translateY(135%)}
  @media (prefers-reduced-motion:reduce){
    .dock a{transition:opacity .01ms, visibility .01ms}
    .dock.is-tucked a{transform:none}
  }
}
body:has(#tray:not([hidden])) .dock{display:none!important}

/* ------------------------------------------------- reading options
   A pizza slice, bottom LEFT — the order helper owns bottom right and the
   floating Call/Directions pills own the bottom edge on a phone, so this sits
   clear of both.
   ⛔ It is not an accessibility overlay and says so nowhere, because it is
   not one. Four switches that actually change the page, and a phone number
   for when they are not enough. */
.ro{position:fixed;z-index:46;left:var(--gut);
  bottom:calc(.9rem + env(safe-area-inset-bottom))}
@media (max-width:56rem){
  /* above the floating pills, not under them */
  .ro{bottom:calc(4.6rem + env(safe-area-inset-bottom))}
}
/* ⭐ THE IMAGE IS THE BUTTON. No pill, no circle, no chrome — the slice sits
   on the page on its own. It can, because the mark now carries the
   accessibility figure, so it identifies itself without a frame or a word
   beside it. */
.ro__btn{display:inline-flex;align-items:center;justify-content:center;
  min-height:48px;min-width:48px;padding:2px;
  border:0;background:none;cursor:pointer;
  transition:transform .18s ease}
.ro__btn:hover{transform:scale(1.08)}
.ro__btn:focus-visible{outline:3px solid var(--sea);outline-offset:3px;
  border-radius:.5rem}
/* A drop-shadow on the artwork itself, not a box behind it: the slice has to
   hold its edge over a photograph without gaining a card to sit in. */
.ro__slice{width:46px;height:46px;flex:0 0 auto;
  filter:drop-shadow(0 6px 10px rgba(18,38,44,.45))
         drop-shadow(0 1px 2px rgba(18,38,44,.5))}
/* The word stays for anything that reads the page aloud, and for the button's
   accessible name — it is simply not drawn. */
.ro__label{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
.ro__panel{position:absolute;bottom:calc(100% + .6rem);left:0;
  width:min(20rem,calc(100vw - 2*var(--gut)));
  background:var(--paper);color:var(--ink);
  border:1px solid var(--line);border-radius:var(--r);
  padding:1.1rem 1.15rem 1rem;
  box-shadow:0 22px 48px -18px rgba(18,38,44,.55)}
.ro__panel[hidden]{display:none}
.ro__h{font-family:var(--sans);font-size:1rem;font-weight:800;margin:0}
.ro__sub{margin:.2rem 0 .9rem;font-size:.8125rem;color:var(--ink-2)}
.ro__row{display:flex;align-items:center;justify-content:space-between;
  gap:.6rem;margin-bottom:.7rem}
.ro__k{font-size:.9375rem;font-weight:700}
.ro__steps{display:flex;align-items:center;gap:.35rem}
.ro__step{width:44px;height:44px;border-radius:.6rem;cursor:pointer;
  border:1.5px solid var(--line);background:var(--sand);color:var(--sea);
  font-size:1.15rem;font-weight:800;line-height:1}
.ro__step:hover{background:var(--foam);border-color:var(--sea)}
.ro__val{min-width:3.2rem;text-align:center;font-weight:700;
  font-variant-numeric:tabular-nums;font-size:.9375rem}
.ro__sw{display:flex;width:100%;align-items:center;justify-content:space-between;
  gap:.6rem;min-height:44px;margin-bottom:.4rem;padding:.55rem .75rem;
  border-radius:.6rem;border:1.5px solid var(--line);background:var(--sand);
  color:var(--ink);cursor:pointer;font:700 .9375rem/1.25 var(--sans);
  text-align:left}
.ro__sw::after{content:"Off";flex:0 0 auto;font-size:.75rem;font-weight:800;
  letter-spacing:.06em;text-transform:uppercase;color:var(--ink-2)}
.ro__sw[aria-pressed="true"]{background:var(--powder);
  border-color:var(--powder-edge)}
.ro__sw[aria-pressed="true"]::after{content:"On";color:var(--ink)}
.ro__sw:hover{border-color:var(--sea)}
.ro__reset{margin-top:.35rem;background:none;border:0;cursor:pointer;
  color:var(--sea);text-decoration:underline;font:600 .875rem var(--sans);
  min-height:44px;padding:.5rem 0}
.ro__note{margin:.5rem 0 0;font-size:.8125rem;color:var(--ink-2)}
.ro__note a{color:var(--sea);font-weight:700}

/* ---- what the switches actually do ---------------------------------- */
/* Stronger contrast: darker ink, white grounds, borders that do not vanish.
   ⛔ Tokens only. Nothing here restyles a component, so a contrast pass can
   never move the layout. */
html[data-ro-contrast]{
  --ink:#000000;
  --ink-2:#1f1f1f;
  --sand:#ffffff;
  --foam:#eef8fa;
  --sea:#004154;
  --line:#5a6a70;
  --rule:#8a979c;
}
html[data-ro-contrast] a{text-decoration:underline}
html[data-ro-contrast] .tile__scrim{
  background:linear-gradient(to top,rgba(0,0,0,.94) 0%,rgba(0,0,0,.8) 34%,
    rgba(0,0,0,.5) 66%,rgba(0,0,0,.25) 100%)}

/* Underline every link, including the ones styled as plain text. */
html[data-ro-underline] a{text-decoration:underline !important}

/* Stop the moving pictures. The rails are driven by script, so app.js checks
   this same attribute; these rules take care of everything CSS animates. */
html[data-ro-still] *,
html[data-ro-still] *::before,
html[data-ro-still] *::after{
  animation-duration:.01ms !important;
  animation-iteration-count:1 !important;
  transition-duration:.01ms !important;
  scroll-behavior:auto !important}

/* ---------------------------------------------------------------- misc */
body{display:flex;flex-direction:column;min-height:100svh}
main{flex:1 0 auto}
.sec,.extras{content-visibility:auto;contain-intrinsic-size:auto 600px}
body:has(#tray:not([hidden])) .foot{padding-bottom:5rem}
@media (max-width:56rem){
  /* The floating pills overlap the footer instead of being stacked under it,
     so the footer still needs clearance — a little more, because the pills
     now sit a gap above the edge rather than flush to it. */
  body:has(.dock) .foot{padding-bottom:calc(6rem + env(safe-area-inset-bottom))}
  body:has(#tray:not([hidden])) .foot{padding-bottom:5rem}
}
@media print{
  .topbar,.mast,.rail,.filters,.tray,.sheet,.adds,.hero__cta,.ords,.dock,.hero__pickup{display:none!important}
  body{background:#fff;font-size:11pt}
  .sec{break-inside:avoid;content-visibility:visible}
}

/* ----------------------------------------------------------------- ask */
/* The order helper. A launcher that clears the sticky tray on the menu
   page, and a dialog that is a real <dialog> -- so Esc closes it, focus is
   trapped, and the rest of the page is inert while it is open. */
.ask__open{position:fixed;right:1rem;bottom:1rem;z-index:46;
  display:inline-flex;align-items:center;gap:.5rem;min-height:48px;
  padding:.7rem 1.1rem;border:0;border-radius:999px;cursor:pointer;
  background:var(--sea);color:#fff;font:700 .9375rem/1 var(--sans);
  box-shadow:0 10px 30px -10px rgba(6,26,32,.6);
  transition:transform .15s ease, background-color .15s ease}
.ask__open:hover{background:var(--sea-2);transform:translateY(-2px)}
.ask__open svg{width:1.15rem;height:1.15rem;fill:currentColor}
/* the menu page's order tray also lives bottom-right; step over it */
/* The order bar is on every page now, so the helper always sits above it. */
body:has(#tray:not([hidden])) .ask__open{bottom:5.25rem}
@media (max-width:56rem){
  .ask__open{bottom:calc(4.85rem + env(safe-area-inset-bottom))}
  body:has(#tray:not([hidden])) .ask__open{bottom:5.25rem}
}
.tray__sum{display:flex;align-items:baseline;gap:.4rem}
@media (max-width:30rem){.ask__open span{display:none}
  .ask__open{padding:.8rem;border-radius:50%}}

.ask{border:0;padding:0;border-radius:var(--r);background:var(--paper);
  color:var(--ink);width:min(30rem,calc(100% - 1.5rem));max-height:min(82svh,44rem);
  box-shadow:var(--shadow-lg);margin:auto auto 1rem}
.ask::backdrop{background:rgba(6,26,32,.55);backdrop-filter:blur(3px)}
.ask__in{display:flex;flex-direction:column;max-height:inherit;
  height:min(82svh,44rem);max-height:100%}
/* Their mark, decorative here: the dialog is already titled "Zen Pizza /
   Order helper" in text, so alt="" and aria-hidden keep a screen reader from
   reading the name three times. */
.ask__logo{height:2.6rem;width:auto;flex:0 0 auto;margin-top:.1rem}
.ask__top{display:flex;align-items:flex-start;gap:.75rem;padding:1rem 1.15rem .75rem;
  background:linear-gradient(165deg,var(--sea),var(--deep));color:#fff;
  border-radius:var(--r) var(--r) 0 0}
.ask__k{margin:0;font-size:.6875rem;font-weight:800;letter-spacing:.1em;
  text-transform:uppercase;color:var(--surf-t)}
.ask__top h2{margin:0;color:#fff;font-size:1.25rem}
.ask__x{margin-left:auto;width:44px;height:44px;border:0;background:transparent;color:#cfe3e6;
  font-size:1.6rem;line-height:1;cursor:pointer;border-radius:.5rem}
.ask__x:hover{background:rgba(255,255,255,.14);color:#fff}

/* min-height:0 is the whole fix. A flex item will not shrink below its
   content's height without it, so the log kept its full height and pushed the
   chips, the input and the note straight out of the dialog's max-height --
   the bottom of the panel was there, just outside the box. */
.ask__log{flex:1 1 auto;min-height:0;overflow-y:auto;padding:1rem 1.15rem;
  display:flex;flex-direction:column;gap:.7rem;background:var(--sand)}
.ask__chips,.ask__form,.ask__note{flex:0 0 auto}
.ask__msg{max-width:88%;padding:.7rem .9rem;border-radius:1rem;
  font-size:.9375rem;line-height:1.5}
.ask__msg--bot{background:var(--paper);border:1px solid var(--line);
  border-bottom-left-radius:.3rem;align-self:flex-start}
.ask__msg--me{background:var(--sea);color:#fff;
  border-bottom-right-radius:.3rem;align-self:flex-end}
.ask__msg a{color:var(--sea);font-weight:600}
.ask__msg--me a{color:#fff}

.ask__item{border-top:1px dashed var(--rule);margin-top:.6rem;padding-top:.6rem}
.ask__item-n{margin:0;font-weight:700}
.ask__item-d{margin:.1rem 0 .3rem;font-size:.875rem;color:var(--ink-2)}
.ask__item-p{margin:0 0 .45rem;font-weight:700;font-variant-numeric:tabular-nums}
.ask__sz{font-size:.75rem;color:var(--ink-2);font-weight:600}
.ask__adds{display:flex;gap:.4rem;flex-wrap:wrap}
.ask__add{min-height:36px;padding:.35rem .8rem;border-radius:999px;
  border:1.5px solid var(--sea);background:var(--paper);color:var(--sea);
  font:700 .8125rem/1 var(--sans);cursor:pointer}
.ask__add:hover{background:var(--sea);color:#fff}
.ask__add[disabled]{border-color:var(--line);color:var(--ink-2);
  background:var(--foam);cursor:default}
/* float:right put the price beside the FIRST line of a name that wrapped.
   A flex row keeps the money on the baseline of the whole item. */
.ask__list{margin:.5rem 0;padding:0;list-style:none;font-size:.9375rem}
.ask__list li{display:flex;gap:.6rem;align-items:baseline;
  padding:.2rem 0;border-bottom:1px dashed var(--rule)}
.ask__list li:last-child{border-bottom:0}
.ask__list b{margin-left:auto;font-variant-numeric:tabular-nums;
  white-space:nowrap}
.ask__tot{margin:.4rem 0 0;font-size:.9375rem}
.ask__undo{background:none;border:0;color:var(--sea);font:inherit;font-weight:800;
  text-decoration:underline;cursor:pointer;padding:.2rem .35rem;min-height:44px}
.ask__qb--x{color:var(--ink-2)}
.ask__qb--x:hover{color:var(--ink)}
.ask__more{margin:.5rem 0 0;font-size:.875rem;color:var(--ink-2)}
.ask__secs{display:flex;flex-wrap:wrap;gap:.35rem;margin-top:.6rem}
.ask__acts{display:flex;flex-wrap:wrap;gap:.45rem;margin-top:.7rem}
.ask__go{display:inline-flex;align-items:center;min-height:40px;
  padding:.45rem 1rem;border-radius:999px;background:var(--powder);
  color:var(--ink);text-decoration:none;font-weight:700;font-size:.875rem;
  border:1.5px solid var(--powder-edge);cursor:pointer}
/* .ask__msg a is (0,2,0) and was beating .ask__go (0,1,0) on the label
   colour -- teal on powder blue at 5.2:1 instead of ink at 9.7:1. */
.ask__msg .ask__go,.ask__go{color:var(--ink)}
.ask__go:hover{background:var(--powder-2);border-color:var(--sea)}
.ask__go--alt{background:transparent;color:var(--sea);
  border:1.5px solid currentColor}
.ask__go--alt:hover{background:var(--foam)}

.ask__chips{display:flex;gap:.4rem;overflow-x:auto;scrollbar-width:none;
  padding:.7rem 1.15rem 0;background:var(--sand)}
.ask__chips::-webkit-scrollbar{display:none}
.ask__chip{flex:0 0 auto;min-height:36px;padding:.4rem .85rem;border-radius:999px;
  border:1.5px solid var(--line);background:var(--paper);color:var(--ink);
  font:600 .8125rem/1 var(--sans);cursor:pointer;white-space:nowrap}
.ask__chip:hover{border-color:var(--sea);color:var(--sea)}

.ask__form{display:flex;gap:.5rem;padding:.75rem 1.15rem;background:var(--sand);
  border-top:1px solid var(--line)}
.ask__form input{flex:1;min-height:44px;padding:.6rem .9rem;border-radius:999px;
  border:1.5px solid var(--line);background:var(--paper);color:var(--ink);
  font:400 1rem/1.2 var(--sans)}
.ask__form input:focus{border-color:var(--sea);outline:none}
.ask__send{width:44px;height:44px;flex:0 0 auto;border:0;border-radius:50%;
  background:var(--sea);color:#fff;cursor:pointer;display:grid;place-items:center}
.ask__send:hover{background:var(--sea-2)}
.ask__send svg{width:1.05rem;height:1.05rem;fill:currentColor}
.ask__note{margin:0;padding:0 1.15rem .9rem;font-size:.75rem;color:var(--ink-2);
  background:var(--sand);border-radius:0 0 var(--r) var(--r)}
@media print{.ask,.ask__open{display:none !important}}

/* the mic. Script unhides it only where recognition actually exists. */
.ask__mic{width:44px;height:44px;flex:0 0 auto;border:1.5px solid var(--line);
  border-radius:50%;background:var(--paper);color:var(--sea);cursor:pointer;
  display:grid;place-items:center;transition:background-color .15s, color .15s}
.ask__mic[hidden]{display:none !important}
.ask__mic svg{width:1.15rem;height:1.15rem;fill:currentColor}
.ask__mic:hover{border-color:var(--sea);background:var(--foam)}
.ask__mic.is-on{background:var(--crust);border-color:var(--crust);color:#fff}
/* a listening indicator that is not just a colour change, for anyone who
   cannot tell red from white */
.ask__mic.is-on::after{content:"";position:absolute;width:44px;height:44px;
  border-radius:50%;border:2px solid var(--crust);animation:ping 1.4s ease-out infinite}
.ask__mic{position:relative}
@media (prefers-reduced-motion:reduce){.ask__mic.is-on::after{animation:none}}

/* the standing order strip inside the panel */
.ask__bar{display:flex;align-items:center;justify-content:space-between;gap:1rem;
  width:100%;min-height:44px;padding:.6rem 1.15rem;border:0;cursor:pointer;
  background:var(--foam);border-bottom:1px solid var(--line);
  color:var(--ink);font:600 .875rem/1.2 var(--sans);text-align:left}
.ask__bar[hidden]{display:none !important}
.ask__bar:hover{background:var(--powder)}
.ask__bar-go{color:var(--sea);font-weight:700;white-space:nowrap}
.ask__bar b{font-size:1rem}

/* quantity controls in the order view */
.ask__q{display:inline-flex;align-items:center;gap:.2rem;flex:0 0 auto}
.ask__qb{width:30px;height:30px;border:1.5px solid var(--line);border-radius:.45rem;
  background:var(--paper);color:var(--sea);font:700 1rem/1 var(--sans);
  cursor:pointer;display:grid;place-items:center;padding:0}
.ask__qb:hover{background:var(--foam);border-color:var(--sea)}
.ask__qn{min-width:1.25rem;text-align:center;font-weight:700;
  font-variant-numeric:tabular-nums}

/* the launcher steps aside while the hero owns the screen */
.ask__open{transition:transform .25s ease, opacity .25s ease,
  background-color .15s ease, visibility .25s}
.ask__open.is-tucked{opacity:1;transform:none;visibility:visible;pointer-events:auto}
@media (prefers-reduced-motion:reduce){
  .ask__open{transition:opacity .01ms, visibility .01ms}
  .ask__open.is-tucked{opacity:1;transform:none;visibility:visible;pointer-events:auto}
}
/* chips wrap rather than scrolling off the edge */
.ask__chips{flex-wrap:wrap;overflow-x:visible;padding-bottom:.15rem}

/* order-helper-always-visible */
body:not(.no-js) .ask__open{display:inline-flex!important;visibility:visible!important;opacity:1!important;pointer-events:auto!important;z-index:60}
@media print{body:not(.no-js) .ask__open{display:none!important}}
