/* --- base --- */
/* The page root and the shared primitives every block builds out of — the first file
   dist/site-blocks.css concatenates, so a block's own rules always win on equal specificity.

   Written entirely in var(--site-*): not one hex, one font name, one radius or one type size lives
   here, because a literal is a value one of the four packs could not repaint (spec/style-packs.md
   §0 rule 2). The mobile values stand at the root; the single breakpoint is @media (min-width:900px)
   and there is no other (spec/mockup-conventions.md §3). Markup that pairs with these classes is in
   the wave-1 mockups, context/design-builder/mockups/site-*-*.html — those files are the source of
   truth for how a block looks, and this css is their BLOCKS-CSS carried over unchanged. */

.sb-page,.sb-page *{box-sizing:border-box}
.sb-page{
  background:var(--site-bg);color:var(--site-ink);
  font-family:var(--site-body);font-size:var(--site-body-size);line-height:var(--site-body-lh);
  font-stretch:var(--site-body-stretch,normal);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}
:where(.sb-page) :is(p,h1,h2,h3,h4,ul,ol,figure,dl,dd,blockquote){margin:0}
:where(.sb-page) :is(ul,ol){padding:0;list-style:none}
:where(.sb-page) a{color:inherit;text-decoration:none}
:where(.sb-page) img{display:block;width:100%;height:100%;object-fit:cover}
:where(.sb-page) svg{width:1.25em;height:1.25em;flex:none}
:where(.sb-page) button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
:where(.sb-page) :is(h1,h2,h3,h4){
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  line-height:var(--site-display-lh);letter-spacing:var(--site-display-ls);
  text-transform:var(--site-display-case);
}
:where(.sb-page) h1{font-size:var(--site-h1)}
:where(.sb-page) h2{font-size:var(--site-h2);line-height:1.08}
:where(.sb-page) h3{font-size:var(--site-h3);line-height:1.15}
:where(.sb-page) h4{font-size:var(--site-h4);line-height:1.2}
.sb-page :focus-visible{outline:.125em solid var(--site-accent);outline-offset:.125em}

.site-block{background:var(--site-bg);color:var(--site-ink)}

/* РИТМ ПОЛОСЫ — ОДНО ПРАВИЛО НА ВЕСЬ НАБОР, а не восемнадцать копий.

   Воздух полосы объявляется здесь один раз: `--site-section-y` по вертикали, `--site-gutter` по
   горизонтали, и оба шага на десктопе внизу файла. До этого узла правило `.sb-section` ниже не
   читал НИКТО (ни один блок не носил этот класс), а каждый block.css переписывал ту же пару себе —
   и копии разошлись:
     • `site-footer` перенёс на десктоп только горизонтальную половину, и подвал стоял на мобильной
       вертикали — вдвое теснее соседей;
     • `points-map` объявил ту же пару НА `__inner` вместе с `max-width`, отчего колонка карты
       оказалась уже соседних ровно на два поля, а сама полоса — без полей вовсе.
   Одно правило снимает целый класс таких расхождений: забыть половину нечего, забывать больше
   негде. Тест purity («ни один block.css не повторяет общий ритм») держит это состояние.

   ПОЧЕМУ СЕЛЕКТОР — `[data-slot]`, А НЕ `.site-block`. Класс `site-block` носит не только полоса:
   его пишет себе и ВЛОЖЕННЫЙ блок (`dish-card/View.tsx` — карточка блюда внутри `menu-catalog` и
   `menu-highlights` через `renderPage` не проходит и обёртку выписывает сама, ради краски и схемы).
   Карточка блюда — не полоса, и воздух страницы внутри неё это раздутая карточка с фотографией,
   оторванной от собственной кромки. `data-slot` пишет ТОЛЬКО `renderPage`/`renderBlock`, и только
   секции, шапке и подвалу — то есть ровно тому, что стоит В СЛОТЕ страницы. Полоса — это то, что
   занимает слот; определение и селектор совпадают.

   Специфичность (0,1,0): `:where()` не добавляет ничего, считается только `[data-slot]`. Значит,
   блоку достаточно СВОЕГО селектора той же силы позже по файлу, чтобы назначить полосе другой
   воздух (`today`, `promo-banner strip`, `menu-catalog`), а полосе во всю ширину — снять его совсем
   (`hero cover`, `site-header`): dist/site-blocks.css склеивает base.css первым, и правила блока
   идут после. `.sb-section` оставлен синонимом — под этим именем общая обёртка описана в
   spec/mockup-conventions.md §4 и живёт в макетах первой волны. */
:where(.sb-page) [data-slot],.sb-section{padding-block:var(--site-section-y);padding-inline:var(--site-gutter)}
.site-block__inner,.sb-section__inner{max-width:var(--site-w-page);margin-inline:auto;width:100%}

/* КОЛОНКА СТРАНИЦЫ ВНУТРИ ПОЛОСЫ ВО ВСЮ ШИРИНУ.

   Полоса, снявшая поля (`hero cover`, `site-header`), возвращает их своим `__inner` — иначе текст
   лёг бы на кромку экрана. Но тогда поле оказывается ВНУТРИ `--site-w-page`, и колонка такой полосы
   становится уже колонки соседей ровно на два поля: заголовок обложки и слова шапки стояли не на
   той вертикали, что заголовки секций под ними. Ширина с возвращённым полем считается один раз
   здесь, и обе полосы её просто читают.

   `--sb-*`, а не `--site-*`: это производная величина набора, а не токен, который назначает пак
   (тот же приём, что `--sb-hero-overlay`). Пак задаёт `--site-w-page` и поля; ширина «полосы во всю
   ширину» из них следует. */
:where(.sb-page) [data-slot]{--sb-w-page-bleed:calc(var(--site-w-page) + var(--site-gutter) * 2)}

.sb-kicker{
  font-family:var(--site-body);font-size:var(--site-micro);font-weight:600;
  letter-spacing:var(--site-micro-ls);text-transform:uppercase;
  color:var(--site-accent);line-height:1.3;
}
.sb-head{
  display:flex;align-items:flex-end;justify-content:space-between;gap:var(--site-space-4);
  margin-bottom:var(--site-space-5);
}
.sb-head__t{display:grid;gap:var(--site-space-2)}
.sb-head__link{
  display:inline-flex;align-items:center;gap:var(--site-space-2);
  color:var(--site-accent);font-size:var(--site-small);font-weight:600;
  min-height:var(--site-btn-h);flex:none;
}
.sb-head__link svg{width:1.15em;height:1.15em}
.sb-lead{color:var(--site-muted);max-width:var(--site-w-read)}

.sb-btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--site-space-2);
  height:var(--site-btn-h);min-height:var(--site-btn-h);
  padding-inline:var(--site-btn-px);border-radius:var(--site-r-btn);
  font-family:var(--site-body);font-size:var(--site-btn-size);font-weight:600;
  letter-spacing:var(--site-btn-ls);text-transform:var(--site-btn-case);
  border:0;white-space:nowrap;
}
.sb-btn svg{width:1.2em;height:1.2em;flex:none}
/* The primary button reads a pair of its own, not the accent: the accent may be a brand colour of
   3:1 under white, and a label is text (узел button-accent-contrast, style/button-colours.ts). */
.sb-btn--primary{background:var(--site-btn-accent);color:var(--site-btn-on-accent)}
.sb-btn--secondary{background:transparent;color:var(--site-ink);border:1px solid var(--site-line)}
.sb-btn--ghost{background:transparent;color:var(--site-accent);padding-inline:var(--site-space-2)}
.sb-btn--wide{width:100%}
.sb-btn--lg{height:calc(var(--site-btn-h) + var(--site-space-2));font-size:var(--site-h4)}

.sb-chip{
  display:inline-flex;align-items:center;gap:var(--site-space-2);
  min-height:var(--site-btn-h-sm);padding-inline:var(--site-space-4);
  border-radius:var(--site-r-chip);border:1px solid var(--site-line);
  background:var(--site-surface);color:var(--site-ink);
  font-size:var(--site-small);font-weight:500;white-space:nowrap;
}
.sb-chip[data-state="on"]{background:var(--site-accent);color:var(--site-on-accent);border-color:transparent}
.sb-chip--tap{min-height:var(--site-btn-h)}
.sb-chip svg{width:1.05em;height:1.05em}

.sb-badge{
  display:inline-flex;align-items:center;gap:var(--site-space-1);
  padding:var(--site-space-1) var(--site-space-2);border-radius:var(--site-r-chip);
  font-size:var(--site-micro);font-weight:700;letter-spacing:var(--site-micro-ls);
  text-transform:uppercase;background:var(--site-accent-soft);color:var(--site-accent);
  justify-self:start;align-self:start;width:fit-content;
}
.sb-badge[data-tone="warn"]{background:var(--site-surface-2);color:var(--site-warn)}
.sb-badge[data-tone="danger"]{background:var(--site-surface-2);color:var(--site-danger)}
.sb-badge[data-tone="ok"]{background:var(--site-accent-soft);color:var(--site-ok)}

.sb-price{
  font-family:var(--site-mono);font-variant-numeric:tabular-nums;
  font-size:var(--site-body-size);font-weight:600;color:var(--site-ink);white-space:nowrap;
}
.sb-price[data-state="off"]{color:var(--site-faint);text-decoration:line-through}

.sb-media{
  position:relative;overflow:hidden;isolation:isolate;
  border-radius:var(--site-r-media);background:var(--site-surface-2);
}
.sb-media--card{aspect-ratio:var(--site-ratio-card)}
.sb-media--tile{aspect-ratio:var(--site-ratio-tile)}
.sb-media--hero{aspect-ratio:var(--site-ratio-hero)}
.sb-media--plain{border-radius:0}
/* A picture shown whole (`BlockImage.fit`, node site-scroll-effects): an illustration in a photo slot
   keeps its edges, and the rest of the frame is the band's own ground rather than a grey plate. */
.sb-media[data-fit="contain"]{background:transparent}
:where(.sb-page) .sb-media[data-fit="contain"] img{object-fit:contain}
.sb-media__scrim::after{content:"";position:absolute;inset:0;background:var(--site-scrim)}
.sb-fill{
  position:relative;display:grid;place-items:center;width:100%;height:100%;overflow:hidden;
  background:linear-gradient(150deg,color-mix(in srgb,var(--site-accent) 58%,var(--site-ink)) 6%,var(--site-accent) 96%);
  color:var(--site-on-accent);
}
.sb-fill::before{content:"";position:absolute;inset:0;
  background:repeating-linear-gradient(128deg,color-mix(in srgb,var(--site-on-accent) 7%,transparent) 0 .1em,transparent .1em .9em)}
.sb-fill::after{content:"";position:absolute;inset:0;
  background:radial-gradient(90% 70% at 22% 12%,color-mix(in srgb,var(--site-on-accent) 20%,transparent),transparent 62%)}
.sb-fill span{position:relative;z-index:1;padding-inline:var(--site-space-4);text-align:center;font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);font-size:var(--site-h3);letter-spacing:var(--site-display-ls);opacity:.94}

.sb-status{display:inline-flex;align-items:center;gap:var(--site-space-2);font-size:var(--site-small);color:var(--site-muted)}
.sb-status::before{content:"";width:.5em;height:.5em;border-radius:var(--site-r-chip);background:var(--site-ok);flex:none}
.sb-status[data-state="closed"]::before{background:var(--site-danger)}
.sb-dot{color:var(--site-faint)}

/* The body of a `richtext` field (parts.tsx `RichText`, src/rich-text.ts).

   Until this node a richtext field printed paragraphs and nothing else; the author can now set a
   subheading, a list and a link inside one, and the page root deliberately strips list markers and
   link colour from EVERY element (`:where(.sb-page) :is(ul,ol)` above), so the subset has to get
   them back exactly where it is printed and nowhere else. Hence a class on the container rather
   than a rule on the page: a `.sb-btn` standing beside a richtext body is a link too, and it must
   not turn into an underlined accent word.

   Modest on purpose — a heading inside a text block is a SUBheading, so h2/h3 here are one step
   below the section's own h2/h3. Every value is a pack token: a literal would be a size one of the
   four packs could not restyle. */
.sb-rt{display:grid;gap:var(--site-space-3);min-width:0}
.sb-rt h2{font-size:var(--site-h3)}
.sb-rt h3{font-size:var(--site-h4)}
.sb-rt :is(ul,ol){padding-left:var(--site-space-5);display:grid;gap:var(--site-space-1)}
.sb-rt ul{list-style:disc}
.sb-rt ol{list-style:decimal}
.sb-rt li :is(ul,ol){margin-top:var(--site-space-1)}
.sb-rt a{color:var(--site-accent);text-decoration:underline;text-underline-offset:.15em}
.sb-rt strong{font-weight:700;color:var(--site-ink)}
.sb-rt em{font-style:italic}

/* Only ever rendered in the editor (parts.tsx `Empty`): a live page shows nothing rather than an
   apology a guest cannot act on. */
.sb-empty{
  padding:var(--site-space-5);border:1px dashed var(--site-line);border-radius:var(--site-r-card);
  color:var(--site-faint);font-size:var(--site-small);text-align:center;
}

/* THE BAND'S BRAND PATTERN (node site-brand-typography-patterns) — `SiteSection.background`.
   `renderSection` writes `data-bg="cover|repeat"` and the picture as `--sb-bg-image`; the picture is
   a layer OVER the band's ground and UNDER its content: `isolation` makes the band its own stacking
   context, so `z-index:-1` stays above the band's background and below everything in it. The colour
   of the veins is the picture's own — pink on white, white on black are two files, not a filter. */
[data-bg]{position:relative;isolation:isolate}
[data-bg]::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:var(--sb-bg-image);opacity:var(--sb-bg-opacity,1);
}
[data-bg="cover"]::before{background-size:cover;background-position:center;background-repeat:no-repeat}
[data-bg="repeat"]::before{background-repeat:repeat;background-position:left top}

/* THE BAND'S DECORATIVE WORD (`SiteSection.display_word`): «меню», «бар», «бронь» — huge, lowercase,
   in the accent face of the brand (`--site-accent-font`, else the display face). Fluid size with a
   ceiling; a long word wraps rather than pushing the page sideways on a phone. */
.sb-display-word{
  display:block;margin-bottom:var(--site-space-6);
  font-family:var(--site-accent-font,var(--site-display));font-weight:var(--site-accent-font-weight,var(--site-display-weight));
  font-size:clamp(3.5rem,17vw,13.75rem);line-height:.8;letter-spacing:-.035em;text-transform:lowercase;
  overflow-wrap:anywhere;
}

/* A BAND'S MOTION, ILLUSTRATIONS AND RUNNING LINE (node site-scroll-effects, render/motion.tsx).
   Every rule keys on an attribute only a band that asked for the effect carries. Two numbers move:
   `--sb-p`, where a band (or one line of its text) stands in the window — +1 entering at the bottom,
   0 in the middle, −1 leaving at the top — written by the inline motion script on scroll; and
   `data-in`, set once when a band first comes into view. Without the script neither exists, and every
   fallback below is «the band at rest in the middle of the screen»: content visible, nothing shifted.

   REVEAL. The hidden starting state is gated by `.sb-motion` on <html>, which only the script adds —
   and only when the guest has not asked for reduced motion. It moves with `translate`/`scale`, the
   individual transform properties, so a block's own `transform` is never overwritten; and opacity
   plus transform never change layout, so nothing below the band jumps. */
[data-motion="fade-up"]{--sb-from-t:0 2.5rem}
[data-motion="slide-left"]{--sb-from-t:-3rem 0}
[data-motion="slide-right"]{--sb-from-t:3rem 0}
[data-motion="zoom"]{--sb-from-s:.92}
[data-motion^="slide"],[data-media-zoom],[data-media-drift]{overflow-x:clip}
.sb-motion [data-motion]:not([data-motion-stagger]) > :not(.sb-decor,.sb-bg-prx),
.sb-motion [data-motion-stagger] > .sb-display-word,
.sb-motion [data-motion-stagger] > :not(.sb-decor,.sb-bg-prx,.sb-display-word) > :not(ul,ol),
.sb-motion [data-motion-stagger] > :not(.sb-decor,.sb-bg-prx,.sb-display-word) > :is(ul,ol) > li{
  opacity:0;translate:var(--sb-from-t,none);scale:var(--sb-from-s,none);
  transition:opacity .8s ease-out,translate 1s cubic-bezier(.2,.7,.2,1),scale 1s cubic-bezier(.2,.7,.2,1);
  transition-delay:calc(min(var(--sb-i,0),8) * 90ms);
}
.sb-motion [data-motion][data-in]:not([data-motion-stagger]) > :not(.sb-decor,.sb-bg-prx),
.sb-motion [data-motion-stagger][data-in] > .sb-display-word,
.sb-motion [data-motion-stagger][data-in] > :not(.sb-decor,.sb-bg-prx,.sb-display-word) > :not(ul,ol),
.sb-motion [data-motion-stagger][data-in] > :not(.sb-decor,.sb-bg-prx,.sb-display-word) > :is(ul,ol) > li{
  opacity:var(--sb-ink,1);translate:none;scale:none;
}

/* INK — headings and paragraphs come up from a pale 20 % to full strength as they reach the middle of
   the screen (Jonny's slogans). Per line: the script writes `--sb-p` on each text element of the band. */
[data-motion-ink] :is(h1,h2,h3,h4,p,.sb-display-word){
  --sb-ink:calc(.2 + .8 * clamp(0, (1 - var(--sb-p,-1)) * 1.4, 1));opacity:var(--sb-ink);
}

/* THE BAND'S PHOTOS ON SCROLL — drift against the page (Liberty's columns, every second one the other
   way when the script marks it `--sb-alt:-1`) and/or arrive larger or smaller and settle to their
   size by the middle of the screen. `transform` here: no block transforms its `.sb-media`. */
[data-media-drift] .sb-media,[data-media-zoom] .sb-media{
  transform:translate3d(0,calc(var(--sb-p,0) * var(--sb-m-prx,0) * var(--sb-alt,1) * -50vh),0)
    scale(calc(1 + (var(--sb-m-zoom,1) - 1) * clamp(0, var(--sb-p,0), 1)));
}

/* STICKY HEADING — the band's heading row stays under the site header while the rest of the band
   scrolls over it; what follows it is lifted above it so cards slide across, not under. */
[data-motion-sticky] .sb-head{position:sticky;top:calc(var(--site-btn-h) + var(--site-space-6));z-index:0}
[data-motion-sticky] .sb-head ~ *{position:relative;z-index:1}

/* THE PATTERN THAT DRIFTS (`motion.parallax`): a real layer that clips itself, so the band stays
   unclipped for an illustration to hang over its edge; it is taller than the band by exactly the
   farthest it can travel, so its edges never show. */
[data-bg-parallax]::before{content:none}
.sb-bg-prx{position:absolute;inset:0;z-index:-1;overflow:hidden;pointer-events:none}
.sb-bg-prx::before{
  content:"";position:absolute;inset:calc(var(--sb-bg-prx,0) * -50vh) 0;
  background-image:var(--sb-bg-image);opacity:var(--sb-bg-opacity,1);
  transform:translate3d(0,calc(var(--sb-p,0) * var(--sb-bg-prx,0) * -50vh),0);
}
[data-bg="cover"] > .sb-bg-prx::before{background-size:cover;background-position:center;background-repeat:no-repeat}
[data-bg="repeat"] > .sb-bg-prx::before{background-repeat:repeat;background-position:left top}

/* ILLUSTRATIONS (`SiteSection.decor`). Pinned to the band by left/top (%), aligned on their own size
   by translate (%), sized in % of the band's width. `back` lies under the content (the band is its
   own stacking context, so −1 stays above its ground), `front` over it — neither ever takes a tap.
   Clipped sideways at the band's edge so the page never scrolls horizontally, free vertically so a
   mascot can sit on the band's top edge; such a band paints over its neighbours (`data-decor-over`). */
[data-decor]{position:relative;isolation:isolate;overflow-x:clip}
[data-decor-over]{z-index:1}
.sb-decor{position:absolute;inset:0;z-index:-1;pointer-events:none}
.sb-decor[data-layer="front"]{z-index:2}
:where(.sb-page) .sb-decor__img{
  position:absolute;left:var(--d-l);top:var(--d-t);width:var(--d-wm);height:auto;max-width:none;object-fit:contain;
  transform:translate(var(--d-tx),var(--d-ty)) translate3d(0,calc(var(--sb-p,0) * var(--d-prx,0) * -50vh),0)
    rotate(calc(var(--d-r,0deg) + var(--sb-p,0) * var(--d-spin,0deg) / 2));
}
.sb-decor__img[data-hide-mobile]{display:none}

/* THE RUNNING LINE — a strip beside its band, edge to edge, in a scheme of the site (accent by default);
   pure css, two identical halves moved by exactly one half so the seam never shows. Slanted strips
   overhang their neighbours, so the strip stands above them and clips sideways. */
.sb-marquee{position:relative;z-index:2;overflow-x:clip}
.sb-marquee__strip{
  background:var(--site-bg);color:var(--site-ink);padding-block:var(--site-space-3);
  rotate:var(--mq-tilt,0deg);width:110%;margin-inline:-5%;
}
.sb-marquee__track{display:flex;width:max-content;margin:0;animation:sb-marquee var(--mq-dur,30s) linear infinite}
.sb-marquee[data-dir="right"] .sb-marquee__track{animation-direction:reverse}
.sb-marquee__half{display:flex;flex:none}
.sb-marquee__item{
  flex:none;padding-inline:var(--site-space-3);white-space:nowrap;
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  font-size:var(--site-h3);line-height:1.1;text-transform:var(--site-display-case);letter-spacing:var(--site-display-ls);
}
@keyframes sb-marquee{from{transform:translate3d(0,0,0)}to{transform:translate3d(-50%,0,0)}}
@media (prefers-reduced-motion:reduce){
  .sb-marquee__track{animation:none}
}

@media (min-width:900px){
  :where(.sb-page) [data-slot],.sb-section{padding-block:var(--site-section-y-d);padding-inline:var(--site-gutter-d)}
  :where(.sb-page) [data-slot]{--sb-w-page-bleed:calc(var(--site-w-page) + var(--site-gutter-d) * 2)}
  :where(.sb-page) .sb-decor__img{width:var(--d-w)}
  .sb-decor__img[data-hide-mobile]{display:block}
}

/* THE BOTTOM SHEET (parts.tsx `Sheet`, node dia-home-look) — keyed by `data-sheet-part`, NOT by the
   `sb-sheet__*` classes: the classes are for readers and tests, and a base sheet that named them
   would become a dependency of every e2e spec that locates a sheet (e2e-style-scope G-5; the tab
   bar's `[data-tabbar]` is the same device). — the «Día» sheet of the table and of the
   card: dimming at 40 %, the canvas-coloured panel with radius-28 top corners sliding up from the
   bottom, a handle, a centred title and a round close button, a body that scrolls on its own.
   Open = the section is the page's target (`:target`, no script) or its island says so
   (`data-open="on"`); once the island is awake (`data-sheet="js"`) a stale `:target` no longer
   counts, because closing drops the hash with `history.replaceState`, which `:target` does not see. */
[data-sheet-part="root"]{position:fixed;inset:0;z-index:60;visibility:hidden;pointer-events:none}
:target:not([data-sheet="js"]) [data-sheet-part="root"],[data-open="on"] [data-sheet-part="root"]{visibility:visible;pointer-events:auto}
[data-sheet-part="scrim"]{position:absolute;inset:0;background:var(--site-overlay);opacity:0;transition:opacity .28s ease}
[data-sheet-part="panel"]{
  position:absolute;left:0;right:0;bottom:0;display:flex;flex-direction:column;
  max-height:calc(100% - var(--site-space-5));background:var(--site-bg);color:var(--site-ink);
  border-radius:var(--site-r-card) var(--site-r-card) 0 0;
  transform:translateY(100%);transition:transform .36s cubic-bezier(.32,.72,0,1);
}
:target:not([data-sheet="js"]) [data-sheet-part="scrim"],[data-open="on"] [data-sheet-part="scrim"]{opacity:1}
:target:not([data-sheet="js"]) [data-sheet-part="panel"],[data-open="on"] [data-sheet-part="panel"]{transform:none}
[data-sheet-part="handle"]{
  position:relative;flex:none;align-self:center;
  width:calc(var(--site-space-6) + var(--site-space-1));height:var(--site-space-1);
  margin-top:var(--site-space-2);border-radius:var(--site-r-chip);background:var(--site-line);
}
/* The bar is a picture; the finger gets a full touch target around it. */
[data-sheet-part="handle"]::after{content:"";position:absolute;inset:calc(var(--site-space-5) * -1) calc(var(--site-space-6) * -1)}
[data-sheet-part="head"]{
  position:relative;flex:none;display:grid;place-items:center;
  min-height:calc(var(--site-space-8) - var(--site-space-3));padding:var(--site-space-3) var(--site-space-8);
}
/* The title names the sheet («Mesa 7»), it is not a section heading: no lowercasing. */
[data-sheet-part="title"]{font-size:var(--site-h3);text-transform:none;letter-spacing:-.015em;text-align:center}
[data-sheet-part="close"]{
  position:absolute;top:var(--site-space-2);right:var(--site-gutter);display:grid;place-items:center;
  width:calc(var(--site-space-6) + var(--site-space-2));height:calc(var(--site-space-6) + var(--site-space-2));
  border-radius:var(--site-r-chip);background:var(--site-surface-2);color:var(--site-ink);
}
[data-sheet-part="close"]::after{content:"";position:absolute;inset:calc(var(--site-space-1) * -.5)}
[data-sheet-part="body"]{
  flex:1;overflow-y:auto;overscroll-behavior:contain;
  padding:0 var(--site-gutter) calc(env(safe-area-inset-bottom,0) + var(--site-space-5));
}
/* The sticky footer: pinned under the scrolling body (the panel is a column, the body alone scrolls),
   on the panel's own ground, casting the pack's footer shadow up over what scrolls beneath it. */
[data-sheet-part="foot"]{
  position:sticky;bottom:0;flex:none;display:grid;gap:var(--site-space-2);
  padding:var(--site-space-3) var(--site-gutter) calc(env(safe-area-inset-bottom,0) + var(--site-space-3));
  background:var(--site-bg);box-shadow:var(--site-shadow-foot);
}
[data-sheet-part="body"]:has(+ [data-sheet-part="foot"]){padding-bottom:var(--site-space-3)}
@media (min-width:900px){
  /* `data-desktop="band"`: on a wide screen the host is the band it always was — no dimming, no
     handle, no close button, the title as the band's heading, everything in the page's flow. */
  [data-sheet-part="root"][data-desktop="band"]{position:static;visibility:visible;pointer-events:auto}
  [data-sheet-part="root"][data-desktop="band"] :is([data-sheet-part="scrim"],[data-sheet-part="handle"],[data-sheet-part="close"]){display:none}
  [data-sheet-part="root"][data-desktop="band"] [data-sheet-part="panel"]{position:static;transform:none;max-height:none;background:none;border-radius:0}
  [data-sheet-part="root"][data-desktop="band"] [data-sheet-part="head"]{place-items:start;min-height:0;padding:0 0 var(--site-space-4)}
  [data-sheet-part="root"][data-desktop="band"] [data-sheet-part="body"]{overflow:visible;padding:0}
  [data-sheet-part="root"][data-desktop="band"] [data-sheet-part="foot"]{position:static;padding:var(--site-space-3) 0 0;background:none;box-shadow:none}
  /* A sheet that is a sheet on a desktop too stands as a centred card, not a full-width drawer. */
  [data-sheet-part="root"][data-desktop="sheet"] [data-sheet-part="panel"]{left:50%;right:auto;width:min(100%,var(--site-w-read));transform:translate(-50%,100%)}
  :target:not([data-sheet="js"]) [data-sheet-part="root"][data-desktop="sheet"] [data-sheet-part="panel"],[data-open="on"] [data-sheet-part="root"][data-desktop="sheet"] [data-sheet-part="panel"]{transform:translate(-50%,0)}
}

/* --- booking --- */
.sb-booking__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-5)}
.sb-booking__body{display:grid;gap:var(--site-space-4);align-content:start;max-width:var(--site-w-read)}
.sb-booking__strip{
  display:flex;align-items:center;gap:var(--site-space-4);
  border:1px solid var(--site-accent);padding:var(--site-space-4);background:transparent;
}
.sb-booking__st{
  width:var(--site-space-6);height:var(--site-space-6);flex:none;border-radius:var(--site-r-chip);
  background:var(--site-accent);color:var(--site-on-accent);display:grid;place-items:center;
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);font-size:var(--site-small);
}
.sb-booking__strip div{flex:1;min-width:0}
.sb-booking__strip b{
  display:block;font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  font-size:var(--site-h4);letter-spacing:var(--site-display-ls);text-transform:var(--site-display-case);
}
.sb-booking__strip span{font-size:var(--site-small);color:var(--site-muted)}
.sb-booking__facts{display:flex;flex-wrap:wrap;gap:var(--site-space-5)}
.sb-booking__fact b{
  display:block;font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  font-size:var(--site-h3);line-height:var(--site-display-lh);letter-spacing:var(--site-display-ls);
}
.sb-booking__fact span{font-size:var(--site-small);color:var(--site-muted)}
.sb-booking__hint{font-size:var(--site-small);color:var(--site-muted)}
.sb-booking__policy{font-size:var(--site-small);color:var(--site-muted);white-space:pre-line}
.sb-booking__media{aspect-ratio:var(--site-ratio-card)}

@media (min-width:900px){
  .sb-booking__inner:has(> .sb-booking__media){grid-template-columns:minmax(0,3fr) minmax(0,2fr);gap:var(--site-space-8);align-items:center}
  .sb-booking__inner:has(> .sb-booking__media) > .sb-booking__media{order:2}
  .sb-booking__inner:has(> .sb-booking__media) > .sb-booking__body{order:1}
  .sb-booking[data-variant="cta-only"] .sb-booking__body{max-width:none}
  .sb-booking[data-variant="cta-only"] .sb-booking__body .sb-btn{justify-self:start;width:auto}
}

/* ── Island states (site-islands-hydrate): the live grid of days, party sizes and hours the runtime
   puts above the block's own invitation. Nothing here applies until the island renders it. ── */
.sb-booking__live{
  max-width:var(--site-w-page);margin-inline:auto;
  display:flex;flex-direction:column;gap:var(--site-space-3);
  margin-bottom:var(--site-space-5);
}
.sb-booking__days,.sb-booking__party,.sb-booking__slots{
  display:flex;flex-wrap:wrap;gap:var(--site-space-2);
}
.sb-booking__days{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
.sb-booking__days .sb-chip{flex-direction:column;gap:0;line-height:1.1;min-width:calc(var(--site-btn-h) + var(--site-space-2))}
.sb-booking__days .sb-chip b{font-family:var(--site-mono);font-size:var(--site-body-size)}
.sb-booking__days .sb-chip span{font-size:var(--site-micro);color:var(--site-faint);text-transform:lowercase}
.sb-booking__slots .sb-chip{font-family:var(--site-mono)}
.sb-booking__note{font-size:var(--site-small);color:var(--site-muted)}

/* --- buttons --- */
/* The title and the row are spaced the way every other block spaces its head and its body
   (`__inner` grid + `--site-space-5`): without it the button sat flush under the title
   (ox.smenapos.ru «more» and «book», 2026-10-14). */
.sb-buttons__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-5)}
.sb-buttons__row{display:flex;flex-direction:column;gap:var(--site-space-2)}
.sb-buttons__row[data-align="center"]{align-items:center}
.sb-buttons__row[data-align="left"]{align-items:flex-start}
.sb-buttons__tile{
  display:flex;flex-direction:column;gap:var(--site-space-2);align-items:flex-start;min-width:0;
  min-height:calc(var(--site-space-8) + var(--site-space-5));padding:var(--site-space-4);
  border:1px solid var(--site-line);border-radius:var(--site-r-card);
  background:var(--site-surface);color:var(--site-ink);
}
.sb-buttons__tile i{display:block;color:var(--site-accent);font-style:normal}
.sb-buttons__tile i svg{width:var(--site-h3);height:var(--site-h3)}
.sb-buttons__tile b{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  font-size:var(--site-h4);letter-spacing:var(--site-display-ls);text-transform:var(--site-display-case);
}
.sb-buttons__tile span{font-size:var(--site-small);color:var(--site-muted)}
.sb-buttons[data-variant="icon-tiles"] .sb-buttons__row{display:grid;grid-template-columns:1fr 1fr;gap:var(--site-gap)}
/* `row`/`stack`: a button with a `note` stands with its line under it in one cell, so the line
   follows the button in a row, in a column and under any alignment. A button without a note is
   printed bare, as before. */
.sb-buttons__cell{display:flex;flex-direction:column;gap:var(--site-space-2);min-width:0}
.sb-buttons__row[data-align="stretch"] > .sb-buttons__cell{align-self:stretch}
.sb-buttons__row[data-align="center"] > .sb-buttons__cell{align-items:center;text-align:center}
.sb-buttons__note{font-size:var(--site-small);color:var(--site-muted)}

@media (min-width:900px){
  .sb-buttons[data-variant="row"] .sb-buttons__row{flex-direction:row;flex-wrap:wrap}
  .sb-buttons[data-variant="row"] .sb-buttons__row[data-align="stretch"]{justify-content:stretch}
  .sb-buttons[data-variant="row"] .sb-buttons__row[data-align="stretch"] > :is(.sb-btn,.sb-buttons__cell){flex:1;width:auto}
  .sb-buttons[data-variant="row"] .sb-buttons__row[data-align="center"]{justify-content:center}
  .sb-buttons[data-variant="icon-tiles"] .sb-buttons__row{grid-template-columns:repeat(4,1fr)}
}

/* ── ВАРИАНТ `hub-tiles` — КАРТОЧКИ-НАМЕРЕНИЯ (узел site-home-hub) ───────────────────────────────
   Стили перенесены из макета выбранного варианта (site-parrilla-02-home-hub-b-md.html, секция
   `buttons` с `data-variant="hub-tiles"`) значение в значение; контейнер называется `__row`, как
   в коде, а не `__list`, как в макете.

   Свой воздух полосе: карточки стоят сразу под полосой-визиткой на первом экране телефона, и
   воздух обычной полосы вытолкнул бы третью карточку за сгиб. Общий ритм не переписывается. */
/* The «Día» tile (node dia-home-look, comanda-dia/screens/dia-home.html `.tile`): a white card of
   radius 28 on the canvas, no border, the icon at the top in the muted tone, the title pushed to the
   bottom, and a sub-line that reserves two lines so the titles of one row stand on one line whether
   the sub wraps or not. The mockup's tile height is two steps of 64 plus 12 on the pack's scale. */
.sb-buttons[data-variant="hub-tiles"]{padding-block:var(--site-space-3)}
.sb-buttons[data-variant="hub-tiles"] .sb-buttons__row{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--site-space-3);
}
.sb-buttons__hub{
  display:flex;flex-direction:column;align-items:flex-start;min-width:0;
  min-height:calc(var(--site-space-8) * 2 + var(--site-space-3));padding:var(--site-space-4);
  border-radius:var(--site-r-card);background:var(--site-surface);color:var(--site-ink);text-align:left;
  box-shadow:var(--site-shadow-card);
}
.sb-buttons__hub svg{width:var(--site-space-5);height:var(--site-space-5);color:var(--site-muted)}
.sb-buttons__hub b{
  margin-top:auto;padding-top:var(--site-space-3);
  font-size:var(--site-h4);font-weight:600;letter-spacing:-.015em;line-height:1.2;
}
.sb-buttons__hub span{margin-top:var(--site-space-1);min-height:2.6em;font-size:var(--site-micro);line-height:1.3;color:var(--site-muted)}
/* THE PRIMARY INTENT IS THE PACK'S BUTTON PAIR, not the ink and not the accent: that pair is the one
   the pack (and the site's palette, through button-colours.ts) guarantees at ≥ 4.5:1, so a
   restaurateur who repaints «Акцент» repaints this tile too and it stays legible. On Día it is ink
   under white (16:1); icon and sub-line are the label at 72 %, as in the mockup. */
.sb-buttons__hub[data-role="primary"]{background:var(--site-btn-accent);color:var(--site-btn-on-accent)}
.sb-buttons__hub[data-role="primary"] :is(svg,span){color:color-mix(in srgb,var(--site-btn-on-accent) 72%,var(--site-btn-accent))}
/* `ghost` — the grey tile: «Obtener la tarjeta» of a guest who has no card yet. */
.sb-buttons__hub[data-role="ghost"]{background:var(--site-surface-2)}
/* `tier` — «Mi tarjeta» of a known guest wears his tier (node dia-card-tiers, brand-spec v11): the same
   face as his card in the sheet. The guest-hello island sets the role and both colours on the tile
   (`--sb-tier`, `--sb-tier-ink` — the white every tier colour carries at ≥ 4.5:1); the shade only
   moves toward ink, and the sub-line is solid, so nothing on the tile reads under AA. */
.sb-buttons__hub[data-role="tier"]{
  background-color:var(--sb-tier);
  background-image:linear-gradient(135deg,var(--sb-tier) 0%,var(--sb-tier) 52%,color-mix(in oklch,var(--sb-tier),var(--site-ink) 12%) 100%);
  color:var(--sb-tier-ink);
}
.sb-buttons__hub[data-role="tier"] :is(svg,span){color:var(--sb-tier-ink)}
/* The waiter is on the way: the call tile turns grey and says so (the table band's island writes
   the state and the words into it — the tile is plain HTML, so it can). */
.sb-buttons__hub[data-call]:not([data-call="idle"]){background:var(--site-surface-2);color:var(--site-ink)}
.sb-buttons__hub[data-call]:not([data-call="idle"]) :is(svg,span){color:var(--site-ink)}
/* This phone sent its review (node dia-table-review, Д-10): the review tile turns grey and says so —
   «Reseña enviada · 10% hasta el 11 oct» — and a tap shows the code again. Same island, same device. */
.sb-buttons__hub[data-review="sent"]{background:var(--site-surface-2);color:var(--site-ink)}
.sb-buttons__hub[data-review="sent"] :is(svg,span){color:var(--site-ink)}

/* A TILE THAT WORKS ONLY IN SOME CONDITIONS IS PRINTED `hidden` and shown by the island that knows
   the condition (decisions.md Д-17 of site-home-hub: no dead control): «call the waiter» needs a
   confirmed table and a floor, «leave a review» needs the table's review address, and «book a table»
   stands in the call's place where there is nobody to call. The attribute, not a class rule: it
   takes the tile out of the picture and out of the accessibility tree, and the island toggles it. */
.sb-buttons__hub[hidden]{display:none}

/* NO HOLES IN THE GRID (contract R-3 of site-home-hub). Two columns on a phone; the last VISIBLE tile
   left alone in its row takes the whole row. Counted among the tiles a guest actually sees — which
   is exactly what `hidden` marks, whatever the island decided. */
.sb-buttons__hub:nth-last-child(1 of :not([hidden])):nth-child(odd of :not([hidden])){grid-column:1/-1}

@media (min-width:900px){
  .sb-buttons[data-variant="hub-tiles"]{padding-block:var(--site-space-5)}
  /* On a desktop every visible card stands in ONE row, however many there are: the columns follow
     the cards, so no cell is left empty. */
  .sb-buttons[data-variant="hub-tiles"] .sb-buttons__row{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:1fr}
  .sb-buttons__hub:nth-last-child(1 of :not([hidden])):nth-child(odd of :not([hidden])){grid-column:auto}
}

/* --- certificates --- */
.sb-certificates__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-5)}
.sb-certificates__head{display:grid;gap:var(--site-space-3);justify-items:start}
.sb-certificates__cover{aspect-ratio:var(--site-ratio-card)}
.sb-certificates__grid{display:grid;gap:var(--site-gap)}
.sb-certificates__card{
  display:flex;flex-direction:column;gap:var(--site-space-2);align-items:flex-start;min-width:0;
  padding:var(--site-space-5);border:1px solid var(--site-line);border-radius:var(--site-r-card);
  background:var(--site-surface);color:var(--site-ink);
}
.sb-certificates__card b{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  font-size:var(--site-h3);line-height:var(--site-display-lh);letter-spacing:var(--site-display-ls);
  text-transform:var(--site-display-case);
}
.sb-certificates__note{font-size:var(--site-small);color:var(--site-muted)}
.sb-certificates__text{font-size:var(--site-small);color:var(--site-muted)}

/* `strip` — the denominations as one scrolling row (a house that sells six of them on a phone);
   `feature` stands the single certificate beside its photograph. */
/* РЕЛЬС ВЫХОДИТ ЗА ПОЛЯ ПОЛОСЫ и возвращает их себе — чтобы прокрутка начиналась от самого края
   экрана. Значит, он обязан называть ТО ЖЕ поле, что несёт полоса, на обеих ширинах: до этого узла
   десктопной половины тут не было, и на паке editorial это не бросалось в глаза только потому, что
   у него совпадали оба поля (16/16). Как только десктопное поле стало другим, рельс начал
   останавливаться на полпути. Так же это написано у `menu-catalog__tabs` и `menu-highlights__rail`. */
.sb-certificates[data-variant="strip"] .sb-certificates__grid{
  display:flex;overflow-x:auto;scroll-snap-type:x mandatory;
  margin-inline:calc(var(--site-gutter) * -1);padding-inline:var(--site-gutter);
}
.sb-certificates[data-variant="strip"] .sb-certificates__card{flex:0 0 70%;scroll-snap-align:start}

@media (min-width:900px){
  .sb-certificates__grid{grid-template-columns:repeat(3,1fr)}
  .sb-certificates[data-variant="strip"] .sb-certificates__grid{
    margin-inline:calc(var(--site-gutter-d) * -1);padding-inline:var(--site-gutter-d);
  }
  .sb-certificates[data-variant="strip"] .sb-certificates__card{flex:0 0 calc(100% / 4)}
  .sb-certificates[data-variant="feature"] .sb-certificates__inner{
    grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:center;column-gap:var(--site-space-8);
  }
  .sb-certificates[data-variant="feature"] .sb-certificates__head{grid-column:1;max-width:var(--site-w-read)}
  .sb-certificates[data-variant="feature"] .sb-certificates__grid{grid-column:1;grid-template-columns:1fr}
  .sb-certificates[data-variant="feature"] .sb-certificates__cover{grid-column:2;grid-row:1 / span 2}
}

/* --- delivery --- */
/* «Доставка»: the zone on one side, the facts that decide an order on the other, then the button —
   the storefront's DeliverySection transcribed onto the site tokens. The catalogue serving puts the
   menu (`__order`, the menu-catalog classes) under the band as a sibling. */
.sb-delivery__inner{max-width:var(--site-w-page);width:100%;margin-inline:auto;display:grid;gap:var(--site-space-4)}
.sb-delivery__lede{max-width:var(--site-w-read);font-size:var(--site-body-size);color:var(--site-muted)}
.sb-delivery__in{display:grid;gap:var(--site-space-6);align-items:start;margin-top:var(--site-space-3)}
.sb-delivery__map{position:relative;margin:0}
.sb-delivery__frame{aspect-ratio:4/3}
.sb-delivery__zone{
  position:absolute;left:var(--site-space-3);bottom:var(--site-space-3);
  padding:var(--site-space-2) var(--site-space-4);border-radius:var(--site-r-chip);
  background:var(--site-surface);color:var(--site-ink);font-size:var(--site-small);font-weight:600;
}
.sb-delivery__zone--flat{
  position:static;display:inline-flex;align-items:center;gap:var(--site-space-2);
  margin-bottom:var(--site-space-3);color:var(--site-accent);background:transparent;padding:0;
}
.sb-delivery__zone--flat::before{content:"";width:var(--site-space-2);height:var(--site-space-2);border-radius:50%;background:currentColor}
.sb-delivery__body{display:grid;gap:var(--site-space-4);align-content:start}
.sb-delivery__facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,8rem),1fr));gap:var(--site-space-2)}
.sb-delivery__fact{min-width:0;padding:var(--site-space-3);border-radius:var(--site-r-card);background:var(--site-surface)}
.sb-delivery__fact b{
  display:block;font-family:var(--site-display);font-weight:var(--site-display-weight);
  font-size:var(--site-h4);line-height:var(--site-display-lh);letter-spacing:var(--site-display-ls);overflow-wrap:anywhere;
}
.sb-delivery__fact span{display:block;margin-top:var(--site-space-1);font-size:var(--site-small);color:var(--site-muted)}
.sb-delivery__zones{list-style:none;margin:0;padding:0;border-top:1px solid var(--site-line)}
.sb-delivery__zone-row{
  display:flex;flex-wrap:wrap;justify-content:space-between;gap:var(--site-space-1) var(--site-space-4);
  padding-block:var(--site-space-3);border-bottom:1px solid var(--site-hairline);
}
.sb-delivery__zone-row b{font-weight:600}
.sb-delivery__zone-row span{font-size:var(--site-small);color:var(--site-muted)}
.sb-delivery__note{max-width:var(--site-w-read);font-size:var(--site-small);color:var(--site-muted)}
.sb-delivery__body > .sb-btn{justify-self:start}
.sb-delivery__order{margin-top:var(--site-space-7);padding:0}

/* The island draws the live search beside the view (it renders the view and adds its controls next
   to it), so the band, the search and the catalogue are siblings here: the search goes BETWEEN the
   conditions and the dishes, not above the heading. */
.sb-delivery:has(> .sb-menu-catalog__live){display:flex;flex-direction:column}
.sb-delivery > .sb-delivery__inner{order:-2}
.sb-delivery > .sb-menu-catalog__live{order:-1;margin-top:var(--site-space-6)}

@media (min-width:900px){
  .sb-delivery__in:has(> .sb-delivery__map){grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--site-space-8)}
}

/* --- directions --- */
.sb-directions__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-5)}
.sb-directions__grid{display:grid;gap:var(--site-gap)}
.sb-directions__tile{position:relative;display:block;min-width:0;color:var(--site-ink)}
/* The frame is a `<span>` (parts.tsx `Media`) inside a block-level link: left inline, it ignored
   `aspect-ratio`, and the picture's `height:100%` resolved against the grid-stretched tile — the
   photo took the whole tile and the caption hung below it, under the next tile on a phone
   (ox.smenapos.ru «deals», 2026-10-14). As a block the frame keeps the card ratio and the tile
   is photo + caption. */
.sb-directions__photo{display:block;aspect-ratio:var(--site-ratio-card)}
/* `photo_ratio` (node site-directions-photo-ratio): the tile shows an Instagram post (4:5) or story
   (9:16) whole instead of cropping it to the pack's card. */
.sb-directions__grid[data-ratio="post"] .sb-directions__photo{aspect-ratio:4 / 5}
.sb-directions__grid[data-ratio="story"] .sb-directions__photo{aspect-ratio:9 / 16}
.sb-directions__cap{
  display:grid;gap:var(--site-space-1);padding:var(--site-space-3) var(--site-space-4);
  background:var(--site-surface);border:1px solid var(--site-line);border-top:0;
}
.sb-directions__cap b{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  font-size:var(--site-h4);letter-spacing:var(--site-display-ls);text-transform:var(--site-display-case);
}
.sb-directions__cap span{font-size:var(--site-small);color:var(--site-muted)}

/* `rows` — the same list without photographs, ruled: the shape a group page uses low on the page.
   `strip` scrolls the tiles on one row, which is what four of them do on a phone. */
.sb-directions[data-variant="rows"] .sb-directions__grid{gap:0;border-top:1px solid var(--site-line)}
.sb-directions[data-variant="rows"] .sb-directions__photo{display:none}
.sb-directions[data-variant="rows"] .sb-directions__cap{
  border:0;border-bottom:1px solid var(--site-hairline);background:transparent;
  padding-inline:0;padding-block:var(--site-space-4);
}
/* РЕЛЬС ВЫХОДИТ ЗА ПОЛЯ ПОЛОСЫ и возвращает их себе — чтобы прокрутка начиналась от самого края
   экрана. Значит, он обязан называть ТО ЖЕ поле, что несёт полоса, на обеих ширинах: до этого узла
   десктопной половины тут не было, и на паке editorial это не бросалось в глаза только потому, что
   у него совпадали оба поля (16/16). Как только десктопное поле стало другим, рельс начал
   останавливаться на полпути. Так же это написано у `menu-catalog__tabs` и `menu-highlights__rail`. */
.sb-directions[data-variant="strip"] .sb-directions__grid{
  display:flex;overflow-x:auto;scroll-snap-type:x mandatory;
  margin-inline:calc(var(--site-gutter) * -1);padding-inline:var(--site-gutter);
}
.sb-directions[data-variant="strip"] .sb-directions__tile{flex:0 0 78%;scroll-snap-align:start}

@media (min-width:900px){
  .sb-directions__grid{grid-template-columns:repeat(4,1fr)}
  .sb-directions[data-variant="rows"] .sb-directions__grid{grid-template-columns:1fr}
  .sb-directions[data-variant="rows"] .sb-directions__cap{display:flex;align-items:baseline;gap:var(--site-space-5)}
  .sb-directions[data-variant="strip"] .sb-directions__grid{
    margin-inline:calc(var(--site-gutter-d) * -1);padding-inline:var(--site-gutter-d);
  }
  .sb-directions[data-variant="strip"] .sb-directions__tile{flex:0 0 calc(100% / 4)}
}

/* --- dish-card --- */
.sb-dish-card{position:relative}
.sb-dish-card[data-variant="tile"]{
  background:var(--site-surface);border:1px solid var(--site-line);border-radius:var(--site-r-card);
  overflow:hidden;display:grid;grid-template-rows:auto 1fr;box-shadow:var(--site-shadow-card);
}
.sb-dish-card[data-variant="tile"] .sb-media{border-radius:0}
.sb-dish-card__body{padding:var(--site-space-4);display:grid;gap:var(--site-space-2);align-content:start}
.sb-dish-card__title{font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-size:var(--site-h4);font-weight:var(--site-display-weight);letter-spacing:var(--site-display-ls);line-height:1.2}
.sb-dish-card__note{font-size:var(--site-small);color:var(--site-muted)}
.sb-dish-card__foot{display:flex;align-items:center;justify-content:space-between;gap:var(--site-space-3);margin-top:var(--site-space-1)}
.sb-dish-card__add{
  width:var(--site-btn-h);height:var(--site-btn-h);min-width:var(--site-btn-h);
  border-radius:var(--site-r-btn);background:var(--site-accent);color:var(--site-on-accent);
  display:grid;place-items:center;border:0;
}
.sb-dish-card__add svg{width:1.15em;height:1.15em}
.sb-dish-card__add[data-state="off"]{background:var(--site-surface-2);color:var(--site-faint)}
.sb-dish-card__badge{position:absolute;top:var(--site-space-3);left:var(--site-space-3);z-index:2;background:var(--site-surface);box-shadow:var(--site-shadow-card)}
.sb-dish-card[data-variant="row"]{
  display:flex;gap:var(--site-space-4);align-items:center;padding-block:var(--site-space-4);
}
.sb-dish-card[data-variant="row"] .sb-media{width:calc(var(--site-space-8) + var(--site-space-4));flex:none;aspect-ratio:var(--site-ratio-tile)}
.sb-dish-card[data-variant="row"] .sb-dish-card__body{padding:0;flex:1;min-width:0}
.sb-dish-card[data-variant="line"]{display:grid;grid-template-columns:minmax(0,auto) minmax(var(--site-space-5),1fr) auto;align-items:baseline;column-gap:var(--site-space-3);row-gap:var(--site-space-1);padding-block:var(--site-space-3)}
.sb-dish-card[data-variant="line"] .sb-dish-card__note{grid-column:1/-1;order:3}
.sb-dish-card[data-variant="line"] .sb-dish-card__title{font-size:var(--site-body-size);font-family:var(--site-body);font-weight:600;letter-spacing:0}
.sb-dish-card__leader{align-self:center;border-bottom:1px dotted var(--site-line)}
.sb-dish-card[data-state="stopped"] .sb-dish-card__title{color:var(--site-muted)}
.sb-dish-card[data-state="stopped"] .sb-media img{filter:grayscale(1);opacity:.5}

@media (min-width:900px){
  .sb-menu-catalog__list .sb-dish-card{break-inside:avoid}
}

/* In the «Día» feed of the home (`menu-highlights` variant `rail`, node dia-home-look): a 150-wide
   white card of radius 24, a square photo inset, the name on two lines, the price and a round grey
   «+» (comanda-dia/screens/dia-home.html `.pcard`). Keyed by the rail band's ATTRIBUTES, so this
   sheet names no class but its own and the band's sheet names none of this block's.
   The «+» is answered by the menu island of the page; until that island takes it on (`data-wired`)
   it holds its place but is not there — out of sight and out of the tab order — because a «+»
   nothing answers is a dead control. */
[data-block="menu-highlights"][data-variant="rail"] .sb-dish-card{
  display:flex;flex-direction:column;gap:calc(var(--site-space-3) * .75);
  padding:calc(var(--site-space-2) * 1.25);border:0;box-shadow:none;
  border-radius:calc(var(--site-r-card) * 6 / 7);background:var(--site-surface);
}
[data-block="menu-highlights"][data-variant="rail"] .sb-dish-card .sb-media{
  aspect-ratio:var(--site-ratio-tile);border-radius:calc(var(--site-r-media) * .85);
}
[data-block="menu-highlights"][data-variant="rail"] .sb-dish-card__body{
  flex:1;display:flex;flex-direction:column;gap:calc(var(--site-space-3) * .75);padding:0;
}
[data-block="menu-highlights"][data-variant="rail"] .sb-dish-card__title{
  font-family:var(--site-body);font-size:var(--site-body-size);font-weight:400;letter-spacing:-.01em;
  text-transform:none;line-height:1.22;min-height:calc(2 * 1.22em);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
[data-block="menu-highlights"][data-variant="rail"] .sb-dish-card__note{display:none}
[data-block="menu-highlights"][data-variant="rail"] .sb-dish-card__foot{margin-top:auto;gap:var(--site-space-1)}
[data-block="menu-highlights"][data-variant="rail"] .sb-dish-card__add{
  position:relative;width:calc(var(--site-space-3) * 3);height:calc(var(--site-space-3) * 3);
  min-width:calc(var(--site-space-3) * 3);border-radius:var(--site-r-btn);
  background:var(--site-surface-2);color:var(--site-ink);
}
[data-block="menu-highlights"][data-variant="rail"] .sb-dish-card__add::after{
  content:"";position:absolute;inset:calc(var(--site-space-1) * -1);
}
[data-block="menu-highlights"][data-variant="rail"] .sb-dish-card__add:not([data-wired]){visibility:hidden}

/* In the compact rows of the menu (`menu-catalog` variant `rows`, node site-blocks-legacy-look): the
   row of the legacy storefront list — a round photo on the left (80, the `row` thumbnail's box, so
   its `sizes` stays true), the name and up to two lines of description, the price and the «+» on
   the right, centred against the text. A dish with no photo is the same row without the circle (the
   card prints no frame for it). Keyed by the band's ATTRIBUTES, like the rail above (G-5). */
[data-block="menu-catalog"][data-variant="rows"] .sb-dish-card[data-variant="row"]{
  gap:var(--site-space-3);padding-block:calc(var(--site-space-3) + var(--site-space-1) / 2);
}
[data-block="menu-catalog"][data-variant="rows"] .sb-dish-card[data-variant="row"] .sb-media{
  aspect-ratio:1;border-radius:50%;
}
[data-block="menu-catalog"][data-variant="rows"] .sb-dish-card[data-variant="row"] .sb-dish-card__body{
  display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;
  column-gap:var(--site-space-3);row-gap:var(--site-space-1);
}
[data-block="menu-catalog"][data-variant="rows"] .sb-dish-card[data-variant="row"] .sb-dish-card__title{
  grid-column:1;font-size:var(--site-body-size);line-height:1.3;overflow-wrap:anywhere;
}
[data-block="menu-catalog"][data-variant="rows"] .sb-dish-card[data-variant="row"] .sb-dish-card__note{
  grid-column:1;line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
[data-block="menu-catalog"][data-variant="rows"] .sb-dish-card[data-variant="row"] .sb-dish-card__foot{
  grid-column:2;grid-row:1 / span 2;align-self:center;margin:0;gap:var(--site-space-2);
}
[data-block="menu-catalog"][data-variant="rows"] .sb-dish-card[data-variant="row"] .sb-dish-card__add{
  width:var(--site-btn-h-sm);height:var(--site-btn-h-sm);min-width:var(--site-btn-h-sm);border-radius:50%;
}
/* The badge sits on the circle's edge, not over the middle of the photo. */
[data-block="menu-catalog"][data-variant="rows"] .sb-dish-card[data-variant="row"] .sb-dish-card__badge{
  top:var(--site-space-2);left:0;
}

/* In the «Most ordered» strip (`menu-highlights` variant `ribbon`, node site-blocks-legacy-look): the
   legacy `.oc-hero` card — a 4:5 photograph (4:3 on a desktop) of radius 24, the pack's scrim over
   its lower part, the name on the photo and the price as a glass pill beside the «+». The card wears
   the pack's dark scheme (View.tsx), so `--site-ink` here is the light type of that scheme. A dish
   with no photo keeps the pack's placeholder: a strip of cards needs every cell the same shape. */
[data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card{
  display:block;aspect-ratio:4 / 5;overflow:hidden;isolation:isolate;
  border:0;box-shadow:none;border-radius:calc(var(--site-r-card) * 1.2);background:var(--site-surface-2);
}
[data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card .sb-media{
  position:absolute;inset:0;aspect-ratio:auto;border-radius:0;
}
[data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;background:var(--site-scrim);
}
[data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card__body{
  position:absolute;left:0;right:0;bottom:0;z-index:2;padding:var(--site-space-4);gap:var(--site-space-3);
}
[data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card__title{
  color:var(--site-ink);font-size:var(--site-h4);line-height:1.2;overflow-wrap:anywhere;text-wrap:balance;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;
}
[data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card__note{display:none}
[data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card__foot{justify-content:flex-start;margin:0;gap:var(--site-space-2)}
[data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card .sb-price{
  display:inline-flex;align-items:center;height:var(--site-btn-h-sm);padding-inline:var(--site-space-4);
  border-radius:var(--site-r-chip);color:var(--site-ink);
  background:color-mix(in srgb,var(--site-bg) 72%,transparent);
  backdrop-filter:blur(var(--site-space-2));-webkit-backdrop-filter:blur(var(--site-space-2));
}
[data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card__add{
  position:relative;width:var(--site-btn-h-sm);height:var(--site-btn-h-sm);min-width:var(--site-btn-h-sm);border-radius:50%;
}
[data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card__add::after{content:"";position:absolute;inset:calc(var(--site-space-1) * -1)}
/* Answered by the page's menu island, as on the `rail`: until it is wired it is not there. */
[data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card__add:not([data-wired]){display:none}
@media (min-width:900px){
  [data-block="menu-highlights"][data-variant="ribbon"] .sb-dish-card{aspect-ratio:4 / 3}
}

/* «Пропорции фото блюд» (`photo_ratio`, node dish-photo-ratio): the frame of a TILE photo, chosen by
   the parent band (`menu-catalog` showcase, `menu-highlights` carousel/grid), which writes the
   attribute on its inner wrapper only when the author picked something other than the pack's own
   card ratio. POS photographs are about square: in a 16:9 frame half of the plate is cut away, in
   1:1 it is whole. The image keeps `object-fit:cover` and its `photo.focal` object-position. */
[data-photo-ratio="16:9"] .sb-dish-card[data-variant="tile"] .sb-media{aspect-ratio:16 / 9}
[data-photo-ratio="4:3"] .sb-dish-card[data-variant="tile"] .sb-media{aspect-ratio:4 / 3}
[data-photo-ratio="1:1"] .sb-dish-card[data-variant="tile"] .sb-media{aspect-ratio:1 / 1}

/* --- events --- */
.sb-events__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-5)}
.sb-events__head{display:grid;gap:var(--site-space-2)}
.sb-events__grid{display:grid;gap:var(--site-gap)}
.sb-events__card{
  display:flex;flex-direction:column;gap:var(--site-space-2);align-items:flex-start;min-width:0;
  padding:var(--site-space-4);border:1px solid var(--site-line);border-radius:var(--site-r-card);
  background:var(--site-surface);color:var(--site-ink);
}
.sb-events__card b{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  font-size:var(--site-h4);letter-spacing:var(--site-display-ls);text-transform:var(--site-display-case);
}
.sb-events__value{
  font-family:var(--site-mono);font-variant-numeric:tabular-nums;font-weight:600;
  font-size:var(--site-small);color:var(--site-accent);
}
.sb-events__note{font-size:var(--site-small);color:var(--site-muted)}
.sb-events__text{font-size:var(--site-small);color:var(--site-muted)}
.sb-events__photo{width:100%;aspect-ratio:var(--site-ratio-card)}
.sb-events__cover{aspect-ratio:var(--site-ratio-card)}
.sb-events__act{display:flex;flex-wrap:wrap;gap:var(--site-space-2)}

/* `rows` — the formats ruled into a list, for a house that offers eight of them and one photo;
   `feature` stands the list beside the photograph of the room (mockup `sb-promo-banner` card). */
.sb-events[data-variant="rows"] .sb-events__grid{gap:0;border-top:1px solid var(--site-line)}
.sb-events[data-variant="rows"] .sb-events__card{
  border:0;border-bottom:1px solid var(--site-hairline);border-radius:0;background:transparent;
  padding-inline:0;flex-direction:row;align-items:baseline;gap:var(--site-space-4);flex-wrap:wrap;
}
.sb-events[data-variant="rows"] .sb-events__value{margin-left:auto;order:2}
.sb-events[data-variant="rows"] .sb-events__photo{display:none}

@media (min-width:900px){
  .sb-events__grid{grid-template-columns:repeat(3,1fr)}
  .sb-events[data-variant="rows"] .sb-events__grid{grid-template-columns:1fr}
  .sb-events[data-variant="feature"] .sb-events__inner{
    grid-template-columns:minmax(0,3fr) minmax(0,2fr);align-items:start;column-gap:var(--site-space-8);
  }
  .sb-events[data-variant="feature"] .sb-events__head{grid-column:1;max-width:var(--site-w-read)}
  .sb-events[data-variant="feature"] .sb-events__grid{grid-column:1;grid-template-columns:1fr 1fr}
  .sb-events[data-variant="feature"] .sb-events__cover{grid-column:2;grid-row:1 / span 3;position:sticky;top:var(--site-space-6)}
  .sb-events[data-variant="feature"] .sb-events__act{grid-column:1}
}

/* --- faq --- */
.sb-faq__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-5)}
.sb-faq__list{max-width:var(--site-w-read);border-top:1px solid var(--site-line)}
.sb-faq__item{border-bottom:1px solid var(--site-line)}
.sb-faq__q{
  display:flex;align-items:center;gap:var(--site-space-4);width:100%;
  min-height:calc(var(--site-btn-h) + var(--site-space-3));padding-block:var(--site-space-3);
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-size:var(--site-h4);font-weight:var(--site-display-weight);
  letter-spacing:var(--site-display-ls);text-align:left;color:var(--site-ink);
}
.sb-faq__q i{margin-left:auto;flex:none;color:var(--site-accent)}
.sb-faq__q svg{width:1.1em;height:1.1em}
.sb-faq__a{padding-bottom:var(--site-space-4);color:var(--site-muted);max-width:var(--site-w-read)}

@media (min-width:900px){
  .sb-faq__inner{grid-template-columns:.7fr 1.3fr;gap:var(--site-space-8);align-items:start}
}

/* The head column (heading + optional action) and the two variants beside `accordion`. An answer
   is authored as richtext and printed as TEXT, so its line breaks are honoured by css rather than
   by html the block would have to trust. `[data-state="closed"]` is only ever written by the
   browser (View.tsx) — server markup keeps every answer open. */
.sb-faq__aside{display:grid;gap:var(--site-space-4);justify-items:start;align-content:start}
.sb-faq__a{white-space:pre-line}
.sb-faq__item[data-state="closed"] .sb-faq__a{display:none}
.sb-faq[data-variant="plain"] .sb-faq__q i{display:none}

@media (min-width:900px){
  .sb-faq[data-variant="two-columns"] .sb-faq__item{display:grid;grid-template-columns:1fr 1fr;gap:var(--site-space-5);align-items:start}
  .sb-faq[data-variant="two-columns"] .sb-faq__a{padding-top:var(--site-space-3)}
  .sb-faq__list[data-columns="2"]{max-width:none;display:grid;grid-template-columns:1fr 1fr;column-gap:var(--site-space-8)}
}

/* --- gallery --- */
.sb-gallery__inner{max-width:var(--site-w-page);margin-inline:auto}
.sb-gallery__grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--site-gap)}
.sb-gallery__item{min-width:0}
.sb-gallery__grid .sb-media{aspect-ratio:var(--site-ratio-card)}
.sb-gallery__grid[data-ratio="tile"] .sb-media{aspect-ratio:var(--site-ratio-tile)}
.sb-gallery__grid[data-ratio="free"] .sb-media{aspect-ratio:auto}
.sb-gallery__grid[data-ratio="free"] .sb-media img{height:auto}
.sb-gallery__cap{font-size:var(--site-micro);color:var(--site-faint);margin-top:var(--site-space-2)}
.sb-gallery__note{margin-top:var(--site-space-4);font-size:var(--site-small);color:var(--site-muted)}

/* `carousel` — one row that scrolls, with a snap point per frame: on a phone the whole block is a
   strip the thumb drags, and 1.2 frames stand in the viewport so the second one says «keep going»
   (spec/blocks.md §3.3, «мобильный — карусель со снапом»). */
/* РЕЛЬС ВЫХОДИТ ЗА ПОЛЯ ПОЛОСЫ и возвращает их себе — чтобы прокрутка начиналась от самого края
   экрана. Значит, он обязан называть ТО ЖЕ поле, что несёт полоса, на обеих ширинах: до этого узла
   десктопной половины тут не было, и на паке editorial это не бросалось в глаза только потому, что
   у него совпадали оба поля (16/16). Как только десктопное поле стало другим, рельс начал
   останавливаться на полпути. Так же это написано у `menu-catalog__tabs` и `menu-highlights__rail`. */
.sb-gallery[data-variant="carousel"] .sb-gallery__grid{
  display:flex;overflow-x:auto;scroll-snap-type:x mandatory;
  margin-inline:calc(var(--site-gutter) * -1);padding-inline:var(--site-gutter);
}
.sb-gallery[data-variant="carousel"] .sb-gallery__item{flex:0 0 80%;scroll-snap-align:start}

/* `masonry` — the same list in css columns, with three of the frames given another crop so the
   wall is not a grid in disguise (mockup site-editorial-08-custom-md.html). */
.sb-gallery[data-variant="masonry"] .sb-gallery__grid{display:block;columns:2;column-gap:var(--site-gap)}
.sb-gallery[data-variant="masonry"] .sb-gallery__item{display:block;width:100%;margin-bottom:var(--site-gap);break-inside:avoid}
.sb-gallery[data-variant="masonry"] .sb-gallery__item:nth-child(3n+1) .sb-media{aspect-ratio:var(--site-ratio-tile)}
.sb-gallery[data-variant="masonry"] .sb-gallery__item:nth-child(4n) .sb-media{aspect-ratio:var(--site-ratio-hero)}

@media (min-width:900px){
  .sb-gallery__grid[data-columns="2"]{grid-template-columns:repeat(2,1fr)}
  .sb-gallery__grid[data-columns="3"]{grid-template-columns:repeat(3,1fr)}
  .sb-gallery__grid[data-columns="4"]{grid-template-columns:repeat(4,1fr)}
  .sb-gallery__grid[data-columns="5"]{grid-template-columns:repeat(5,1fr)}
  .sb-gallery[data-variant="carousel"] .sb-gallery__grid{
    margin-inline:calc(var(--site-gutter-d) * -1);padding-inline:var(--site-gutter-d);
  }
  .sb-gallery[data-variant="carousel"] .sb-gallery__item{flex:0 0 calc(100% / 4)}
  .sb-gallery[data-variant="masonry"] .sb-gallery__grid{columns:3}
}

/* ── Island states (site-islands-hydrate): the viewer. `data-live` is the island's own mark, so a
   frame only looks clickable once something can actually open it (no-dead-controls). ── */
.sb-gallery[data-live="on"] .sb-gallery__item{cursor:zoom-in}
.sb-gallery__viewer{
  position:fixed;inset:0;z-index:70;
  display:flex;align-items:center;justify-content:center;gap:var(--site-space-2);
  padding:var(--site-space-4);background:var(--site-scrim);
}
.sb-gallery__full{max-width:min(96vw,var(--site-w-page));max-height:88vh;display:flex;flex-direction:column;gap:var(--site-space-2)}
.sb-gallery__full img{width:auto;max-width:100%;max-height:80vh;object-fit:contain;border-radius:var(--site-r-media)}
.sb-gallery__full figcaption{color:var(--site-on-accent);font-size:var(--site-small);text-align:center}
.sb-gallery__x{
  position:absolute;top:var(--site-space-4);right:var(--site-space-4);
  width:var(--site-btn-h);height:var(--site-btn-h);border-radius:var(--site-r-btn);
  display:grid;place-items:center;font-size:var(--site-h3);line-height:1;color:var(--site-on-accent);
}
.sb-gallery__nav{
  width:var(--site-btn-h);height:var(--site-btn-h);flex:none;border-radius:var(--site-r-btn);
  display:grid;place-items:center;font-size:var(--site-h2);line-height:1;color:var(--site-on-accent);
}

/* `slider` — the venue's photographs on the «Día» guest home (node dia-home-look): one 4:3 frame
   per screen with the next one peeking inside the gutter, snapping, and a row of dots under it —
   the active dot a wider ink pill. Sizes are the mockup's (gap 10, peek 28, dot 6, pill 16), as
   multiples of the pack's steps. The dots are marked by the island (`aria-current`); before it
   wakes the first dot stands marked, and without it the strip simply scrolls. */
.sb-gallery[data-variant="slider"] .sb-gallery__grid{
  display:flex;gap:calc(var(--site-space-2) * 1.25);overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;scroll-padding-inline:var(--site-gutter);scrollbar-width:none;
  margin-inline:calc(var(--site-gutter) * -1);padding-inline:var(--site-gutter);
}
.sb-gallery[data-variant="slider"] .sb-gallery__item{flex:0 0 calc(100% - var(--site-space-1) * 7);scroll-snap-align:start}
.sb-gallery[data-variant="slider"] .sb-gallery__grid .sb-media{display:block;border-radius:var(--site-r-card)}
.sb-gallery__dots{
  display:flex;justify-content:center;gap:calc(var(--site-space-1) * 1.5);
  margin-top:calc(var(--site-space-3) + var(--site-space-1) / 2);
}
.sb-gallery__dot{
  position:relative;display:block;padding:0;border:0;
  width:calc(var(--site-space-1) * 1.5);height:calc(var(--site-space-1) * 1.5);
  border-radius:var(--site-r-chip);background:color-mix(in srgb,var(--site-faint) 35%,var(--site-line));
  transition:width .18s ease,background-color .18s ease;
}
.sb-gallery__dot::after{content:"";position:absolute;inset:calc(var(--site-space-3) * -1) calc(var(--site-space-2) * -1)}
.sb-gallery__dot[aria-current="true"],
.sb-gallery:not([data-live="on"]) .sb-gallery__dot:first-child{width:var(--site-space-4);background:var(--site-ink)}

@media (min-width:900px){
  /* Desktop is not redesigned (contract Out): the slider lays its frames out as the block's grid. */
  .sb-gallery[data-variant="slider"] .sb-gallery__grid{display:grid;overflow:visible;margin-inline:0;padding-inline:0}
  .sb-gallery__dots{display:none}
}

/* --- guest-hello --- */
/* guest-hello — полоса гостя в двух состояниях. Стили перенесены из макета выбранного варианта
   (site-parrilla-02-home-hub-b-md.html, секция `guest_hello`) значение в значение; изменены
   только имена селекторов и медиазапрос (в макете доска подменяет его на `@container`).

   СВОЙ ВОЗДУХ, А НЕ ВОЗДУХ СЕКЦИИ. Полоса гостя стоит между визиткой и карточками намерений и
   обязана быть тоньше обычной полосы — иначе первый экран «пульта» не помещается в телефон.
   Общий ритм при этом не переписывается (его нельзя переписывать — purity.test.ts): здесь
   назначен ДРУГОЙ воздух, той же природы, что у `today` и у `promo-banner strip`. */
.sb-guest-hello{padding-block:var(--site-space-3)}
/* No border (node dia-home-look): a card stands on the canvas by its colour; a pack that wants an
   edge gives it through `--site-shadow-card`. */
.sb-guest-hello__inner{
  max-width:var(--site-w-page);margin-inline:auto;
  border-radius:var(--site-r-card);
  background:var(--site-surface);box-shadow:var(--site-shadow-card);overflow:hidden;
}

/* ── узнанный гость ─────────────────────────────────────────────────────────────────────────── */
.sb-guest-hello__top{display:flex;align-items:center;gap:var(--site-space-3);padding:var(--site-space-4)}
.sb-guest-hello__ava{
  flex:none;
  width:calc(var(--site-space-8) - var(--site-space-3));
  height:calc(var(--site-space-8) - var(--site-space-3));
  border-radius:var(--site-r-chip);background:var(--site-accent-soft);color:var(--site-accent);
  display:grid;place-items:center;font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);
  font-size:var(--site-h4);font-weight:var(--site-display-weight);
}
.sb-guest-hello__who{flex:1;min-width:0;display:grid;gap:var(--site-space-1)}
.sb-guest-hello__who b{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-size:var(--site-h3);
  font-weight:var(--site-display-weight);letter-spacing:var(--site-display-ls);
}
.sb-guest-hello__who span{font-size:var(--site-small);color:var(--site-muted)}
.sb-guest-hello__pts{flex:none;text-align:right;display:grid;gap:var(--site-space-1)}
.sb-guest-hello__pts b{
  font-family:var(--site-mono);font-variant-numeric:tabular-nums;
  font-size:var(--site-h4);color:var(--site-ink);
}
.sb-guest-hello__pts span{
  font-size:var(--site-micro);letter-spacing:var(--site-micro-ls);
  text-transform:uppercase;color:var(--site-faint);
}
.sb-guest-hello__last{
  display:flex;align-items:center;gap:var(--site-space-3);
  padding:var(--site-space-3) var(--site-space-4);
  border-top:1px solid var(--site-hairline);background:var(--site-surface-2);
}
.sb-guest-hello__last .sb-media{
  flex:none;
  width:calc(var(--site-space-8) - var(--site-space-2));
  height:calc(var(--site-space-8) - var(--site-space-2));
}
.sb-guest-hello__last div{flex:1;min-width:0;display:grid;gap:var(--site-space-1)}
.sb-guest-hello__last b{font-size:var(--site-body-size);font-weight:600;display:block;line-height:1.25}
.sb-guest-hello__last span{font-size:var(--site-small);color:var(--site-muted)}
.sb-guest-hello__last .sb-btn{flex:none}

/* ── незнакомый гость ───────────────────────────────────────────────────────────────────────── */
/* The sign-in card of «Día» (dia-home.html `.hello`): a question, why to sign in, then the ways in
   as full-width pills. The question is a sentence, not a section heading, so it keeps its capital
   even on a pack that lowercases headings; the mockup's size is the pack's h3 plus three. */
.sb-guest-hello__body{display:grid;gap:var(--site-space-4);padding:var(--site-space-4) var(--site-space-4) var(--site-space-3)}
.sb-guest-hello__say{display:grid;gap:var(--site-space-2);min-width:0}
.sb-guest-hello__body h3{font-size:calc(var(--site-h3) + var(--site-space-1) * .75);text-transform:none;letter-spacing:-.02em}
.sb-guest-hello__body .sb-rt{font-size:var(--site-small);color:var(--site-muted)}
.sb-guest-hello__ways{display:grid;gap:var(--site-space-3);align-content:start}
.sb-guest-hello__ways .sb-btn{width:100%}
/* Второй способ входа — строка со значком, а не кнопка: у входа с карты нет контрола, который
   можно нажать здесь (View.tsx). Тач-цели у строки нет намеренно — это не контрол. */
.sb-guest-hello__wallet{
  display:flex;align-items:flex-start;gap:var(--site-space-2);
  font-size:var(--site-small);color:var(--site-muted);line-height:1.35;
}
.sb-guest-hello__wallet svg{width:1.2em;height:1.2em;flex:none;color:var(--site-faint)}
.sb-guest-hello__note{
  font-size:var(--site-micro);color:var(--site-muted);
  padding:0 var(--site-space-4) var(--site-space-4);
}

/* Кнопка «повторить» стоит в строке прошлого заказа и обязана быть ниже обычной: строка тонкая. */
.sb-btn--sm{
  height:var(--site-btn-h-sm);min-height:var(--site-btn-h-sm);
  padding-inline:var(--site-space-4);font-size:var(--site-small);
}

/* Вариант `strip` — та же полоса, где место дорого: без прошлого заказа и мельче. */
.sb-guest-hello[data-variant="strip"] .sb-guest-hello__top{padding:var(--site-space-3) var(--site-space-4)}
.sb-guest-hello[data-variant="strip"] .sb-guest-hello__who b{font-size:var(--site-h4)}
.sb-guest-hello[data-variant="strip"] .sb-guest-hello__ava{
  width:var(--site-btn-h-sm);height:var(--site-btn-h-sm);font-size:var(--site-body-size);
}
.sb-guest-hello[data-variant="strip"] .sb-guest-hello__last{display:none}

/* ── variant `sheet` — the card sheet of the «Día» home (node dia-home-look) ────────────────────
   A known guest has nothing on the page itself (his points are on the card tile), so the section
   dissolves its box instead of leaving the band's air around an empty place; the fixed sheet is
   all that is left of it. The card face is the pack's ink plate (the Wallet pass of the mockup:
   ink with white type), the ladder a white card under it. */
.sb-guest-hello[data-variant="sheet"]:not(:has(> .sb-guest-hello__inner)){display:contents}
.sb-guest-hello__card{display:grid;gap:var(--site-space-3)}
.sb-guest-hello__face{
  display:grid;gap:var(--site-space-2);padding:var(--site-space-5);
  min-height:calc(var(--site-space-8) * 3);align-content:space-between;
  border-radius:var(--site-r-card);background:var(--site-btn-accent);color:var(--site-btn-on-accent);
}
.sb-guest-hello__tier{font-size:var(--site-h3);font-weight:600;letter-spacing:-.015em}
.sb-guest-hello__balance{display:flex;align-items:baseline;gap:var(--site-space-2)}
.sb-guest-hello__balance b{font-size:calc(var(--site-space-6) + var(--site-space-2));font-weight:600;letter-spacing:-.03em;line-height:1;font-variant-numeric:tabular-nums}
.sb-guest-hello__balance span,.sb-guest-hello__rate span{font-size:var(--site-small);color:color-mix(in srgb,var(--site-btn-on-accent) 82%,var(--site-btn-accent))}
.sb-guest-hello__rate{display:flex;align-items:center;gap:var(--site-space-2)}
.sb-guest-hello__rate b{
  display:inline-grid;place-items:center;min-height:var(--site-btn-h-sm);padding-inline:var(--site-space-3);
  border-radius:var(--site-r-chip);border:1px solid color-mix(in srgb,var(--site-btn-on-accent) 85%,transparent);
  font-size:var(--site-h4);font-weight:600;
}
.sb-guest-hello__ladder{display:grid;gap:var(--site-space-3);padding:var(--site-space-4);border-radius:var(--site-r-card);background:var(--site-surface)}
.sb-guest-hello__ladder p{font-size:var(--site-body-size);font-weight:600}
.sb-guest-hello__bar{display:block;height:calc(var(--site-space-1) * 1.5);border-radius:var(--site-r-chip);background:var(--site-surface-2);overflow:hidden}
.sb-guest-hello__bar i{display:block;height:100%;width:var(--sb-progress,0%);border-radius:inherit;background:var(--site-ink)}
.sb-guest-hello__card .sb-btn{width:100%}

/* ── the known guest's card (node dia-card-tiers; dia-home.html `.tiers` / `.tier` / `.ladder` /
   `.coupon`, brand-spec v9–v11, v22) — drawn by the card sheet's lazy renderer (guest-hello/card.tsx).
   Sizes are the mockup's, written in the pack's scale: 20 = space-4 + space-1, 28 = space-5 + space-1,
   40 = space-6 + space-2, 44 = space-6 + space-3, 196 = space-8 × 3 + space-1.
   Colour comes from the element (`--sb-tier`, `--sb-tier-ink` — the tier and the white it carries at
   ≥ 4.5:1). Every shade on the face is the tier moved toward the pack's ink, never toward white, so no
   pixel under the text is lighter than the tier itself; the text is solid, never a faded white. */
.sb-guest-card{display:grid;gap:var(--site-space-3)}
.sb-guest-card__strip{
  display:flex;gap:var(--site-space-3);overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;scroll-padding-inline:var(--site-gutter);scrollbar-width:none;
  margin-inline:calc(var(--site-gutter) * -1);padding:var(--site-space-1) var(--site-gutter);
}
.sb-guest-card__strip::-webkit-scrollbar{display:none}
.sb-guest-card__tier{
  position:relative;flex:0 0 calc(100% - var(--site-space-5) - var(--site-space-1));scroll-snap-align:start;
  min-height:calc(var(--site-space-8) * 3 + var(--site-space-1));
  display:flex;flex-direction:column;
  padding:calc(var(--site-space-4) + var(--site-space-1)) calc(var(--site-space-4) + var(--site-space-1)) calc(var(--site-space-4) + var(--site-space-1) * .5);
  border-radius:var(--site-r-card);color:var(--sb-tier-ink);
  /* The solid tier colour UNDER the sheen: it is what a contrast check reads as the ground, and what
     stays if a browser cannot mix colours. */
  background-color:var(--sb-tier);
  background-image:linear-gradient(135deg,var(--sb-tier) 0%,var(--sb-tier) 52%,color-mix(in oklch,var(--sb-tier),var(--site-ink) 12%) 100%);
}
/* Tiers ahead are on the strip but not his yet: the whole card dimmed, the lock says why (brand-spec v10). */
.sb-guest-card__tier[data-locked="on"]{opacity:.6}
.sb-guest-card__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--site-space-3)}
.sb-guest-card__name{font-size:var(--site-h3);font-weight:600;letter-spacing:-.015em;padding-top:var(--site-space-1)}
.sb-guest-card__chip{
  flex:none;padding:calc(var(--site-space-1) * 1.5) calc(var(--site-space-2) + var(--site-space-1) * .5);border-radius:var(--site-r-chip);
  background:color-mix(in oklch,var(--sb-tier),var(--site-ink) 28%);
  font-size:calc(var(--site-micro) - 1px);font-weight:500;letter-spacing:.06em;text-transform:uppercase;
}
.sb-guest-card__figure{display:flex;align-items:center;gap:var(--site-space-2);margin-top:var(--site-space-3)}
.sb-guest-card__figure b{font-size:calc(var(--site-space-6) + var(--site-space-2));font-weight:600;letter-spacing:-.03em;line-height:1;font-variant-numeric:tabular-nums}
.sb-guest-card__figure svg{flex:none;width:calc(var(--site-space-5) + var(--site-space-1));height:calc(var(--site-space-5) + var(--site-space-1))}
.sb-guest-card__figure span{font-size:var(--site-h4);font-weight:600}
.sb-guest-card__sub{margin-top:var(--site-space-2);font-size:var(--site-small);text-wrap:pretty}
.sb-guest-card__bot{margin-top:auto;padding-top:calc(var(--site-space-4) + var(--site-space-1) * .5);display:flex;align-items:center;justify-content:space-between;gap:var(--site-space-2)}
.sb-guest-card__rate{display:inline-flex;align-items:center;gap:var(--site-space-2);font-size:var(--site-small)}
.sb-guest-card__rate span{max-width:5.2em;line-height:1.2;text-wrap:balance}
.sb-guest-card__rate b{
  display:inline-grid;place-items:center;height:calc(var(--site-space-6) + var(--site-space-3));
  min-width:calc(var(--site-space-8) + var(--site-space-1) * .5);padding-inline:var(--site-space-3);
  border-radius:var(--site-r-chip);border:1px solid var(--sb-tier-ink);
  font-size:calc(var(--site-h4) + var(--site-space-1));font-weight:600;letter-spacing:-.02em;
}
.sb-guest-card__qr,.sb-guest-card__lock{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--site-space-2);
  height:calc(var(--site-space-6) + var(--site-space-3));border-radius:var(--site-r-chip);
  background:color-mix(in oklch,var(--sb-tier),var(--site-ink) 28%);color:var(--sb-tier-ink);
}
.sb-guest-card__qr{padding-inline:var(--site-space-4);font:inherit;font-size:calc(var(--site-small) + 1px);font-weight:500;white-space:nowrap;border:0;cursor:pointer}
.sb-guest-card__lock{width:calc(var(--site-space-6) + var(--site-space-3))}
.sb-guest-card__qr svg,.sb-guest-card__lock svg{width:calc(var(--site-space-4) + var(--site-space-1) * .5);height:calc(var(--site-space-4) + var(--site-space-1) * .5)}
/* The till's code: dark modules on the sheet's white, four modules of quiet zone in the svg itself. */
.sb-guest-card__code{
  display:grid;justify-items:center;gap:var(--site-space-3);padding:var(--site-space-5) var(--site-space-4);
  border-radius:var(--site-r-card);background:var(--site-surface);text-align:center;
}
.sb-guest-card__code p{font-size:var(--site-body-size);font-weight:600}
.sb-guest-card__code svg{width:calc(var(--site-space-8) * 3);max-width:100%;height:auto;aspect-ratio:1;fill:var(--site-ink);background:var(--site-surface)}
.sb-guest-card__code span{font-size:var(--site-small);color:var(--site-muted);font-variant-numeric:tabular-nums}
.sb-guest-card__code .sb-btn{width:100%}
.sb-guest-card__ladder{
  margin-top:var(--site-space-2);padding:calc(var(--site-space-4) + var(--site-space-1) * .5) calc(var(--site-space-4) + var(--site-space-1) * .5) calc(var(--site-space-1) * 1.5);
  border-radius:var(--site-r-card);background:var(--site-surface);
}
.sb-guest-card__to{font-size:var(--site-body-size);font-weight:600;letter-spacing:-.01em;text-wrap:pretty}
.sb-guest-card__bar{display:block;height:calc(var(--site-space-1) * 1.5);margin-top:var(--site-space-3);border-radius:var(--site-r-chip);background:var(--site-surface-2);overflow:hidden}
.sb-guest-card__bar i{display:block;height:100%;width:var(--sb-progress,0%);border-radius:inherit;background:var(--sb-tier)}
.sb-guest-card__how{margin-top:calc(var(--site-space-4) + var(--site-space-1) * .5);font-size:var(--site-micro);letter-spacing:.06em;text-transform:uppercase;color:var(--site-muted)}
.sb-guest-card__row{display:flex;align-items:center;gap:var(--site-space-3);padding-block:var(--site-space-3)}
.sb-guest-card__row + .sb-guest-card__row{border-top:1px solid var(--site-line)}
.sb-guest-card__dot{flex:none;width:var(--site-space-3);height:var(--site-space-3);border-radius:var(--site-r-chip);background:var(--sb-tier)}
.sb-guest-card__level{flex:1 1 auto;min-width:0;font-size:var(--site-body-size);font-weight:600;letter-spacing:-.01em}
.sb-guest-card__level small{display:block;margin-top:calc(var(--site-space-1) * .5);font-size:var(--site-micro);font-weight:400;color:var(--site-muted)}
.sb-guest-card__row[data-here="on"] .sb-guest-card__level small{color:var(--site-ink)}
.sb-guest-card__pct{flex:none;font-size:var(--site-body-size);font-weight:600;font-variant-numeric:tabular-nums}
.sb-guest-card__coupon{
  display:flex;align-items:center;gap:var(--site-space-3);
  padding:calc(var(--site-space-3) + var(--site-space-1) * .5) var(--site-space-4);border-radius:var(--site-r-media);background:var(--site-surface);
}
.sb-guest-card__tag{flex:none;width:calc(var(--site-space-5) - var(--site-space-1) * .5);height:calc(var(--site-space-5) - var(--site-space-1) * .5);color:var(--site-ink)}
.sb-guest-card__coupon > span{flex:1 1 auto;min-width:0;display:grid}
.sb-guest-card__coupon b{font-size:var(--site-body-size);font-weight:600;letter-spacing:-.01em}
.sb-guest-card__coupon b + span{margin-top:calc(var(--site-space-1) * .5);font-size:var(--site-small);color:var(--site-muted);font-variant-numeric:tabular-nums;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

@media (min-width:900px){
  .sb-guest-hello{padding-block:var(--site-space-5)}
  .sb-guest-hello__inner:has(> .sb-guest-hello__last){display:grid;grid-template-columns:1fr auto}
  .sb-guest-hello__inner:has(> .sb-guest-hello__last) > .sb-guest-hello__top{grid-column:1}
  .sb-guest-hello__last{
    grid-column:2;border-top:0;border-left:1px solid var(--site-hairline);
    min-width:calc(var(--site-space-8) * 6);
  }
  .sb-guest-hello__body{grid-template-columns:1fr auto;align-items:center;gap:var(--site-space-6)}
  .sb-guest-hello__ways{grid-auto-flow:column;gap:var(--site-space-3);align-items:center}
}

/* --- hero --- */
/* hero — spec/blocks.md §3.2, markup from mockups/site-*-02-home-md.html.
   `__body` is always in the tree; in `cover` it dissolves so the copy sits directly on the
   inner grid, which is what makes one markup serve all three variants. */
/* ПОЛОСА ВО ВСЮ ШИРИНУ — осознанный и единственный способ отказаться от общих полей полосы
   (base.css): собственный `padding:0` на корне полосы, и так это пишет каждый, кому такое нужно.
   У `cover` кадр — это фон ПОЛОСЫ, он обязан доходить до края экрана, а поля возвращает `__inner`.
   У `split` и `plate` фотография стоит колонкой ВНУТРИ полосы — они полей не снимают и живут на
   общем ритме, поэтому своей пары `padding-*` у них больше нет.

   Пока ритм был расписан по каждому блоку отдельно, «во всю ширину» получалось само собой у того,
   кто просто не написал себе полей, и замысел было не отличить от пропуска. */
.sb-hero[data-variant="cover"]{padding:0}
.sb-hero{position:relative;overflow:hidden}
.sb-hero__media{position:absolute;inset:0}
.sb-hero__media::after{content:"";position:absolute;inset:0;background:var(--site-scrim);opacity:var(--sb-hero-overlay,.4)}
/* «ТЁМНЫЙ ГРАДИЕНТ БЕЗ ФОТО» (spec/blocks.md §3.2) — обложка заведения, у которого ещё нет ни
   одного снимка. Плоскость собрана из ТОКЕНОВ ПАКА, а не из своих цветов: на кремовой `parrilla`
   она тёплая, на `dark-promo` холодная, и ни один пак не приходится править ради неё.
   Скрим поверх не нужен и выключен — градиент уже темнеет к низу, туда, где стоит текст. */
.sb-hero__media--gradient{
  background:
    radial-gradient(120% 90% at 78% 2%,color-mix(in srgb,var(--site-accent) 32%,transparent) 0%,transparent 60%),
    linear-gradient(158deg,color-mix(in srgb,var(--site-surface) 70%,var(--site-accent)) 0%,var(--site-surface) 34%,var(--site-bg) 100%);
}
.sb-hero__media--gradient::after{display:none}
.sb-hero[data-variant="cover"] .sb-hero__media::after{background:var(--site-scrim),linear-gradient(90deg,color-mix(in srgb,var(--site-bg) 72%,transparent) 0%,color-mix(in srgb,var(--site-bg) 28%,transparent) 66%,transparent 100%),linear-gradient(180deg,color-mix(in srgb,var(--site-bg) 46%,transparent) 0%,transparent 50%)}
.sb-hero[data-variant="cover"] .sb-btn--secondary{background:color-mix(in srgb,var(--site-surface) 72%,transparent);border-color:var(--site-muted)}
/* `--sb-w-page-bleed` (base.css) — колонка страницы ПЛЮС поле, которое эта полоса вернула себе
   сама: содержимое обложки встаёт на ту же вертикаль, что и содержимое соседних полос. */
.sb-hero__inner{
  position:relative;max-width:var(--sb-w-page-bleed);margin-inline:auto;
  padding:var(--site-space-8) var(--site-gutter) var(--site-space-6);
  display:grid;gap:var(--site-space-4);align-content:end;
}
/* ОБЛОЖКА СУЩЕСТВУЕТ, ЧТОБЫ ЕЁ УВИДЕЛИ ЦЕЛИКОМ — вместе с кнопкой, ради которой она стоит первой.
   Высота по-прежнему берётся из шкалы (findings-w1 §9: `hero cover` меряется min-height, а не
   aspect-ratio), но НЕ БОЛЬШЕ окна: `min()` оставляет число шкалы там, где оно помещается, и
   подрезает его там, где нет.

   Владелец 02.09, ноутбук с окном 800 и 741 точек по высоте: обложка LUMA занимала 832 — больше
   окна вместе с шапкой. Кикер и заголовок стояли у нижней кромки, лид обрывался на середине строки,
   кнопки не было видно вовсе: первый экран не сообщал, куда нажать. Содержимое прижато книзу
   (`align-content:end`), поэтому лишняя высота выталкивает за сгиб именно то, ради чего полосу и
   открывают.

   `svh`, а не `vh`: на телефоне `vh` считается по РАЗВЁРНУТОМУ окну, и обложка оказывается выше
   видимой области ровно на высоту адресной строки — тот же дефект, только мобильный. `svh` — это
   гарантированно видимая высота. Вычитается `--site-nav-h`: шапка липкая и стоит НАД обложкой,
   её высота — часть того же первого экрана.

   ДВЕ СТРОКИ НА ОДНУ ВЫСОТУ — не дубль, а запасной путь, и порядок в нём значащий. Браузер, не
   знающий `svh`, читает всё значение как невалидное и отбрасывает ВСЮ строку; будь она одна,
   обложка осталась бы вообще без min-height и схлопнулась бы в высоту текста. Первой строкой стоит
   число шкалы — то самое поведение, что было до этого узла, — и старый браузер остаётся на нём. */
.sb-hero__inner[data-height="s"]{
  padding-top:var(--site-space-7);
  min-height:calc(var(--site-space-8) * 4);
  min-height:min(calc(var(--site-space-8) * 4),calc(100svh - var(--site-nav-h)));
}
.sb-hero__inner[data-height="m"]{
  min-height:calc(var(--site-space-8) * 7);
  min-height:min(calc(var(--site-space-8) * 7),calc(100svh - var(--site-nav-h)));
}
.sb-hero__inner[data-height="l"]{
  min-height:calc(var(--site-space-8) * 9);
  min-height:min(calc(var(--site-space-8) * 9),calc(100svh - var(--site-nav-h)));
}
.sb-hero__title{max-width:var(--site-w-read)}
.sb-hero__sub{color:var(--site-muted);max-width:var(--site-w-read);font-size:var(--site-h4);line-height:1.45;font-weight:400}
.sb-hero__cta{display:grid;gap:var(--site-space-2);margin-top:var(--site-space-2)}
.sb-hero__meta{
  display:flex;flex-wrap:wrap;align-items:center;gap:var(--site-space-2) var(--site-space-3);
  font-size:var(--site-small);color:var(--site-muted);
}
.sb-hero__search{
  display:flex;align-items:center;gap:var(--site-space-3);
  height:var(--site-input-h);padding-inline:var(--site-space-4);
  border-radius:var(--site-r-input);border:1px solid var(--site-line);
  background:var(--site-surface);color:var(--site-faint);font-size:var(--site-body-size);
  max-width:var(--site-w-read);
}
.sb-hero__search svg{width:1.15em;height:1.15em;color:var(--site-muted);flex:none}
/* `split` и `plate` полей не снимали — их несёт полоса, а `__inner` остаётся обычной колонкой. */
.sb-hero[data-variant="split"] .sb-hero__inner,.sb-hero[data-variant="plate"] .sb-hero__inner{padding:0;max-width:var(--site-w-page);min-height:0;gap:var(--site-space-5)}
.sb-hero[data-variant="split"] .sb-hero__media{position:relative;inset:auto;border-radius:var(--site-r-media);overflow:hidden;aspect-ratio:var(--site-ratio-card)}
.sb-hero[data-variant="split"] .sb-hero__media::after{display:none}
.sb-hero[data-variant="split"] .sb-hero__body,.sb-hero[data-variant="plate"] .sb-hero__body{display:grid;gap:var(--site-space-4);align-content:center}
.sb-hero__facts{
  display:grid;gap:var(--site-space-4);margin-top:var(--site-space-2);
  padding-top:var(--site-space-5);border-top:1px solid var(--site-line);
}
.sb-hero__fact dt{font-size:var(--site-micro);letter-spacing:var(--site-micro-ls);text-transform:uppercase;color:var(--site-faint)}
.sb-hero__fact dd{font-size:var(--site-h4);font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);letter-spacing:var(--site-display-ls);margin-top:var(--site-space-1)}

@media (min-width:900px){
  .sb-hero__inner{padding-inline:var(--site-gutter-d);padding-bottom:var(--site-space-8)}
  .sb-hero__inner[data-height="s"]{
    min-height:calc(var(--site-space-8) * 6);
    min-height:min(calc(var(--site-space-8) * 6),calc(100svh - var(--site-nav-h)));
  }
  .sb-hero:is([data-variant="split"],[data-variant="plate"]) .sb-hero__inner{min-height:0}
  .sb-hero__inner[data-height="m"]{
    min-height:calc(var(--site-space-8) * 10);
    min-height:min(calc(var(--site-space-8) * 10),calc(100svh - var(--site-nav-h)));
  }
  .sb-hero__inner[data-height="l"]{
    min-height:calc(var(--site-space-8) * 13);
    min-height:min(calc(var(--site-space-8) * 13),calc(100svh - var(--site-nav-h)));
  }
  .sb-hero__cta{display:flex;gap:var(--site-space-3)}
  .sb-hero__cta .sb-btn{min-width:calc(var(--site-space-8) * 3)}
  .sb-hero__facts{grid-template-columns:repeat(3,1fr);gap:var(--site-space-6)}
  .sb-hero[data-variant="split"] .sb-hero__inner,
  .sb-hero[data-variant="plate"] .sb-hero__inner{grid-template-columns:1.05fr .95fr;align-items:center;gap:var(--site-space-8);}
  .sb-hero[data-variant="split"] .sb-hero__media{order:2;aspect-ratio:var(--site-ratio-card)}
  .sb-hero[data-variant="split"] .sb-hero__body{order:1;display:grid;gap:var(--site-space-4)}
  .sb-hero[data-variant="plate"] .sb-hero__inner:not(:has(.sb-hero__media)){grid-template-columns:1fr;max-width:var(--site-w-read)}
}

/* `align: center` — the one geometry the mockups showed only on the culinary boards. */
.sb-hero__inner[data-align="center"]{justify-items:center;text-align:center}
.sb-hero[data-variant="cover"] .sb-hero__body{display:contents}
/* Живая строка «открыто до 01:00» — пилюля, а не голый текст. Обложка стоит на фотографии, и
   единственная строка первого экрана, ради которой гость и открыл сайт в девять вечера, обязана
   читаться поверх любого кадра. Цвета берутся у СХЕМЫ полосы (`--site-ink`/`--site-surface`),
   поэтому одна и та же пилюля работает и на тёмной обложке, и на светлой — второго правила под
   вторую схему не нужно. `justify-self:start` — потому что `__body` это грид: без него пилюля
   растянулась бы во всю колонку. */
.sb-hero__status{
  justify-self:start;
  padding:var(--site-space-2) var(--site-space-4);
  border-radius:var(--site-r-chip);
  background:color-mix(in srgb,var(--site-surface) 20%,transparent);
  border:1px solid color-mix(in srgb,var(--site-ink) 24%,transparent);
}
.sb-hero__status .sb-status{color:var(--site-ink);font-weight:600;font-size:var(--site-body-size)}

/* ── ВАРИАНТ `strip` — УЗКАЯ ПОЛОСА-ВИЗИТКА (узел site-home-hub) ─────────────────────────────────
   Стили перенесены из макета выбранного варианта (site-parrilla-02-home-hub-b-md.html, секция
   `hero` с `data-variant="strip"`) значение в значение.

   Свой воздух полосе назначен намеренно: визитка на главной-разводящей стоит между шапкой и
   карточками намерений, и воздух обычной полосы вытолкнул бы карточки за первый экран телефона.
   Общий ритм при этом не переписывается — здесь ДРУГОЙ воздух, как у `today`. */
.sb-hero[data-variant="strip"]{padding-block:var(--site-space-4);background:var(--site-bg)}
.sb-hero[data-variant="strip"] .sb-hero__inner{
  max-width:var(--site-w-page);margin-inline:auto;padding:0;min-height:0;
  display:flex;align-items:center;gap:var(--site-space-3);
}
/* `position:relative` ОБЯЗАТЕЛЕН: у `.sb-hero__media` есть `::after` со скримом, и при `static`
   он раскрылся бы по всей полосе — ближайшим позиционированным предком оказалась бы сама
   `.sb-hero` (blocks-proposal-home-hub.md §6 п.4). Скрим полосе не нужен и погашен. */
.sb-hero[data-variant="strip"] .sb-hero__media{
  flex:none;position:relative;inset:auto;
  width:calc(var(--site-space-8) - var(--site-space-2));
  height:calc(var(--site-space-8) - var(--site-space-2));
  border-radius:var(--site-r-media);overflow:hidden;
}
.sb-hero[data-variant="strip"] .sb-hero__media::after{display:none}
.sb-hero[data-variant="strip"] .sb-hero__body{flex:1;min-width:0;display:grid;gap:var(--site-space-1)}
.sb-hero[data-variant="strip"] .sb-hero__title{
  font-size:var(--site-h3);max-width:none;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.sb-hero[data-variant="strip"] .sb-hero__meta{gap:var(--site-space-2);font-size:var(--site-small);margin:0}
.sb-hero[data-variant="strip"] .sb-hero__meta .sb-status{font-weight:600}

/* КИКЕР ОБЛОЖКИ — ЧЕРНИЛА, А НЕ АКЦЕНТ. Красный `--site-accent` пака `parrilla` поверх
   затемнённого снимка даёт около 3,2:1 на кегле кикера — ниже нормы даже для крупного текста
   (blocks-proposal-home-hub.md §6 п.7). На `--site-ink` схемы обложки та же строка даёт более 8:1.
   Красный остаётся кнопкам и значкам: акцент поверх фотографии — заливка, но не текст. */
.sb-hero[data-variant="cover"] .sb-kicker{color:var(--site-ink)}

@media (min-width:900px){
  .sb-hero[data-variant="strip"] .sb-hero__inner{padding:0;min-height:0}
  .sb-hero[data-variant="strip"] .sb-hero__title{font-size:var(--site-h3)}
}

/* ── VARIANT `card` — THE TOP OF THE «DÍA» HOME (node dia-home-look) ────────────────────────────
   A photo card with a rounded bottom, a round mark straddling its edge, the name and the
   ink table pill in one row, «open · until · address» under them (comanda-dia/screens/dia-home.html,
   `.hero--card`). Values are the mockup's, expressed on the pack's scale: photo = 64×3.75,
   mark = 64−4, pill = 32+4. The band sheds the section air: the photo runs to the screen edges. */
.sb-hero[data-variant="card"]{padding:0 0 var(--site-space-2);background:var(--site-bg);overflow:visible}
.sb-hero[data-variant="card"] .sb-hero__media{
  position:relative;inset:auto;height:calc(var(--site-space-8) * 3.75);
  border-radius:0 0 var(--site-r-card) var(--site-r-card);overflow:hidden;background:var(--site-surface-2);
}
.sb-hero[data-variant="card"] .sb-hero__media > .sb-media{position:absolute;inset:0}
.sb-hero[data-variant="card"] .sb-hero__media::after{z-index:1;pointer-events:none}
/* The language button lives on the photo only where the tab bar replaced the header (a phone page
   with tabs); anywhere else the header carries the switch and a second one would be noise. */
.sb-hero__langs{display:none}
[data-tabbar="on"] .sb-hero__langs{
  position:absolute;z-index:2;top:var(--site-space-3);right:var(--site-gutter);
  display:flex;gap:var(--site-space-2);
}
.sb-hero__lang{
  position:relative;display:grid;place-items:center;
  min-width:calc(var(--site-space-7) - var(--site-space-1));height:var(--site-space-6);
  padding-inline:var(--site-space-3);border-radius:var(--site-space-2);
  /* An ink glass rather than the mockup's white one (18 %): white type on white glass over a light
     photo measured under 3:1, and the button is text. Ink at 45 % keeps it ≥ 7:1 over any photo
     under the top shade, and still reads as glass on the picture. */
  background:color-mix(in srgb,var(--site-ink) 45%,transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--site-surface) 22%,transparent);
  backdrop-filter:blur(var(--site-space-3));-webkit-backdrop-filter:blur(var(--site-space-3));
  color:var(--site-surface);font-size:var(--site-small);font-weight:600;
}
/* A small pill for the eye, a full touch target for the finger. */
.sb-hero__lang::before{content:"";position:absolute;inset:calc(var(--site-space-2) * -.75)}
.sb-hero[data-variant="card"] .sb-hero__inner{
  display:block;position:relative;z-index:1;min-height:0;
  max-width:var(--sb-w-page-bleed);padding:0 var(--site-gutter);
}
.sb-hero__mark{
  display:grid;place-items:center;overflow:hidden;
  width:calc(var(--site-space-8) - var(--site-space-1));height:calc(var(--site-space-8) - var(--site-space-1));
  margin-top:calc((var(--site-space-8) - var(--site-space-1)) / -2);
  border-radius:var(--site-r-chip);background:var(--site-surface);
  box-shadow:0 0 0 calc(var(--site-space-1) * .75) var(--site-bg);
  color:var(--site-ink);font-size:var(--site-h3);font-weight:700;letter-spacing:.04em;
}
.sb-hero__mark img{width:100%;height:100%;object-fit:cover}
.sb-hero__row{display:flex;align-items:center;justify-content:space-between;gap:var(--site-space-3);margin-top:var(--site-space-3)}
.sb-hero[data-variant="card"] .sb-hero__title{flex:1;min-width:0;max-width:none;font-size:var(--site-h1);overflow-wrap:anywhere}
.sb-hero__table{
  flex:none;display:inline-flex;align-items:center;
  height:calc(var(--site-space-6) + var(--site-space-1));padding-inline:var(--site-space-4);
  border-radius:var(--site-r-chip);background:var(--site-btn-accent);color:var(--site-btn-on-accent);
  font-size:var(--site-body-size);font-weight:600;letter-spacing:-.01em;white-space:nowrap;
}
.sb-hero__table[data-state="off"]{display:none}
.sb-hero[data-variant="card"] .sb-hero__meta{
  display:flex;flex-wrap:wrap;align-items:center;gap:0 var(--site-space-1);
  margin-top:var(--site-space-2);font-size:var(--site-small);color:var(--site-muted);
}
.sb-hero[data-variant="card"] .sb-hero__meta .sb-status{font-size:inherit;font-weight:500;color:var(--site-ink)}

@media (min-width:900px){
  .sb-hero[data-variant="card"] .sb-hero__media{height:calc(var(--site-space-8) * 5)}
  .sb-hero[data-variant="card"] .sb-hero__inner{padding-inline:var(--site-gutter-d)}
  [data-tabbar="on"] .sb-hero__langs{display:none}
}

/* ── THE GLASS PLATE (`info_plate`, node site-blocks-legacy-look) ───────────────────────────────
   The first screen of the legacy venue page: the address, «open now» and the buttons on one
   translucent, blurred panel over the cover photo. Its colours are the band's SCHEME, not white
   glass: the plate is the scheme's own background at 55 % under a blur, the type is the scheme's
   ink — so the pair keeps its contrast on every photograph and on each of the four schemes (white
   at 16 % under white type, the legacy recipe, drops below 3:1 on a light frame).
   `width:fit-content` instead of `justify-self`: the plate follows the cover's own alignment
   (`data-align`), standing at the start of a left cover and in the middle of a centred one. */
.sb-hero__plate{
  display:grid;gap:var(--site-space-3);width:fit-content;max-width:min(100%,var(--site-w-read));
  margin-top:var(--site-space-2);padding:var(--site-space-4);
  border-radius:var(--site-r-card);color:var(--site-ink);
  background:color-mix(in srgb,var(--site-bg) 55%,transparent);
  border:1px solid color-mix(in srgb,var(--site-ink) 16%,transparent);
  backdrop-filter:blur(var(--site-space-3)) saturate(1.2);-webkit-backdrop-filter:blur(var(--site-space-3)) saturate(1.2);
}
.sb-hero__plate .sb-hero__meta{gap:var(--site-space-2) var(--site-space-4);color:var(--site-ink);font-size:var(--site-small)}
.sb-hero__plate .sb-status{color:var(--site-ink);font-weight:600;font-size:inherit}
.sb-hero__addr{display:inline-flex;align-items:flex-start;gap:var(--site-space-2)}
.sb-hero__addr svg{flex:none;width:1.15em;height:1.15em;margin-top:.1em}
.sb-hero__plate .sb-hero__cta{margin-top:0}

/* `height: full` (node site-blocks-legacy-look) — the option was selectable and had no rule, so the
   cover collapsed to the height of its text. Now it is the whole visible window under the sticky
   header: `svh`, not `vh`, so a phone's address bar never pushes the buttons under the fold, minus
   `--site-nav-h` because the header stands over the same first screen. `max()` keeps a floor for a
   phone held sideways (a 390-high window still gets a cover, not a strip). The first line is the
   fallback for a browser without `svh`, which drops the whole second line. Written for the cover
   and the split; the split's own `min-height:0` rules are outweighed by the variant selectors here,
   which come later in the sheet. */
.sb-hero__inner[data-height="full"],
.sb-hero[data-variant="split"] .sb-hero__inner[data-height="full"]{
  min-height:calc(var(--site-space-8) * 7);
  min-height:max(calc(var(--site-space-8) * 5),calc(100svh - var(--site-nav-h)));
}
.sb-hero[data-variant="split"] .sb-hero__inner[data-height="full"]{align-content:center}
@media (min-width:900px){
  .sb-hero__inner[data-height="full"],
  .sb-hero:is([data-variant="split"]) .sb-hero__inner[data-height="full"]{
    min-height:calc(var(--site-space-8) * 10);
    min-height:max(calc(var(--site-space-8) * 6),calc(100svh - var(--site-nav-h)));
  }
}

/* ── THE PHOTO DISSOLVES INTO THE BAND (`media_fade`, node site-blocks-ox-variants) ────────────────
   LUMA's OX asked for «a big picture that melts into a plain ground the text stands on», on a phone
   and on a desktop. The ground is the band's own `--site-bg` (the section paints it), so the fade is
   a MASK on the frame, not a second colour: whatever the scheme, the photo melts into exactly the
   colour around it, and the scrim melts with it.
   Phone: the frame stays the background layer but covers only the top of the band, 4:5 of the
   width (capped so the copy still shows on the first screen), melting downwards; the copy starts
   where the photo has almost melted and stands on the plain ground — never over the photo itself.
   The same height is written twice: frame and copy are siblings, and a custom property set on one
   is not seen by the other.
   Desktop: the frame is the right of the band and melts leftwards under the copy. */
.sb-hero__media[data-fade]{
  bottom:auto;height:calc(100vw * 1.25);max-height:calc(100svh - var(--site-nav-h) - var(--site-space-8));
  -webkit-mask-image:linear-gradient(180deg,var(--site-ink) 45%,transparent 100%);mask-image:linear-gradient(180deg,var(--site-ink) 45%,transparent 100%);
}
.sb-hero__media[data-fade] > .sb-media{position:absolute;inset:0}
.sb-hero[data-variant="cover"] .sb-hero__media[data-fade]::after{background:var(--site-scrim)}
.sb-hero__media[data-fade] + .sb-hero__inner{
  padding-top:calc(min(calc(100vw * 1.25),calc(100svh - var(--site-nav-h) - var(--site-space-8))) - var(--site-space-8));
}
@media (min-width:900px){
  .sb-hero__media[data-fade]{
    inset:0 0 0 auto;width:68%;height:auto;max-height:none;
    -webkit-mask-image:linear-gradient(90deg,transparent 0%,var(--site-ink) 45%);mask-image:linear-gradient(90deg,transparent 0%,var(--site-ink) 45%);
  }
  .sb-hero__media[data-fade] + .sb-hero__inner{padding-top:var(--site-space-8)}
  .sb-hero__media[data-fade] + .sb-hero__inner[data-height="s"]{padding-top:var(--site-space-7)}
}

/* --- hours --- */
.sb-hours__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-5)}
.sb-hours__table{display:grid;border-top:1px solid var(--site-line)}
.sb-hours__row{
  display:flex;align-items:center;gap:var(--site-space-4);
  padding:var(--site-space-3) var(--site-space-3);border-bottom:1px solid var(--site-hairline);
  font-size:var(--site-body-size);min-height:var(--site-btn-h);
}
.sb-hours__row span:first-child{flex:1;color:var(--site-muted)}
.sb-hours__row b{font-family:var(--site-mono);font-variant-numeric:tabular-nums;font-weight:600}
.sb-hours__row[data-state="today"]{background:var(--site-accent-soft);border-radius:var(--site-r-input)}
.sb-hours__row[data-state="today"] span:first-child{color:var(--site-ink);font-weight:600}
.sb-hours__note{font-size:var(--site-small);color:var(--site-muted)}

@media (min-width:900px){
  .sb-hours__inner{grid-template-columns:1fr 1fr;gap:var(--site-space-8);align-items:start}
}

/* The status line and the `status-card` variant, added with the view: the mockups printed the
   status inside the section head, and `status-card` is the same tree with that one line blown up
   and the week dropped to small type. */
.sb-hours__status{display:flex;align-items:center}
.sb-hours[data-variant="status-card"] .sb-hours__status .sb-status{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-size:var(--site-h3);
  letter-spacing:var(--site-display-ls);color:var(--site-ink);
}
.sb-hours[data-variant="status-card"] .sb-hours__row{font-size:var(--site-small)}

/* --- legacy-section --- */
/* legacy-section — visible to the author only (mode='editor'); the guest render is empty.

   Ритм полосы — общий (base.css); своей пары полей у блока больше нет.

   Имена переменных исправлены тем же узлом: блок был написан по НЕСУЩЕСТВУЮЩИМ токенам
   (`--site-width-text`, `--site-border`, `--site-radius-m`, `--site-text`, `--site-text-muted`,
   `--site-font-*`) — ни одного из них нет в `SITE_PACK_TOKENS`, поэтому каждое такое объявление
   браузер отбрасывал и плашка приезжала автору без рамки, без краски и системным шрифтом.
   Здесь стоят те имена, которые пак действительно определяет. */

.sb-legacy-section__plate {
  max-width: var(--site-w-read);
  margin: 0 auto;
  padding: var(--site-space-5);
  border: 1px dashed var(--site-line);
  border-radius: var(--site-r-card);
  background: var(--site-surface);
  color: var(--site-muted);
  text-align: center;
}

.sb-legacy-section__kind {
  margin: 0;
  font-family: var(--site-body);
  font-size: var(--site-micro);
  font-weight: 600;
  letter-spacing: var(--site-micro-ls);
  text-transform: uppercase;
  color: var(--site-muted);
}

.sb-legacy-section__title {
  margin: var(--site-space-2) 0 0;
  font-family: var(--site-display);
  font-weight: var(--site-display-weight);
  font-size: var(--site-h3);
  color: var(--site-ink);
}

.sb-legacy-section__note {
  margin: var(--site-space-3) 0 0;
  font-size: var(--site-small);
}

/* --- loyalty --- */
/* «Клуб и баллы» (node site-loyalty-block). Only the pack's tokens: the form takes the page's
   surface, line, radius and type, so a club page on editorial and one on dark-promo are the same
   form in two different houses. */
.sb-loyalty__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-5)}
.sb-loyalty__head{display:grid;gap:var(--site-space-3);justify-items:start;max-width:var(--site-w-read)}

.sb-loyalty__facts{display:grid;gap:var(--site-space-3);justify-items:start}
.sb-loyalty__rate{display:flex;align-items:baseline;gap:var(--site-space-2);margin:0}
.sb-loyalty__rate b{
  font-family:var(--site-display);font-weight:var(--site-display-weight);font-size:var(--site-h2);
  line-height:var(--site-display-lh);letter-spacing:var(--site-display-ls);color:var(--site-accent);
}
.sb-loyalty__rate span{font-size:var(--site-small);color:var(--site-muted)}
.sb-loyalty__tiers{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:var(--site-space-2)}
.sb-loyalty__tiers li{
  display:inline-flex;align-items:center;gap:var(--site-space-2);
  padding:var(--site-space-2) var(--site-space-3);border:1px solid var(--site-line);
  border-radius:var(--site-r-chip);background:var(--site-surface);color:var(--site-ink);font-size:var(--site-small);
}
.sb-loyalty__tiers i{width:.7em;height:.7em;border-radius:50%;background:var(--sb-tier);flex:none}
.sb-loyalty__tiers span{color:var(--site-muted)}
.sb-loyalty__tiers li[data-entry="on"]{border-color:var(--sb-tier)}

.sb-loyalty__terms{display:grid;gap:var(--site-space-4);justify-items:start;max-width:var(--site-w-read)}

.sb-loyalty__panel{display:grid;gap:var(--site-space-3);width:100%;max-width:30rem}
.sb-loyalty__form,.sb-loyalty__card{
  display:grid;gap:var(--site-space-3);padding:var(--site-space-5);
  border:1px solid var(--site-line);border-radius:var(--site-r-card);
  background:var(--site-surface);color:var(--site-ink);
}
.sb-loyalty__field{display:grid;gap:var(--site-space-1);font-size:var(--site-small);color:var(--site-muted)}
.sb-loyalty__field > input,.sb-loyalty__phone input{
  font:inherit;font-size:var(--site-body-size);color:var(--site-ink);
  min-height:var(--site-btn-h);padding:0 var(--site-space-3);
  border:1px solid var(--site-line);border-radius:var(--site-r-btn);background:var(--site-bg);
}
.sb-loyalty__field > input:focus-visible,.sb-loyalty__phone input:focus-visible{outline:.125rem solid var(--site-accent);outline-offset:1px}
.sb-loyalty__check{display:flex;gap:var(--site-space-2);align-items:flex-start;font-size:var(--site-small);color:var(--site-muted)}
.sb-loyalty__check input{margin-top:.2em;accent-color:var(--site-accent);flex:none}
.sb-loyalty__check a{color:inherit;text-decoration:underline}
.sb-loyalty__check p{margin:0}
.sb-loyalty__choice{border:0;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:var(--site-space-2) var(--site-space-4)}
.sb-loyalty__choice legend{padding:0;margin-bottom:var(--site-space-1);width:100%}
.sb-loyalty__legal{font-size:var(--site-small);color:var(--site-muted)}
.sb-loyalty__legal p{margin:0}
.sb-loyalty__legal a{color:inherit;text-decoration:underline}
/* Clipped away, not display:none — a bot that skips hidden inputs still sees this one. */
.sb-loyalty__trap{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.sb-loyalty__error{margin:0;font-size:var(--site-small);color:var(--site-danger)}
.sb-loyalty__form button[disabled]{opacity:.6;cursor:default}
.sb-loyalty__login{margin:0;font-size:var(--site-small)}
.sb-loyalty__login a{color:var(--site-ink)}

.sb-loyalty__card > b{
  font-family:var(--site-display);font-weight:var(--site-display-weight);font-size:var(--site-h3);
  line-height:var(--site-display-lh);letter-spacing:var(--site-display-ls);text-transform:var(--site-display-case);
}
.sb-loyalty__card p{margin:0}
.sb-loyalty__balance{display:flex;align-items:baseline;gap:var(--site-space-2)}
.sb-loyalty__balance b{font-family:var(--site-display);font-size:var(--site-h2);line-height:1}
.sb-loyalty__balance span,.sb-loyalty__tier,.sb-loyalty__number{font-size:var(--site-small);color:var(--site-muted)}
.sb-loyalty__wallet{display:grid;gap:var(--site-space-2)}

/* luma-loyalty-signup: «how it works», the tiers as cards, the country code at the phone and the
   confirmation of a member's number. Tokens only, so each brand's site draws them in its own type. */
.sb-loyalty__steps{margin:0;padding-inline-start:1.4em;list-style:decimal;display:grid;gap:var(--site-space-1);color:var(--site-ink)}
.sb-loyalty__steps li::marker{color:var(--site-accent);font-weight:600}
.sb-loyalty__levels{list-style:none;margin:0;padding:0;display:grid;gap:var(--site-space-3);width:100%}
.sb-loyalty__levels li{
  display:grid;gap:var(--site-space-1);padding:var(--site-space-4);
  border:1px solid var(--site-line);border-inline-start:.25rem solid var(--sb-tier);
  border-radius:var(--site-r-card);background:var(--site-surface);color:var(--site-ink);
}
.sb-loyalty__levels p{margin:0}
.sb-loyalty__level-head{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--site-space-1) var(--site-space-3)}
.sb-loyalty__level-head b{
  font-family:var(--site-display);font-weight:var(--site-display-weight);font-size:var(--site-h2);
  line-height:var(--site-display-lh);letter-spacing:var(--site-display-ls);color:var(--site-accent);
}
.sb-loyalty__level-head span{
  font-family:var(--site-display);font-weight:var(--site-display-weight);text-transform:var(--site-display-case);
  letter-spacing:var(--site-display-ls);font-size:var(--site-h3);
}
.sb-loyalty__level-how{font-size:var(--site-small);color:var(--site-muted)}
.sb-loyalty__phone{display:flex;gap:var(--site-space-2)}
.sb-loyalty__phone select{
  font:inherit;font-size:var(--site-body-size);color:var(--site-ink);flex:none;max-width:7.5rem;
  min-height:var(--site-btn-h);padding:0 var(--site-space-2);
  border:1px solid var(--site-line);border-radius:var(--site-r-btn);background:var(--site-bg);
}
.sb-loyalty__phone input{flex:1;min-width:0}
.sb-loyalty__phone select:focus-visible{outline:.125rem solid var(--site-accent);outline-offset:1px}
.sb-loyalty__hint{font-size:var(--site-small);color:var(--site-muted)}
.sb-loyalty__otp{display:grid;gap:var(--site-space-3)}
/* signin-desktop-qr: the messenger link's QR, from the block's one breakpoint up (a phone never sees it); the
   code's light ground and quiet zone are inside its svg. */
.sb-loyalty__qr{display:none}
@media (min-width:900px){
  .sb-loyalty__qr{display:flex;flex-direction:column;align-items:center;gap:var(--site-space-2)}
}
.sb-loyalty__qr svg{border-radius:var(--site-r-card)}
.sb-loyalty__link{
  font:inherit;font-size:var(--site-small);color:var(--site-ink);background:none;border:0;padding:0;
  text-decoration:underline;cursor:pointer;justify-self:start;
}

@media (min-width:900px){
  .sb-loyalty[data-variant="join"] .sb-loyalty__inner{
    grid-template-columns:minmax(0,1fr) minmax(0,30rem);align-items:start;column-gap:var(--site-space-8);
  }
}

/* --- media --- */
.sb-media-block__inner{max-width:var(--site-w-page);margin-inline:auto}
.sb-media-block__inner[data-width="read"]{max-width:var(--site-w-read)}
.sb-media-block__figure{position:relative}
.sb-media-block__figure .sb-media{aspect-ratio:var(--site-ratio-card)}
.sb-media-block__inner[data-ratio="hero"] .sb-media{aspect-ratio:var(--site-ratio-hero)}
.sb-media-block__inner[data-ratio="tile"] .sb-media{aspect-ratio:var(--site-ratio-tile)}
.sb-media-block__inner[data-ratio="free"] .sb-media{aspect-ratio:auto}
.sb-media-block__inner[data-ratio="free"] .sb-media img{height:auto}
.sb-media-block__cap{margin-top:var(--site-space-2);font-size:var(--site-small);color:var(--site-faint)}
.sb-media-block__play{position:absolute;inset:0;display:grid;place-items:center;z-index:2}
.sb-media-block__play i{
  display:grid;place-items:center;
  width:calc(var(--site-space-8) + var(--site-space-4));height:calc(var(--site-space-8) + var(--site-space-4));
  border-radius:var(--site-r-chip);border:1px solid var(--site-on-accent);color:var(--site-on-accent);
}
.sb-media-block__play svg{width:var(--site-h3);height:var(--site-h3)}

/* `full-bleed` — the frame runs to the edges of the page, so the gutter comes off the section and
   the caption gets it back (it is type, and type keeps its margin).

   Тот же приём отказа от полей полосы, что у `hero cover` и `site-header` (base.css), но ТОЛЬКО по
   горизонтали: кадр идёт до краёв окна, а вертикальный ритм полосы остаётся общим — эта полоса
   стоит в потоке страницы, а не открывает её. Одного объявления хватает на обе ширины: селектор
   варианта сильнее общего правила, и десктопная копия, которая тут была, снята как мёртвая. */
.sb-media-block[data-variant="full-bleed"]{padding-inline:0}
.sb-media-block[data-variant="full-bleed"] .sb-media-block__inner{max-width:none}
.sb-media-block[data-variant="full-bleed"] .sb-media-block__cap{padding-inline:var(--site-gutter)}

@media (min-width:900px){
  .sb-media-block[data-variant="full-bleed"] .sb-media-block__cap{padding-inline:var(--site-gutter-d)}
}

/* --- menu-catalog --- */
/* Каталог кончается корзиной-панелью, приклеенной к низу окна, поэтому НИЖНЕГО воздуха у полосы
   нет: он ушёл бы под панель. Всё остальное — общий ритм из base.css. */
.sb-menu-catalog{padding-bottom:0}

/* THE RAIL'S HEIGHT, SAID ONCE. The category rail is a row of tap chips (`.sb-chip--tap`, min-height
   `--site-btn-h`) inside its own block padding and a 1px bottom rule. A jumped-to category lands
   right under header + rail (`scroll-margin-top` below), and the island's scroll-spy reads that same
   computed margin as its activation line — so the header token, the rail and the spy share one
   source and none of them carries a measured pixel. */
.sb-menu-catalog{--sb-catalog-rail-h:calc(var(--site-btn-h) + var(--site-space-3) * 2 + 1px)}

/* `width:100%` ЗДЕСЬ ОБЯЗАТЕЛЕН, а не «то же самое, что max-width». Колонка каталога — не блочный
   бокс, как у соседних полос: `:has(> __live)` внизу файла делает саму полосу flex-колонкой (ради
   `order:-1` у поиска), и `__inner` становится flex-элементом. У flex-элемента с автополями по
   горизонтали (`margin-inline:auto`) stretch ОТКЛЮЧЁН — ширина считается как fit-content, то есть
   от СОДЕРЖИМОГО, с полом по min-content. Полом оказывалась лента чипов ниже, и колонка выходила
   422.5 точки в экране 390: строки блюд разъезжались, круглая «+» вставала на x=395 — целиком за
   кромкой, страница ехала вбок (scrollWidth 459 при clientWidth 390, и те же 459 на 360 и 414 —
   ширина шла от содержимого, а не от экрана). На десктопе та же арифметика молча сужала колонку
   меню до 857 точек при 1180 у собственного поиска над ней.
   Явная ширина возвращает колонке ширину полосы: содержимое больше не может её раздуть. Ровно это
   правило носит общий `.site-block__inner` в base.css — здесь оно повторено потому, что имя класса
   у каталога своё. Тест e2e/tests/site-menu-mobile-overflow.spec.ts держит геометрию. */
.sb-menu-catalog__inner{max-width:var(--site-w-page);width:100%;margin-inline:auto}

/* Лента чипов дотягивается до кромок экрана — отрицательными полями она съедает поле полосы и
   возвращает его себе паддингом, чтобы первый чип стоял по общей вертикали, а прокрутка уходила
   под кромку. Приём оплачен тем, что бокс ленты ШИРЕ родителя ровно на два поля; пока у родителя
   ширина задана явно (см. `__inner` выше), это ничего не двигает — лента упирается в кромку экрана
   и дальше листается внутри себя. Без явной ширины родителя лента становилась его min-content и
   растаскивала всю полосу.
   The rail sticks right under the site header: `--sb-header-stick` is the header's row while it is
   stuck and 0 when it is not (site-header/block.css), so that token is the rail's `top`. Nothing
   else in the block may stick above it — see `__live` below. */
.sb-menu-catalog__tabs{
  position:sticky;top:var(--sb-header-stick,var(--site-nav-h));z-index:20;
  display:flex;gap:var(--site-space-2);overflow-x:auto;scrollbar-width:none;
  margin-inline:calc(var(--site-gutter) * -1);padding:var(--site-space-3) var(--site-gutter);
  background:var(--site-bg);border-bottom:1px solid var(--site-line);
}
/* The rail scrolls inside itself, so its right end is a cut through a chip. A trailing fade pinned to
   the scrollport's right edge (`position:sticky;right:0` inside the flex scroller) turns the cut into
   «there is more»; at the end of the scroll it is just trailing room after the last chip, so the
   last chip is never faded. Sticky offsets count from inside the scroller's padding, so the
   negative gutter pins the fade to the rail's outer edge, over the padding a chip scrolls through. */
.sb-menu-catalog__tabs::after{
  content:"";flex:none;position:sticky;right:calc(var(--site-gutter) * -1);width:var(--site-space-7);
  background:linear-gradient(to right,transparent,var(--site-bg));pointer-events:none;
}
/* Telegram's iOS in-app browser lays the page out below its see-through top bar but lets scrolled
   content draw up under it, so the rail stuck at top:0 shows the page through above it. While the
   rail is stuck (`data-stuck`, set by the island only under this mark) its background is extended
   two `--site-space-7` steps up, under the bar. A shadow, not a `::before`: the rail scrolls sideways, so its own overflow
   clips any pseudo-element hung outside its box; an outer shadow is not clipped and leaves the
   bottom rule alone (offset minus one step + spread one step = a band of two steps above the rail's top edge). Kept
   short on purpose: a 100vh strip was never painted there — WebKit tiles a large composited layer and
   draws only its on-screen part — while a small layer is drawn whole. */
html[data-inapp="telegram"] .sb-menu-catalog__tabs[data-stuck]{box-shadow:0 calc(var(--site-space-7) * -1) 0 var(--site-space-7) var(--site-bg)}
/* The air between a category and whatever sits above it is split: the part a jumped-to heading keeps
   under the rail (`--site-space-4`) is the category's OWN top padding, the rest is margin. So the
   category's box starts exactly where it lands under the rail (`scroll-margin-top` below is header +
   rail, no air), and the first pixel row under the rail always belongs to the category the spy
   lights — there is no band where the next tab is lit while the previous category is still there.
   The heading sits where it always did: margin + padding add up to the old `--site-space-7`. */
.sb-menu-catalog__cat{margin-top:calc(var(--site-space-7) - var(--site-space-4));padding-top:var(--site-space-4)}
.sb-menu-catalog__cat>h3{display:flex;align-items:baseline;gap:var(--site-space-3);margin-bottom:var(--site-space-4);font-size:var(--site-h2)}
.sb-menu-catalog__cat>h3 small{font-family:var(--site-body);font-size:var(--site-small);font-weight:500;color:var(--site-faint);letter-spacing:0}
.sb-menu-catalog__grid{display:grid;gap:var(--site-gap)}
.sb-menu-catalog__list{border-top:1px solid var(--site-line)}
.sb-menu-catalog__list .sb-dish-card{border-bottom:1px solid var(--site-hairline)}
.sb-menu-catalog__end{padding-block:var(--site-space-7)}

@media (min-width:900px){
  /* On a desktop the column is centred in a wider window, so a bleed by the gutter would stop in mid
     air (the rail and its rule wider than the menu, the chips cut off beside it). The rail is the
     column: same width as the dishes and the search above it. */
  .sb-menu-catalog__tabs{margin-inline:0;padding-inline:0}
  .sb-menu-catalog__tabs::after{right:0}
  .sb-menu-catalog__grid{grid-template-columns:repeat(3,1fr)}
  .sb-menu-catalog__cat>h3{font-size:var(--site-h2)}
  .sb-menu-catalog__list{columns:2;column-gap:var(--site-space-8)}
  .sb-menu-catalog__list .sb-dish-card{break-inside:avoid}
}

/* Added with the view: an anchored category must not land under the sticky header + tab rail
   (spec/blocks.md, «Моб/деск»), and `columns_d` has to reach the two containers the variants use. */
.sb-menu-catalog__cat{scroll-margin-top:calc(var(--sb-header-stick,var(--site-nav-h)) + var(--sb-catalog-rail-h))}
@media (min-width:900px){
  .sb-menu-catalog__grid[data-columns="1"]{grid-template-columns:1fr}
  .sb-menu-catalog__grid[data-columns="2"]{grid-template-columns:repeat(2,1fr)}
  .sb-menu-catalog__list[data-columns="1"]{columns:1}
  .sb-menu-catalog__list[data-columns="3"]{columns:3}
}

/* ── Island states (site-islands-hydrate). Search, the sticky basket and the dish card are drawn by
   the storefront runtime with these classes, so the interactive menu carries no css of its own and
   the page still loads exactly one stylesheet. `data-live` is set by the island, so a page whose
   script never arrives is untouched by every rule below. ── */
.sb-menu-catalog:has(> .sb-menu-catalog__live){display:flex;flex-direction:column}
/* The search is NOT sticky. It used to stick at `top:0` above the rail (z 21 over its 20): under a
   sticky site header that parked the field behind the header, its bottom edge peeking out as a stray
   frame and its box clipping the top of the chips. One sticky strip under the header is the rail;
   the search sits above the menu and scrolls away with it. */
.sb-menu-catalog__live{
  order:-1;
  max-width:var(--site-w-page);width:100%;margin-inline:auto;
  padding-block:var(--site-space-3);background:var(--site-bg);
}
.sb-menu-catalog__q{
  width:100%;min-height:var(--site-input-h);padding-inline:var(--site-space-4);
  font:inherit;font-size:var(--site-body-size);color:var(--site-ink);
  background:var(--site-surface);border:1px solid var(--site-line);border-radius:var(--site-r-input);
}
.sb-menu-catalog__q::placeholder{color:var(--site-faint)}

/* ЛИПКАЯ КОРЗИНА САДИТСЯ НАД ТЕМ, ЧТО СТОИТ У НИЖНЕЙ КРОМКИ, А НЕ ПОВЕРХ. Сегодня это нижние
   вкладки телефона: страница с ними объявляет их высоту в `--sb-tabbar-h`
   (`site-tabbar/block.css`), и корзина читает её у себя. Нет вкладок — переменной нет, и `0`
   возвращает прежнее поведение. Знание живёт в переменной, а не в селекторе, поэтому ни один из
   двух листов не называет классов другого. */
.sb-menu-catalog__bar{
  position:fixed;left:0;right:0;bottom:var(--sb-tabbar-h,0);z-index:60;
  display:flex;align-items:center;gap:var(--site-space-4);
  padding:var(--site-space-3) var(--site-gutter);
  padding-bottom:calc(var(--site-space-3) + env(safe-area-inset-bottom,0px));
  background:var(--site-surface);border-top:1px solid var(--site-line);box-shadow:var(--site-shadow-pop);
}
.sb-menu-catalog__bar-of{display:flex;flex-direction:column;margin-right:auto;min-width:0}
.sb-menu-catalog__bar-of b{font-size:var(--site-small);font-weight:600}
.sb-menu-catalog__bar-of span{font-family:var(--site-mono);font-size:var(--site-body-size);color:var(--site-muted)}
.sb-menu-catalog__bar .sb-btn{flex:none}

/* THE ORDER BAR OF «DÍA» (node dia-home-look, brand-spec §E v16/v17). On a pack that wears Día the
   island draws the bar in another FORM — `data-form="dishes"`: an ink pill with the photos of what
   is coming, the wait and «View order», no sum. The strip above stays the placement — fixed, above
   the tab bar, the page's gutters — and turns transparent and click-through, so only the pill takes
   a tap. The pill is the pack's primary button pair, i.e. ink on Día; the photo ring is the pill's
   own colour, the «×2» and «+N» badges are the inverse.
   The air between the pill and whatever is under it is the strip's bottom PADDING, not a `calc` on
   `bottom`: on a desktop the tab bar sets `--sb-tabbar-h` to a unitless `0`, and a unitless zero
   plus a length inside `calc()` is invalid — the declaration would drop and the bar would fall into
   the page flow. */
.sb-menu-catalog__bar[data-form="dishes"]{
  bottom:var(--sb-tabbar-h,env(safe-area-inset-bottom,0px));
  padding:0 var(--site-gutter) var(--site-space-3);
  background:none;border:0;box-shadow:none;pointer-events:none;
}
.sb-menu-catalog__order{
  --sb-order-ink:var(--site-btn-accent,var(--site-accent));
  --sb-order-on:var(--site-btn-on-accent,var(--site-on-accent));
  --sb-order-pic:calc(var(--site-space-5) + var(--site-space-1));
  pointer-events:auto;
  display:flex;align-items:center;gap:calc(var(--site-space-2) + var(--site-space-1) / 2);
  width:100%;max-width:var(--site-w-mobile);margin-inline:auto;
  min-height:calc(var(--site-btn-h) + var(--site-space-2));
  padding-inline:calc(var(--site-space-4) + var(--site-space-1));
  border-radius:var(--site-r-chip);
  background:var(--sb-order-ink);color:var(--sb-order-on);box-shadow:var(--site-shadow-pop);
  font-size:var(--site-body-size);line-height:1.2;text-decoration:none;
}
.sb-menu-catalog__order:active{opacity:.88}
.sb-menu-catalog__order:focus-visible{outline:calc(var(--site-space-1) / 2) solid var(--site-ink);outline-offset:calc(var(--site-space-1) / 2)}
.sb-menu-catalog__pics{flex:none;display:flex;align-items:center}
.sb-menu-catalog__pic{
  position:relative;flex:none;display:grid;place-items:center;
  width:var(--sb-order-pic);height:var(--sb-order-pic);border-radius:50%;
  background:var(--site-surface-2);color:var(--site-ink);font-size:var(--site-micro);font-weight:600;
  box-shadow:0 0 0 calc(var(--site-space-1) / 2) var(--sb-order-ink);
}
/* Overlap, the newest (first) circle on top of the one it covers. */
.sb-menu-catalog__pic+.sb-menu-catalog__pic{margin-left:calc(var(--site-space-2) * -1)}
.sb-menu-catalog__pic:nth-child(1){z-index:4}
.sb-menu-catalog__pic:nth-child(2){z-index:3}
.sb-menu-catalog__pic:nth-child(3){z-index:2}
.sb-menu-catalog__pic img{width:100%;height:100%;object-fit:cover;border-radius:50%}
.sb-menu-catalog__qty{
  position:absolute;right:calc(var(--site-space-1) / -2);bottom:calc(var(--site-space-1) / -2);
  min-width:var(--site-space-4);padding-inline:calc(var(--site-space-1) * .75);
  border-radius:var(--site-r-chip);background:var(--sb-order-on);color:var(--sb-order-ink);
  font-size:calc(var(--site-micro) * .75);font-weight:600;
  line-height:calc(var(--site-space-3) + var(--site-space-1) / 2);text-align:center;font-variant-numeric:tabular-nums;
}
.sb-menu-catalog__more{background:var(--sb-order-on);color:var(--sb-order-ink);font-variant-numeric:tabular-nums}
.sb-menu-catalog__eta{
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:color-mix(in srgb,var(--sb-order-on) 82%,transparent);font-variant-numeric:tabular-nums;
}
.sb-menu-catalog__go{position:relative;flex:none;margin-left:auto;padding-left:var(--site-space-3);font-weight:600;white-space:nowrap}
.sb-menu-catalog__go::before{
  content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:1px;height:calc(var(--site-space-4) + var(--site-space-1) / 2);
  background:color-mix(in srgb,var(--sb-order-on) 36%,transparent);
}

/* THE SAME PILL WHILE THE ORDER IS OUT (node dia-menu-look, In-7): the basket empty and an order in
   the kitchen, the bar says where it is — the stage on a soft disc, «En la cocina» / «Lo llevan a la
   mesa» — and leads to its status (site/order-bar.tsx `KitchenBar`, `data-form="kitchen"`). */
.sb-menu-catalog__st{
  flex:none;display:grid;place-items:center;width:var(--sb-order-pic);height:var(--sb-order-pic);border-radius:50%;
  background:color-mix(in srgb,var(--sb-order-on) 16%,transparent);color:var(--sb-order-on);
}
.sb-menu-catalog__st svg{width:var(--site-space-4);height:var(--site-space-4)}
.sb-menu-catalog__order[data-form="kitchen"] .sb-menu-catalog__eta{flex:1 1 auto;font-weight:600;color:var(--sb-order-on)}
.sb-menu-catalog__t{margin-left:auto;color:color-mix(in srgb,var(--sb-order-on) 72%,transparent);font-variant-numeric:tabular-nums;white-space:nowrap}

.sb-menu-catalog__scrim{
  position:fixed;inset:0;z-index:70;display:flex;align-items:flex-end;justify-content:center;
  background:var(--site-scrim);
}
.sb-menu-catalog__sheet{
  position:relative;width:100%;max-width:var(--site-w-mobile);max-height:88vh;overflow-y:auto;
  padding:var(--site-space-6) var(--site-gutter) var(--site-space-5);
  background:var(--site-bg);color:var(--site-ink);
  border-radius:var(--site-r-card) var(--site-r-card) 0 0;
}
.sb-menu-catalog__x{
  position:absolute;top:var(--site-space-3);right:var(--site-space-3);
  width:var(--site-btn-h-sm);height:var(--site-btn-h-sm);border-radius:var(--site-r-btn);
  display:grid;place-items:center;font-size:var(--site-h3);line-height:1;color:var(--site-muted);
}
.sb-menu-catalog__lead{margin-top:var(--site-space-2);color:var(--site-muted);font-size:var(--site-small)}
.sb-menu-catalog__group{border:0;padding:0;margin-top:var(--site-space-5)}
.sb-menu-catalog__group legend{
  padding:0;font-size:var(--site-micro);letter-spacing:var(--site-micro-ls);text-transform:uppercase;
  color:var(--site-faint);
}
.sb-menu-catalog__group legend span{color:var(--site-accent)}
.sb-menu-catalog__opt{
  display:flex;align-items:center;gap:var(--site-space-3);
  min-height:var(--site-btn-h);padding-block:var(--site-space-2);
  border-bottom:1px solid var(--site-hairline);cursor:pointer;
}
/* The radio itself wears the site's accent — a browser default blue inside a restaurant's own
   palette is the one control that gives the page away as somebody else's. */
.sb-menu-catalog__radio{flex:none;accent-color:var(--site-accent)}
.sb-menu-catalog__opt span{flex:1;min-width:0}
.sb-menu-catalog__opt b{font-family:var(--site-mono);font-size:var(--site-small);color:var(--site-muted)}
.sb-menu-catalog__opt[data-state="on"]{color:var(--site-ink)}
.sb-menu-catalog__hint{margin-top:var(--site-space-4);color:var(--site-danger);font-size:var(--site-small)}
.sb-menu-catalog__add{margin-top:var(--site-space-5);width:100%}

@media (min-width:900px){
  .sb-menu-catalog__live{padding-block:var(--site-space-4)}
  .sb-menu-catalog__bar{padding-inline:var(--site-gutter-d);justify-content:center}
  .sb-menu-catalog__bar-of{margin-right:var(--site-space-6);flex-direction:row;align-items:baseline;gap:var(--site-space-3)}
  .sb-menu-catalog__scrim{align-items:center}
  .sb-menu-catalog__sheet{border-radius:var(--site-r-card);max-height:80vh}
}

/* --- menu-highlights --- */
.sb-menu-highlights__inner{max-width:var(--site-w-page);margin-inline:auto}
.sb-menu-highlights__rail{
  display:grid;grid-auto-flow:column;grid-auto-columns:68%;
  gap:var(--site-gap);overflow-x:auto;scroll-snap-type:x mandatory;
  margin-inline:calc(var(--site-gutter) * -1);padding-inline:var(--site-gutter);
  scrollbar-width:none;
}
.sb-menu-highlights__rail>*{scroll-snap-align:start}
.sb-menu-highlights__grid{display:grid}
.sb-menu-highlights__num{
  display:flex;align-items:center;gap:var(--site-space-4);
  padding-block:var(--site-space-4);border-bottom:1px solid var(--site-line);
}
.sb-menu-highlights__num i{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-style:normal;font-weight:var(--site-display-weight);
  font-size:var(--site-h2);color:var(--site-accent);letter-spacing:var(--site-display-ls);
  min-width:1.6em;line-height:1;
}
.sb-menu-highlights__num .sb-media{width:calc(var(--site-space-8) + var(--site-space-4));flex:none;aspect-ratio:var(--site-ratio-tile)}
.sb-menu-highlights__num b{display:block;font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-size:var(--site-h4);font-weight:var(--site-display-weight);letter-spacing:var(--site-display-ls)}
.sb-menu-highlights__num span{display:block;font-size:var(--site-small);color:var(--site-muted)}
.sb-menu-highlights__num>div{flex:1;min-width:0}

@media (min-width:900px){
  .sb-menu-highlights__rail{margin-inline:calc(var(--site-gutter-d) * -1);padding-inline:var(--site-gutter-d)}
  .sb-menu-highlights__rail{grid-auto-columns:1fr;grid-auto-flow:row;grid-template-columns:repeat(3,1fr);overflow:visible}
  .sb-menu-highlights[data-variant="numbered"] .sb-menu-highlights__grid{max-width:var(--site-w-read)}
}

/* Added with the view: `__num span` styles the caption, and the price is a `.sb-price` sibling that
   would inherit it. Both states are restated so a stopped dish keeps its struck, faint number. */
.sb-menu-highlights__num .sb-price{display:inline;font-size:var(--site-body-size);color:var(--site-ink)}
.sb-menu-highlights__num .sb-price[data-state="off"]{color:var(--site-faint)}

/* `rail` — the shelf of the «Día» guest home (node dia-home-look): narrow white cards on a snapping
   strip, a square photo inset in each, the name on two lines, the price and a round grey «+».
   Sizes are the mockup's (card 150, radius 24, inset 10, photo radius 17, «+» 36 with a 44 hit),
   written as multiples of the pack's own steps so a pack with square corners stays square.
   THE CARD ITSELF IS STYLED IN dish-card/block.css, keyed by this band's attributes
   (`[data-block="menu-highlights"][data-variant="rail"]`): a sheet that names another block's
   classes becomes a dependency of every e2e spec that measures that block (e2e-style-scope G-5). */
.sb-menu-highlights[data-variant="rail"] .sb-menu-highlights__rail{
  grid-auto-columns:calc(var(--site-space-5) * 6.25);
  scroll-snap-type:x proximity;scroll-padding-inline:var(--site-gutter);
}
/* The mockup's price is the text face with tabular figures, not the pack's monospace. */
.sb-menu-highlights[data-variant="rail"] .sb-price{
  font-family:var(--site-body);font-weight:400;letter-spacing:-.01em;font-size:var(--site-body-size);white-space:nowrap;
}
/* Head of the shelf as the mockup draws it: 14 under it, the «all of the carte» link a quiet line
   on the title's baseline rather than a 48-high button. */
.sb-menu-highlights[data-variant="rail"] .sb-head{margin-bottom:calc(var(--site-space-3) + var(--site-space-1) / 2)}
.sb-menu-highlights[data-variant="rail"] .sb-head__link{
  min-height:0;padding-block:calc(var(--site-space-1) * 1.5);color:var(--site-muted);font-weight:400;
}

/* The past-visit card (node dia-order-flow, In-1; mockup `.pcard--last`), first on the recognised guest's
   shelf: a column of its own, wider than a dish card (the mockup's 196 on its 24 step), two photos side by
   side 130 high (gap 3) under «Tu última vez, …», the dishes on two lines, the sum and a grey «Repetir» pill
   36 high (the mockup's `.btn--xs`: padding 12, small text, a 14 icon). Drawn by the shelf's lazy renderer,
   which marks the strip `data-last`. */
.sb-menu-highlights[data-variant="rail"] .sb-menu-highlights__rail[data-last]{grid-template-columns:calc(var(--site-space-5) * 49 / 6)}
.sb-menu-highlights__last{
  display:flex;flex-direction:column;gap:calc(var(--site-space-3) * .75);min-width:0;
  padding:calc(var(--site-space-2) * 1.25);border-radius:calc(var(--site-r-card) * 6 / 7);background:var(--site-surface);
}
.sb-menu-highlights__duo{
  position:relative;display:grid;grid-template-columns:1fr 1fr;gap:calc(var(--site-space-1) * .75);height:calc(var(--site-space-5) * 65 / 12);
  border-radius:calc(var(--site-r-media) * .85);overflow:hidden;background:var(--site-surface-2);
}
.sb-menu-highlights__duo .sb-media{display:block;height:100%;aspect-ratio:auto;border-radius:0}
.sb-menu-highlights__duo .sb-media img{display:block;width:100%;height:100%;object-fit:cover}
.sb-menu-highlights__duo .sb-media:only-of-type{grid-column:1 / -1}
.sb-menu-highlights__when{
  position:absolute;left:var(--site-space-2);top:var(--site-space-2);max-width:calc(100% - var(--site-space-2) * 2);
  height:calc(var(--site-space-2) * 2.75);padding:0 calc(var(--site-space-2) * 1.125);border-radius:var(--site-r-btn);
  background:color-mix(in srgb,var(--site-ink) 78%,transparent);color:var(--site-surface);
  font-size:var(--site-micro);line-height:calc(var(--site-space-2) * 2.75);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.sb-menu-highlights__what{
  margin:0;font-family:var(--site-body);font-size:var(--site-body-size);line-height:1.22;min-height:calc(2 * 1.22em);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.sb-menu-highlights__foot{margin-top:auto;display:flex;align-items:center;justify-content:space-between;gap:var(--site-space-1)}
.sb-menu-highlights__repeat{
  position:relative;display:inline-flex;align-items:center;gap:calc(var(--site-space-1) * 1.5);
  height:calc(var(--site-space-3) * 3);padding:0 var(--site-space-3);
  border-radius:var(--site-r-btn);background:var(--site-surface-2);color:var(--site-ink);
  font-size:var(--site-small);font-weight:600;text-decoration:none;white-space:nowrap;
}
.sb-menu-highlights__repeat::after{content:"";position:absolute;inset:calc(var(--site-space-1) * -1)}
.sb-menu-highlights__repeat svg{width:calc(var(--site-space-2) * 1.75);height:calc(var(--site-space-2) * 1.75)}

@media (min-width:900px){
  /* Desktop is not redesigned (contract Out): the shelf becomes the block's grid, just narrower. */
  .sb-menu-highlights[data-variant="rail"] .sb-menu-highlights__rail{
    grid-template-columns:repeat(auto-fill,minmax(calc(var(--site-space-8) * 3),1fr));
  }
}

/* `ribbon` — the «Most ordered» strip of the legacy storefront (node site-blocks-legacy-look): tall
   photo cards 260 wide (never more than 78 % of the screen, so the next card always peeks) on a
   snapping strip; from 900px the block's own grid of three. The card is styled in
   dish-card/block.css, keyed by this band's attributes (G-5), like `rail`. */
.sb-menu-highlights[data-variant="ribbon"] .sb-menu-highlights__rail{
  grid-auto-columns:min(calc(var(--site-space-8) * 4 + var(--site-space-1)),78%);
  gap:var(--site-space-3);scroll-padding-inline:var(--site-gutter);
}

/* --- people --- */
.sb-people__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-5)}
.sb-people__grid{display:grid;gap:var(--site-space-5)}
.sb-people__card{display:grid;gap:var(--site-space-3);min-width:0}
.sb-people__photo{aspect-ratio:var(--site-ratio-card)}
.sb-people__body{display:grid;gap:var(--site-space-3);align-content:start}
.sb-people__bio{color:var(--site-muted)}
.sb-people__who{font-size:var(--site-small);color:var(--site-muted)}
.sb-people__who b{
  display:block;font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  font-size:var(--site-h4);letter-spacing:var(--site-display-ls);
  text-transform:var(--site-display-case);color:var(--site-ink);
}

/* `rows` — the same people without their photographs, ruled into a list: what a house with one
   good portrait and eight names actually has. `quote` sets the first person's words in the display
   face beside the portrait — spec/blocks.md's `chef-feature`. */
.sb-people[data-variant="rows"] .sb-people__grid{gap:0;border-top:1px solid var(--site-line)}
.sb-people[data-variant="rows"] .sb-people__card{
  grid-template-columns:1fr;border-bottom:1px solid var(--site-hairline);
  padding-block:var(--site-space-4);
}
.sb-people[data-variant="rows"] .sb-people__photo{display:none}
.sb-people[data-variant="quote"] .sb-people__bio{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-size:var(--site-h2);line-height:var(--site-display-lh);
  letter-spacing:var(--site-display-ls);text-transform:var(--site-display-case);color:var(--site-ink);
}

@media (min-width:900px){
  .sb-people__grid{grid-template-columns:repeat(3,1fr)}
  .sb-people[data-variant="rows"] .sb-people__grid{grid-template-columns:1fr}
  .sb-people[data-variant="rows"] .sb-people__card{grid-template-columns:1fr 2fr;align-items:baseline;gap:var(--site-space-6)}
  .sb-people[data-variant="quote"] .sb-people__grid{grid-template-columns:1fr}
  .sb-people[data-variant="quote"] .sb-people__card{grid-template-columns:minmax(0,2fr) minmax(0,3fr);align-items:center;gap:var(--site-space-8)}
}

/* `photo_ratio: portrait` (node site-blocks-legacy-look): a 3:4 frame for a portrait shot standing,
   cropped from the top so the head stays in. A focal point set on the photo (inline
   `object-position`) overrides the top anchor. */
.sb-people__grid[data-photo="portrait"] .sb-people__photo{aspect-ratio:3 / 4}
.sb-people__grid[data-photo="portrait"] .sb-people__photo img{object-position:50% 0}

/* --- points-list --- */
.sb-points-list__inner{max-width:var(--site-w-page);margin-inline:auto}
.sb-points-list__grid{display:grid;gap:var(--site-gap)}
.sb-points-list__card{
  background:var(--site-surface);border:1px solid var(--site-line);border-radius:var(--site-r-card);
  overflow:hidden;display:grid;box-shadow:var(--site-shadow-card);
}
.sb-points-list__card .sb-media{border-radius:0;aspect-ratio:var(--site-ratio-card)}
.sb-points-list__body{padding:var(--site-space-5);display:grid;gap:var(--site-space-3);align-content:start}
.sb-points-list__addr{color:var(--site-muted);font-size:var(--site-small)}
.sb-points-list__rowmeta{display:flex;flex-wrap:wrap;gap:var(--site-space-2) var(--site-space-4);font-size:var(--site-small);color:var(--site-muted)}
.sb-points-list__act{display:flex;flex-wrap:wrap;gap:var(--site-space-2);margin-top:var(--site-space-1)}
.sb-points-list[data-variant="rows"] .sb-points-list__grid{gap:0;border-top:1px solid var(--site-line)}
.sb-points-list[data-variant="rows"] .sb-points-list__card{
  border:0;border-bottom:1px solid var(--site-hairline);border-radius:0;background:transparent;box-shadow:none;
  display:flex;align-items:center;gap:var(--site-space-4);
}
.sb-points-list[data-variant="rows"] .sb-points-list__body{padding:var(--site-space-4) 0;flex:1;min-width:0}

@media (min-width:900px){
  .sb-points-list__grid{grid-template-columns:repeat(3,1fr)}
  .sb-points-list[data-variant="rows"] .sb-points-list__grid{grid-template-columns:1fr}
  .sb-points-list[data-variant="rows"] .sb-points-list__body{display:flex;align-items:center;gap:var(--site-space-6);padding-block:var(--site-space-5);}
  .sb-points-list[data-variant="rows"] .sb-points-list__body>*{flex:1}
  .sb-points-list[data-variant="rows"] .sb-points-list__act{flex:none;margin:0}
  .sb-points-list__grid:has(>:only-child){grid-template-columns:1fr}
  .sb-points-list__grid:has(>:only-child) .sb-points-list__card{grid-template-columns:.85fr 1.15fr;align-items:stretch}
  .sb-points-list__grid:has(>:only-child) .sb-points-list__body{align-content:center;padding:var(--site-space-7)}
}

/* Groups («район → точки») and the `map-split` frame, added with the view: the mockups drew the
   flat `cards` list only, and both shapes are layout the markup cannot carry on its own. */
.sb-points-list__group + .sb-points-list__group{margin-top:var(--site-space-7)}
.sb-points-list__group > .sb-kicker{margin-bottom:var(--site-space-3)}
.sb-points-list__split{display:grid;gap:var(--site-gap)}
.sb-points-list__map{aspect-ratio:var(--site-ratio-card)}

@media (min-width:900px){
  /* List on the left, map on the right; on mobile the map stands first, as the spec asks. */
  .sb-points-list__split{grid-template-columns:1fr 1fr;align-items:start}
  .sb-points-list__split > .sb-points-list__map{order:2;position:sticky;top:var(--site-space-6)}
  .sb-points-list[data-variant="map-split"] .sb-points-list__grid{grid-template-columns:1fr}
}

/* `contact` — «how to get there» of the «Día» guest home (node dia-home-look): a white card of rows
   (the mockup's 54 high, 12 between icon and text, a 1px rule between rows). The address row turns
   into a check and «Copiado» while the island marks it `data-state="copied"`. */
.sb-points-list[data-variant="contact"] .sb-points-list__inner{display:grid;gap:var(--site-space-3)}
.sb-points-list__contact{background:var(--site-surface);border-radius:var(--site-r-card);padding-inline:var(--site-space-4)}
.sb-points-list__cname{padding-top:var(--site-space-4);font-size:var(--site-h4)}
.sb-points-list__row{
  display:flex;align-items:center;gap:var(--site-space-3);width:100%;
  min-height:calc(var(--site-space-3) * 4.5);padding:var(--site-space-2) 0;border:0;background:none;
  font:inherit;font-size:var(--site-body-size);letter-spacing:-.01em;color:var(--site-ink);
  text-align:left;text-decoration:none;
}
.sb-points-list__row + .sb-points-list__row{border-top:1px solid var(--site-line)}
.sb-points-list__ico,.sb-points-list__end{flex:none;display:grid;color:var(--site-muted)}
.sb-points-list__ico svg{width:calc(var(--site-space-5) - var(--site-space-1));height:calc(var(--site-space-5) - var(--site-space-1))}
.sb-points-list__end svg{width:calc(var(--site-space-4) + var(--site-space-1) / 2);height:calc(var(--site-space-4) + var(--site-space-1) / 2)}
.sb-points-list__end svg + svg{display:none}
.sb-points-list__txt{flex:1;min-width:0;text-wrap:pretty}
.sb-points-list__hint{display:none;flex:none;font-size:var(--site-small);color:var(--site-muted);white-space:nowrap}
.sb-points-list__row[data-state="copied"] .sb-points-list__hint{display:inline}
.sb-points-list__row[data-state="copied"] .sb-points-list__end svg:first-child{display:none}
.sb-points-list__row[data-state="copied"] .sb-points-list__end svg + svg{display:block}

@media (min-width:900px){
  /* Desktop is not redesigned (contract Out): the card keeps its rows at reading width. */
  .sb-points-list[data-variant="contact"] .sb-points-list__contact{max-width:var(--site-w-read)}
}

/* --- points-map --- */
/* points-map — карта точек. Разбор блока — в index.ts.

   Вёрстка перенесена с живой витрины (`ristorante.css`, `.rst-mapview`/`.rst-pin`): картографию
   рисует ТОТ ЖЕ компонент (`web-storefront/src/sections/VenuesMap.tsx`), которому блок передаёт свои
   имена классов. Величины при переносе переписаны в токены пака — здесь их нельзя оставить числами
   (BR-3, тест purity): полоса обязана жить на бумаге любого пака, а не только на кремовой. */

/* Полоса берёт общий ритм из base.css, а `__inner` — только колонка страницы, как у всех соседних
   блоков. Раньше воздух полосы был объявлен ЗДЕСЬ, на `__inner`, вместе с `max-width`: поля попадали
   ВНУТРЬ колонки страницы, и содержимое карты стояло на два поля уже, чем у любой другой полосы
   (владелец 02.09: «у The island меньше, чем у предыдущих»), а сама полоса шла без полей вовсе. */
.sb-points-map__inner { max-width: var(--site-w-page); margin-inline: auto; width: 100%; }

.sb-points-map__lead { max-width: var(--site-w-read); margin-top: var(--site-space-3); color: var(--site-muted); }

.sb-points-map__body { display: grid; grid-template-columns: 1fr; gap: var(--site-space-5);
  margin-top: var(--site-space-5); }
@media (min-width:900px) {
  .sb-points-map__body[data-variant='split'] { grid-template-columns: 1.35fr 1fr; align-items: start; }
}

/* РАМКА КАРТЫ. В серверном документе она пуста — в неё монтируется островок. Своя высота у неё есть
   до всякого javascript, иначе полоса прыгала бы, когда приедут тайлы. */
.sb-points-map__frame { position: relative; aspect-ratio: 3 / 4; background: var(--site-surface-2);
  border: 1px solid var(--site-line); border-radius: var(--site-r-media); overflow: hidden; }
@media (min-width:900px) { .sb-points-map__frame { aspect-ratio: var(--site-ratio-hero); } }
.sb-points-map__body[data-variant='wide'] .sb-points-map__frame { border-radius: 0;
  border-left: 0; border-right: 0; }

.sb-points-map__view { width: 100%; height: 100%; z-index: 0; }
/* Подложка под тайлами — бумага пака, чтобы карта не светилась белым, пока тайлы едут. */
.sb-points-map__frame .leaflet-container { background: var(--site-surface-2); font-family: var(--site-body); }

/* ТАБЛИЧКИ ДОМОВ едут маркерами leaflet и потому двигаются вместе с географией. Сам маркер — коробка
   НУЛЕВОЙ ширины на самой координате, а табличка свешивается с него: вправо по умолчанию и ВЛЕВО для
   дома в правой половине группы, чтобы длинное имя не вылезало за рамку. Ширину нельзя мерить
   процентом от родителя: процент от нулевой коробки — ноль, и имя схлопнулось бы в букву (это
   разбиралось на живом сайте, `ristorante.css`). Поэтому предел задан колонкой чтения пака. */
.sb-pin { position: absolute; top: 0; left: 0; width: max-content;
  max-width: calc(var(--site-w-read) / 2); display: flex; align-items: center;
  gap: var(--site-space-2); pointer-events: none; }
.sb-pin.left { left: auto; right: 0; flex-direction: row-reverse; }
.sb-pin i { flex: 0 0 auto; width: var(--site-space-3); height: var(--site-space-3);
  border-radius: 50% 50% 50% 0; transform: rotate(-45deg); background: var(--site-accent);
  box-shadow: var(--site-shadow-pop); }
.sb-pin b { font-family: var(--site-display); font-size: var(--site-small);
  letter-spacing: var(--site-display-ls); background: var(--site-surface); color: var(--site-ink);
  border: 1px solid var(--site-line); padding: var(--site-space-1) var(--site-space-2); min-width: 0; }
/* Дома, которые текущий масштаб не различает, подписаны ОДНОЙ табличкой — по строке на дом
   (это решение владельца по живому сайту, узел luma-map-labels). */
.sb-pin b span { display: block; white-space: nowrap; }
.sb-pin b span + span { margin-top: var(--site-space-1); padding-top: var(--site-space-1);
  border-top: 1px solid var(--site-line); }
.sb-pin.left b span { text-align: right; }

/* Районы и как между ними — авторский текст, а не данные. */
.sb-points-map__areas { display: grid; gap: var(--site-space-4); }
.sb-points-map__area b { display: block; font-size: var(--site-micro);
  letter-spacing: var(--site-micro-ls); text-transform: uppercase; color: var(--site-accent); }
.sb-points-map__area span { display: block; margin-top: var(--site-space-2); color: var(--site-muted); }

/* Список адресов — то, что полоса печатает БЕЗ javascript и не перестаёт печатать с ним. */
.sb-points-map__list { list-style: none; margin: var(--site-space-5) 0 0; padding: 0;
  display: grid; gap: 1px; background: var(--site-line); border: 1px solid var(--site-line); }
.sb-points-map__row { background: var(--site-bg); padding: var(--site-space-4); display: flex;
  align-items: baseline; justify-content: space-between; gap: var(--site-space-4); flex-wrap: wrap; }
.sb-points-map__row b { font-family: var(--site-display); font-size: var(--site-h4); }
.sb-points-map__addr { display: block; margin-top: var(--site-space-1); font-size: var(--site-small);
  color: var(--site-muted); }
.sb-points-map__rowmeta { display: flex; align-items: center; gap: var(--site-space-3); }
.sb-points-map__cta { margin-top: var(--site-space-5); }

/* --- promo-banner --- */
/* `strip` — та же полоса-строка, что и `today`: своя вертикаль, общие горизонтальные поля. */
.sb-promo-banner[data-variant="strip"]{padding-block:var(--site-space-4)}
.sb-promo-banner[data-variant="strip"] .sb-promo-banner__inner{
  max-width:var(--site-w-page);margin-inline:auto;
  display:flex;align-items:center;flex-wrap:wrap;gap:var(--site-space-3) var(--site-space-4);
}
.sb-promo-banner__t{font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);font-size:var(--site-h4);letter-spacing:var(--site-display-ls)}
.sb-promo-banner__d{font-size:var(--site-small);color:var(--site-muted)}
.sb-promo-banner[data-variant="strip"] .sb-btn{margin-left:auto}
.sb-promo-banner[data-variant="card"] .sb-promo-banner__inner{
  max-width:var(--site-w-page);margin-inline:auto;
  background:var(--site-surface);border:1px solid var(--site-line);border-radius:var(--site-r-card);
  overflow:hidden;display:grid;
}
.sb-promo-banner__body{padding:var(--site-space-6) var(--site-space-5);display:grid;gap:var(--site-space-3);align-content:center}
.sb-promo-banner__body p{color:var(--site-muted)}
.sb-promo-banner__media{aspect-ratio:var(--site-ratio-card);border-radius:0}
.sb-promo-banner__timer svg{width:1.05em;height:1.05em}
.sb-promo-banner__timer{
  display:inline-flex;align-items:center;gap:var(--site-space-2);
  font-family:var(--site-mono);font-variant-numeric:tabular-nums;font-weight:700;
  color:var(--site-warn);font-size:var(--site-h4);
}

@media (min-width:900px){
  .sb-promo-banner[data-variant="card"] .sb-promo-banner__inner{grid-template-columns:.9fr 1.1fr;align-items:stretch}
  .sb-promo-banner[data-variant="card"] .sb-promo-banner__body{padding:var(--site-space-8)}
  .sb-promo-banner__media{aspect-ratio:auto;height:100%;border-radius:0}
}

/* `split` — the card with the copy first and the headline at hero size. Added with the view: the
   mockups drew `strip` and `card`, and the third shape spec/blocks.md names is the same tree in a
   mirrored grid. */
.sb-promo-banner[data-variant="split"] .sb-promo-banner__inner{
  max-width:var(--site-w-page);margin-inline:auto;
  display:grid;gap:var(--site-space-5);align-items:center;
}
.sb-promo-banner[data-variant="split"] .sb-promo-banner__body{padding:0}
.sb-promo-banner[data-variant="split"] .sb-promo-banner__body h2{font-size:var(--site-h1)}

@media (min-width:900px){
  .sb-promo-banner[data-variant="split"] .sb-promo-banner__inner{grid-template-columns:1.1fr .9fr;gap:var(--site-space-8)}
}

/* `list` — several offers at once, ruled into rows (node site-luma-migration, Д-4): a thumbnail, the
   copy, and the figure the offer is about pulled to the edge where a price stands on every other
   block of this pack. */
.sb-promo-banner[data-variant="list"] .sb-promo-banner__inner{
  max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-4);
}
.sb-promo-banner__list{display:grid;gap:0;border-top:1px solid var(--site-line)}
.sb-promo-banner__row{
  display:flex;align-items:flex-start;gap:var(--site-space-4);
  padding-block:var(--site-space-4);border-bottom:1px solid var(--site-hairline);
}
.sb-promo-banner__thumb{flex:none;width:calc(var(--site-space-8) + var(--site-space-4));aspect-ratio:var(--site-ratio-tile)}
.sb-promo-banner__rowbody{flex:1;min-width:0;display:grid;gap:var(--site-space-2);justify-items:start}
/* The offer's prose is one element now (the shared RichText), so the gap between its paragraphs
   moves here — the row body still spaces its OWN children, and the prose spaces its paragraphs. */
.sb-promo-banner__rowtext{display:grid;gap:var(--site-space-2);justify-items:start}
.sb-promo-banner__rowbody p{color:var(--site-muted);font-size:var(--site-small)}
.sb-promo-banner__when{font-size:var(--site-small);color:var(--site-muted)}
.sb-promo-banner__v{
  flex:none;margin-left:auto;
  font-family:var(--site-mono);font-variant-numeric:tabular-nums;font-weight:700;
  font-size:var(--site-h4);color:var(--site-accent);white-space:nowrap;
}

@media (min-width:900px){
  .sb-promo-banner__row{gap:var(--site-space-6);padding-block:var(--site-space-5);align-items:center}
}

/* --- reviews --- */
.sb-reviews__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-5)}
.sb-reviews__head{display:flex;align-items:center;gap:var(--site-space-4);flex-wrap:wrap}
.sb-reviews__score{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);font-size:var(--site-h1);
  line-height:var(--site-display-lh);letter-spacing:var(--site-display-ls);color:var(--site-ink);
  font-variant-numeric:tabular-nums;
}
.sb-reviews__of{font-size:var(--site-small);color:var(--site-muted);max-width:var(--site-w-read)}
.sb-reviews__head .sb-btn{margin-left:auto}
.sb-reviews__grid{display:grid;gap:var(--site-gap)}
.sb-reviews__card{
  display:flex;flex-direction:column;gap:var(--site-space-3);min-width:0;
  padding:var(--site-space-5);border:1px solid var(--site-line);border-radius:var(--site-r-card);
  background:var(--site-surface);
}
.sb-reviews__quote{color:var(--site-ink);white-space:pre-line}
/* The guillemets are typography, not words: the quote is a `richtext` value now, and wrapping it in
   « » in the markup would have put them outside the author's own paragraph. */
.sb-reviews__quote > :first-child::before{content:"«"}
.sb-reviews__quote > :last-child::after{content:"»"}
.sb-reviews__who{margin-top:auto;font-size:var(--site-small);color:var(--site-faint)}
.sb-reviews__who b{color:var(--site-ink)}

/* `quote` — one voice, set in the display face and standing on the page itself rather than on a
   plate; `aggregate` keeps the score first and the quotes short under it. */
.sb-reviews[data-variant="quote"] .sb-reviews__card{border:0;background:transparent;padding:0}
.sb-reviews[data-variant="quote"] .sb-reviews__quote{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-size:var(--site-h2);line-height:var(--site-display-lh);
  letter-spacing:var(--site-display-ls);text-transform:var(--site-display-case);
}
.sb-reviews[data-variant="aggregate"] .sb-reviews__card{padding:var(--site-space-4)}
.sb-reviews[data-variant="aggregate"] .sb-reviews__quote{font-size:var(--site-small);color:var(--site-muted)}

@media (min-width:900px){
  .sb-reviews__grid{grid-template-columns:repeat(3,1fr)}
  .sb-reviews[data-variant="quote"] .sb-reviews__grid{grid-template-columns:1fr;max-width:var(--site-w-page)}
}

/* --- richtext --- */
.sb-richtext__inner{max-width:var(--site-w-read);margin-inline:auto}
.sb-richtext__inner[data-width="page"]{max-width:var(--site-w-page)}
.sb-richtext__inner[data-align="center"]{text-align:center}
.sb-richtext__title{margin-bottom:var(--site-space-3)}
.sb-richtext__body{display:flex;flex-direction:column;gap:var(--site-space-3);color:var(--site-muted)}
.sb-richtext__inner[data-size="s"] .sb-richtext__body{font-size:var(--site-small);color:var(--site-faint)}
.sb-richtext__inner[data-size="l"] .sb-richtext__body{font-size:var(--site-h4);color:var(--site-ink)}
.sb-richtext[data-variant="lead"] .sb-richtext__body{font-size:var(--site-h4);color:var(--site-ink)}

@media (min-width:900px){
  .sb-richtext[data-variant="columns"] .sb-richtext__inner{max-width:var(--site-w-page)}
  .sb-richtext[data-variant="columns"] .sb-richtext__body{
    display:grid;grid-template-columns:1fr 1fr;gap:var(--site-space-3) var(--site-space-7);align-items:start;
  }
}

/* --- site-footer --- */
/* Подвал берёт ритм полосы из base.css, как все. Своя пара тут была, и на десктопе у неё
   переопределялась только горизонтальная половина — вертикаль оставалась мобильной, вдвое теснее
   соседних полос. Собственная краска подвалу нужна: он стоит вне `main` и ничего не наследует. */
.sb-site-footer{background:var(--site-bg);color:var(--site-ink)}
.sb-site-footer__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-6)}
.sb-site-footer__top{display:grid;gap:var(--site-space-6)}
.sb-site-footer__brand{display:grid;gap:var(--site-space-3);align-content:start}
.sb-site-footer__col{display:grid;gap:var(--site-space-2);align-content:start}
.sb-site-footer__col h4{font-size:var(--site-micro);letter-spacing:var(--site-micro-ls);text-transform:uppercase;color:var(--site-faint);font-family:var(--site-body);font-weight:600;margin-bottom:var(--site-space-1)}
.sb-site-footer__col a,.sb-site-footer__col p{font-size:var(--site-small);color:var(--site-muted);min-height:calc(var(--site-space-5) + var(--site-space-2));display:flex;align-items:center}
.sb-site-footer__col a{color:var(--site-ink)}
.sb-site-footer__soc{display:flex;gap:var(--site-space-2);margin-top:var(--site-space-2)}
.sb-site-footer__soc a{
  width:var(--site-btn-h);height:var(--site-btn-h);border-radius:var(--site-r-chip);
  border:1px solid var(--site-line);display:grid;place-items:center;color:var(--site-ink);
}
.sb-site-footer__soc svg{width:1.15em;height:1.15em}
.sb-site-footer__legal{
  border-top:1px solid var(--site-line);padding-top:var(--site-space-5);
  display:flex;flex-wrap:wrap;align-items:center;gap:var(--site-space-3) var(--site-space-5);
  font-size:var(--site-small);color:var(--site-muted);
}
.sb-site-footer__pay{display:flex;gap:var(--site-space-2);margin-left:auto;color:var(--site-faint)}
.sb-site-footer__pay svg{width:2.4em;height:1.5em}

@media (min-width:900px){
  .sb-site-footer__top{grid-template-columns:1.3fr .9fr .9fr .9fr;gap:var(--site-space-6)}
}

/* The resolved points, and the two variants beside `columns`. Points come from a source rather
   than from the author (blocks.md: «live: адреса/часы подтягиваются»), so they get their own cell
   instead of one of the authored columns; `points-grid` gives that cell the width, `compact`
   collapses the whole top row into one line. */
.sb-site-footer__points{display:grid;gap:var(--site-space-3);align-content:start}
.sb-site-footer__points h4{
  grid-column:1/-1;font-family:var(--site-body);font-weight:600;
  font-size:var(--site-micro);letter-spacing:var(--site-micro-ls);text-transform:uppercase;color:var(--site-faint);
}
.sb-site-footer__point{display:grid;gap:var(--site-space-1);font-size:var(--site-small);color:var(--site-muted)}
.sb-site-footer__point b{font-weight:600;color:var(--site-ink)}
.sb-site-footer[data-variant="compact"] .sb-site-footer__top{display:flex;flex-wrap:wrap;align-items:center;gap:var(--site-space-3) var(--site-space-6)}
.sb-site-footer[data-variant="compact"] .sb-site-footer__col h4{display:none}

@media (min-width:900px){
  .sb-site-footer[data-variant="points-grid"] .sb-site-footer__top{grid-template-columns:1fr 2fr}
  .sb-site-footer[data-variant="points-grid"] .sb-site-footer__points{grid-template-columns:repeat(3,1fr);gap:var(--site-space-5)}
}

/* --- site-header --- */
/* ПОЛОСА ВО ВСЮ ШИРИНУ — осознанный и единственный способ отказаться от общих полей полосы
   (base.css): собственный `padding:0` на корне полосы, тот же приём, что у обложки. Шапке он нужен
   по двум причинам: её краска и нижняя линейка идут от края до края окна, а высоту строки задаёт
   `--site-nav-h`, а не воздух секции. Горизонтальное поле возвращает `__inner` — ровно то же
   `--site-gutter`, что у всех остальных полос. */
.sb-site-header{
  padding:0;
  position:sticky;top:0;z-index:40;
  background:var(--site-bg);border-bottom:1px solid var(--site-line);
}
.sb-site-header__inner{
  max-width:var(--sb-w-page-bleed);margin-inline:auto;
  min-height:var(--site-nav-h);padding-inline:var(--site-gutter);
  display:flex;align-items:center;gap:var(--site-space-4);
}
.sb-site-header__brand{display:flex;align-items:center;gap:var(--site-space-3);margin-right:auto}
.sb-site-header__logo{width:calc(var(--site-space-6) + var(--site-space-1));height:calc(var(--site-space-6) + var(--site-space-1));flex:none;color:var(--site-accent)}
.sb-site-header__logo svg{width:100%;height:100%}
/* A wordmark logo is wide: `m`/`l` give it a height and let the width follow the file, instead of
   squeezing it into the square the default `s` keeps for a mark. */
.sb-site-header__logo:is([data-size="m"],[data-size="l"]){width:auto;height:calc(var(--site-space-6) + var(--site-space-3))}
.sb-site-header__logo[data-size="l"]{height:calc(var(--site-space-7) + var(--site-space-2))}
.sb-site-header__logo:is([data-size="m"],[data-size="l"]) img{height:100%;width:auto;max-width:min(100%,calc(var(--site-space-8) * 4));object-fit:contain}
/* On a phone the actions row (languages, button, menu) keeps its width and a wide wordmark gives
   way to it — without this a long wordmark pushed the row past a phone screen and the page scrolled sideways. */
.sb-site-header__brand:has(.sb-site-header__logo:is([data-size="m"],[data-size="l"])){min-width:0;flex:0 1 auto}
.sb-site-header__logo:is([data-size="m"],[data-size="l"]){flex:0 1 auto;min-width:0}
.sb-site-header__inner:has(.sb-site-header__logo:is([data-size="m"],[data-size="l"])) .sb-site-header__act{flex:none}
.sb-site-header__wordmark{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  font-size:var(--site-h3);letter-spacing:var(--site-display-ls);line-height:1;display:block;
}
.sb-site-header__nav{display:none;gap:var(--site-space-5)}
.sb-site-header__nav a{font-size:var(--site-small);font-weight:500;color:var(--site-muted);min-height:var(--site-btn-h);display:inline-flex;align-items:center}
.sb-site-header__nav a[aria-current]{color:var(--site-ink);box-shadow:inset 0 -1px 0 var(--site-accent)}
.sb-site-header__act{display:flex;align-items:center;gap:var(--site-space-2)}
.sb-site-header__phone{display:none;font-size:var(--site-small);font-weight:600;color:var(--site-ink);white-space:nowrap}
.sb-site-header__icon{
  width:var(--site-btn-h);height:var(--site-btn-h);border-radius:var(--site-r-btn);
  display:grid;place-items:center;color:var(--site-ink);position:relative;
  background:transparent;border:0;
}
.sb-site-header__icon svg{width:1.35em;height:1.35em}
.sb-site-header__count{
  position:absolute;top:var(--site-space-1);right:var(--site-space-1);
  min-width:1.35em;height:1.35em;padding-inline:var(--site-space-1);
  border-radius:var(--site-r-chip);background:var(--site-accent);color:var(--site-on-accent);
  font-family:var(--site-mono);font-size:var(--site-micro);font-weight:700;
  display:grid;place-items:center;
}
.sb-site-header__cta{display:none}

@media (min-width:900px){
  .sb-site-header__inner{padding-inline:var(--site-gutter-d)}
  .sb-site-header__nav{display:flex}
  .sb-site-header__phone{display:block}
    .sb-site-header__cta{display:inline-flex}
  .sb-site-header__burger{display:none}
}

/* The language switcher and the two layout variants beside `classic-bar`. The switcher is an
   island control, so it is a row of buttons rather than links (there is no url to point at before
   the script knows the page). `sticky` is authored per header, and the sticky element is the
   SECTION — which the view does not own — so the switch is read off the part it does own. */
.sb-site-header:has(> .sb-site-header__inner[data-sticky="off"]){position:static}
/* NOT STUCK IN TELEGRAM'S IN-APP BROWSER. On iOS Telegram lays the page out BELOW its see-through top
   bar but lets the scrolled content draw up under it, so a `top:0` header sticks under the bar with
   the page showing through above it — and nothing painted past the window edge can cover that.
   The head of the document marks the browser (`data-inapp`, lib/sites/inapp-js.ts in the server);
   there the header scrolls away with the page. Its z-index stays, so the burger's drop-down still
   lies over the bands below. */
html[data-inapp="telegram"] .sb-site-header{position:relative}
/* WHERE THINGS STICK UNDER THE HEADER, said once for the page: the header's row while it is stuck,
   0 when there is none to stick under (no header, a static one, Telegram). The menu's category rail
   reads it (menu-catalog/block.css). */
.sb-page{--sb-header-stick:0px}
.sb-page:has(.sb-site-header){--sb-header-stick:var(--site-nav-h)}
.sb-page:has(.sb-site-header__inner[data-sticky="off"]),
html[data-inapp="telegram"] .sb-page{--sb-header-stick:0px}
.sb-site-header__lang{display:flex;align-items:center;gap:var(--site-space-1)}
.sb-site-header__lang button{
  min-height:var(--site-btn-h);padding-inline:var(--site-space-2);
  font-size:var(--site-micro);letter-spacing:var(--site-micro-ls);text-transform:uppercase;
  color:var(--site-faint);
}
.sb-site-header__lang button[aria-current]{color:var(--site-ink)}
.sb-site-header[data-variant="minimal"] .sb-site-header__phone{display:none}
.sb-site-header[data-variant="centered"] .sb-site-header__inner{flex-wrap:wrap;justify-content:center;padding-block:var(--site-space-3)}
.sb-site-header[data-variant="centered"] .sb-site-header__brand{margin-right:0}
.sb-site-header[data-variant="centered"] .sb-site-header__nav{order:3;flex-basis:100%;justify-content:center}

/* ── Island states (site-islands-hydrate). The header's runtime adds NO elements: it flips
   `data-menu` on the section and `data-count` on the cart link, and these rules do the rest.
   That is what lets the served markup and the hydrated markup stay byte-identical. ── */
.sb-site-header__icon[data-count]::after{
  content:attr(data-count);
  position:absolute;top:var(--site-space-1);right:var(--site-space-1);
  min-width:1.35em;height:1.35em;padding-inline:var(--site-space-1);
  border-radius:var(--site-r-chip);background:var(--site-accent);color:var(--site-on-accent);
  font-family:var(--site-mono);font-size:var(--site-micro);font-weight:700;
  display:grid;place-items:center;
}
/* Mobile-first, like every rule above it: the drawer IS the nav, stacked under the bar and IN FLOW
   (the header may be sticky or static — the author's switch — and a positioned drawer would have to
   know which). The desktop block below puts the row back, so a guest who opens the drawer and then
   widens the window sees the ordinary nav rather than a column. */
.sb-site-header[data-menu="open"] .sb-site-header__inner{flex-wrap:wrap;row-gap:0}
.sb-site-header[data-menu="open"] .sb-site-header__nav{
  display:flex;flex-direction:column;gap:0;order:9;flex-basis:100%;
  padding-block:var(--site-space-2) var(--site-space-4);border-top:1px solid var(--site-hairline);
}
.sb-site-header[data-menu="open"] .sb-site-header__nav a{min-height:var(--site-btn-h);font-size:var(--site-body-size)}

@media (min-width:900px){
  .sb-site-header[data-menu="open"] .sb-site-header__inner{flex-wrap:nowrap}
  .sb-site-header[data-menu="open"] .sb-site-header__nav{
    flex-direction:row;gap:var(--site-space-5);order:0;flex-basis:auto;padding-block:0;border-top:0;
  }
}

/* СТРАНИЦА С ВКЛАДКАМИ ЗАБИРАЕТ У ШАПКИ БУРГЕР И КОРЗИНУ. Работу шапки на телефоне взяла нижняя
   полоса: список страниц переехал вниз целиком, корзина стала вкладкой и липкой полосой, а две
   навигации, спорящие друг с другом, — это как раз бургер плюс вкладки. Остаются знак, название и
   переключатель языка (contract.md узла site-home-hub, R-2).

   Правило стоит ЗДЕСЬ, а не в `site-tabbar/block.css`, хотя причина там: классы шапки — свои
   только для этого листа, и лист, назвавший чужие, перестаёт быть узким (разбор — там же).
   Признак `data-tabbar` пишет `renderPage` на корне страницы. */
[data-tabbar="on"] .sb-site-header__burger,
[data-tabbar="on"] .sb-site-header__icon:not(.sb-site-header__burger){display:none}

/* A PHONE PAGE THAT OPENS ON THE VENUE CARD HAS NO HEADER AT ALL (node dia-home-look, the «Día»
   home). The card names the venue, carries the language button on its photo and the table pill,
   and the tabs carry the navigation — a header above it would say the venue's name twice and push
   the photo down by a bar. Keyed by attributes only: the page's `data-tabbar` and the hero's
   `data-variant`, both written by renderPage. The desktop keeps its header (contract Out). */
[data-tabbar="on"]:has([data-block="hero"][data-variant="card"]) [data-block="site-header"]{display:none}

@media (min-width:900px){
  [data-tabbar="on"]:has([data-block="hero"][data-variant="card"]) [data-block="site-header"]{display:block}
  /* Корзина возвращается ровно там, где полосы вкладок не стало: автор вправе оставить вкладки и
     на десктопе, и тогда второй корзины рядом с вкладкой-корзиной не появляется. */
  [data-tabbar="on"]:has(.sb-site-tabbar__inner[data-desktop="off"]) .sb-site-header__icon:not(.sb-site-header__burger){display:grid}
}

/* --- site-tabbar --- */
/* site-tabbar — нижняя навигация телефона. Стили перенесены из макета выбранного варианта
   (context/design-builder/mockups/site-parrilla-02-home-hub-b-md.html, секция `site_tabbar`)
   значение в значение; изменены только имена селекторов (kebab-case реестра, decisions.md Д-2)
   и медиазапрос: в макете доска подменяет его на `@container`, в продукте это окно.

   ПОЛОСА ВО ВСЮ ШИРИНУ И БЕЗ ВОЗДУХА СЕКЦИИ — собственный `padding` на корне полосы, тот же
   приём, что у шапки и у обложки (base.css): краска и верхняя линейка идут от края до края окна,
   а высоту строки задают вкладки, а не ритм секций. */
/* ВЫСОТА ПОЛОСЫ — ОДНО ЧИСЛО, А НЕ ДВА ПОХОЖИХ. Резерв поля страницы и высота самой полосы
   обязаны совпадать: разойдутся на волосок — и нижняя кромка контента уедет под вкладки. Считались
   они порознь и разошлись ровно на верхнюю линейку (замер приёмки). Теперь считается одно: строка
   вкладки — и полная высота из неё же, вместе с линейкой и безопасной зоной телефона с вырезом.
   Имена свои, `--sb-`: это переменные блока, а не токены пака (их список — style-packs.md). */
/* Признак носит СТРАНИЦА, и правило ключится по признаку, а не по её классу. Так лист вкладок
   не называет ни одного чужого имени и остаётся УЗКИМ: `core/ops/process/e2e-style-scope.py`
   считает зависимости спеков по классам селектора, и лист, назвавший `.sb-page`, тянет за собой
   каждый спек, который меряет страницу. `data-tabbar` пишет только `renderPage` и только на
   `.sb-page` — адрес от этого не становится шире, а зависимость исчезает. */
[data-tabbar="on"]{
  --sb-tabbar-row:calc(var(--site-btn-h) + var(--site-space-3));
  --sb-tabbar-h:calc(var(--sb-tabbar-row) + 1px + env(safe-area-inset-bottom,0));
}
.sb-site-tabbar{
  padding:0;
  position:fixed;left:0;right:0;bottom:0;z-index:40;
  background:var(--site-surface);border-top:1px solid var(--site-line);
  padding-bottom:env(safe-area-inset-bottom,0);
}
/* `grid-auto-flow:column` вместо `repeat(4,1fr)` из макета — единственное осознанное расхождение
   в этом файле: вкладок бывает три, четыре и пять (пресеты блока), и колонок должно быть ровно
   столько же. Прибитая четвёрка растянула бы три вкладки на четыре места и обрезала бы пятую. */
.sb-site-tabbar__inner{
  display:grid;grid-auto-flow:column;grid-auto-columns:1fr;
  max-width:var(--site-w-page);margin-inline:auto;
}
.sb-site-tabbar__tab{
  display:grid;justify-items:center;align-content:center;gap:var(--site-space-1);
  min-height:var(--sb-tabbar-row);
  padding:var(--site-space-2) var(--site-space-1);
  color:var(--site-muted);font-size:var(--site-micro);font-weight:500;
  line-height:1.2;text-align:center;position:relative;
}
.sb-site-tabbar__tab svg{width:var(--site-space-5);height:var(--site-space-5);stroke-width:1.5}
/* THE ACTIVE TAB IS INK, label and icon alike, and nothing else marks it (node dia-home-look, the
   «Día» tab bar): no bar on top, no accent. The accent is not safe as text on every pack (parrilla's
   old red gave 3.2:1 on the label), and ink is — 14:1 on the bar's white. */
.sb-site-tabbar__tab[aria-current="page"]{color:var(--site-ink);font-weight:600}
.sb-site-tabbar__ico{position:relative;display:grid;place-items:center}
/* МЕТКА КОРЗИНЫ И ТОЧКА СТОЛА — АТРИБУТ, А НЕ УЗЕЛ. Остров пишет `data-count` (число позиций) и
   `data-pip` (стол подтверждён) на коробку значка, а рисует их css. Так поданная и оживлённая
   разметка совпадают байт в байт: лишний потомок был бы узлом, которого react не ставил. */
.sb-site-tabbar__ico[data-count]::after,
.sb-site-tabbar__ico[data-pip]::after{
  content:attr(data-count);
  position:absolute;top:0;right:calc(var(--site-space-2) * -1);
  min-width:var(--site-space-4);height:var(--site-space-4);padding-inline:var(--site-space-1);
  border-radius:var(--site-r-chip);background:var(--site-accent);color:var(--site-on-accent);
  font-family:var(--site-mono);font-size:var(--site-micro);font-weight:700;line-height:1;
  display:grid;place-items:center;
}
/* Точка — тот же кружок без числа: у стола нечего считать, ему нужно только «здесь что-то есть». */
.sb-site-tabbar__ico[data-pip]:not([data-count])::after{
  content:"";min-width:var(--site-space-2);width:var(--site-space-2);height:var(--site-space-2);padding:0;
}
/* Вариант `icons` — пять вкладок группы, где подписи не помещаются. Подпись остаётся В ДОКУМЕНТЕ
   и достаётся читалке экрана: вкладка со значком и без имени иначе называется «ссылка». */
.sb-site-tabbar[data-variant="icons"] .sb-site-tabbar__label{
  position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;
}

/* СТРАНИЦА ОСВОБОЖДАЕТ МЕСТО ПОД ПОЛОСОЙ — единственное, что этот лист говорит не о себе, и
   говорит он это признаку, а не чужому классу. Липкая корзина каталога садится над вкладками
   САМА, читая `--sb-tabbar-h` у себя в `menu-catalog/block.css`: обе прибиты к нижней кромке, и
   без этого корзина накрыла бы вкладки на каждой странице с заказом
   (blocks-proposal-home-hub.md §6 п.5). Кто чей сосед — знает переменная, а не селектор.
   Так же уходит из шапки бургер: правило живёт в `site-header/block.css`, потому что классы там
   его. */
[data-tabbar="on"]{padding-bottom:var(--sb-tabbar-h)}

@media (min-width:900px){
  /* Полоса телефона — на десктопе её нет вовсе, и место под неё страница не резервирует.
     `:has()` — потому что признак носит часть, а корень секции принадлежит renderPage. */
  .sb-site-tabbar:has(> .sb-site-tabbar__inner[data-desktop="off"]){display:none}
  /* Полосы нет — значит и высота её ноль, и всё, что на неё опиралось (поле страницы, посадка
     липкой корзины), само встаёт на место. Одно число, одно правило. */
  [data-tabbar="on"]:has(.sb-site-tabbar__inner[data-desktop="off"]){--sb-tabbar-h:0px}
}

/* --- story --- */
.sb-story__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-5)}
.sb-story__text{display:grid;gap:var(--site-space-4);align-content:center;max-width:var(--site-w-read)}
.sb-story__text p{color:var(--site-muted)}
/* The body is now ONE child of the text column (a `richtext` value may be a list or a subheading,
   not only paragraphs), so the column's own rhythm moves inside it. */
.sb-story__text .sb-rt{gap:var(--site-space-4)}
.sb-story__sign{display:flex;align-items:center;gap:var(--site-space-3);margin-top:var(--site-space-2)}
.sb-story__sign b{display:block;font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-size:var(--site-h4);font-weight:var(--site-display-weight)}
.sb-story__sign span{display:block;font-size:var(--site-small);color:var(--site-faint)}
.sb-story__sign .sb-media{width:calc(var(--site-space-7) + var(--site-space-1));aspect-ratio:var(--site-ratio-tile);border-radius:var(--site-r-chip);flex:none}
.sb-story__media{aspect-ratio:var(--site-ratio-card)}

@media (min-width:900px){
  .sb-story__inner{grid-template-columns:1fr 1fr;gap:var(--site-space-8);align-items:center}
  .sb-story__inner .sb-story__media{aspect-ratio:var(--site-ratio-card);order:2}
  .sb-story__inner .sb-story__text{order:1}
}

/* Variants and `media_side`, added with the view: the mockups drew only `side-by-side` with the
   photo on the right, and the three shapes spec/blocks.md names are the same tree in a different
   grid — so they are a few rules here rather than three markup branches in View.tsx. */
.sb-story__inner[data-side="none"]{grid-template-columns:minmax(0,1fr)}
.sb-story[data-variant="wide-quote"] .sb-story__text{max-width:none}
.sb-story[data-variant="wide-quote"] .sb-story__text p{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-size:var(--site-h3);
  line-height:var(--site-display-lh);color:var(--site-ink);
}

@media (min-width:900px){
  .sb-story__inner[data-side="left"] .sb-story__media{order:1}
  .sb-story__inner[data-side="left"] .sb-story__text{order:2}
  .sb-story[data-variant="overlap"] .sb-story__inner .sb-story__text{
    position:relative;z-index:1;background:var(--site-surface);
    border-radius:var(--site-r-card);padding:var(--site-space-7);
    margin-inline-start:calc(var(--site-space-8) * -1);
  }
}

/* --- table-actions --- */
/* table-actions — гость за столом. Стили перенесены из макета выбранного варианта
   (site-parrilla-02-home-hub-b-md.html, секция `table_actions`) значение в значение; изменены
   имена селекторов и медиазапрос.

   ПОЛОСА НЕ ВИДНА, ПОКА СТОЛ НЕ ПОДТВЕРЖДЁН. Единственное правило, ради которого блок вообще
   печатается в документ (см. View.tsx): остров оживляет только то, что сервер напечатал, а стол
   сервер знать не может. `display:none` убирает полосу и из картинки, и из дерева доступности —
   гость без стола не видит и не слышит ничего. */
.sb-table-actions__inner[data-state="off"]{display:none}
/* И САМА ПОЛОСА ТОЖЕ — ИНАЧЕ ОТ НЕЁ ОСТАЁТСЯ ВОЗДУХ. Воздух полосы `base.css` вешает на корень
   секции по `[data-slot]`, а корень принадлежит `renderPage`: спрятав одно содержимое, блок
   оставлял между намерениями и рассказом о доме пустой прямоугольник в высоту двойного воздуха
   полосы — измерено на снимках приёмки. `:has()` — потому что признак носит часть, а прячется
   целое. */
.sb-table-actions:has(> .sb-table-actions__inner[data-state="off"]){display:none}
.sb-table-actions__act[data-href="off"]{display:none}

.sb-table-actions__inner{max-width:var(--site-w-page);margin-inline:auto;display:grid;gap:var(--site-space-4)}
.sb-table-actions__head{display:flex;align-items:center;gap:var(--site-space-3);flex-wrap:wrap}
.sb-table-actions__head h2{font-size:var(--site-h3)}
.sb-table-actions__grid{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--site-space-3)}
.sb-table-actions__act{
  display:grid;gap:var(--site-space-2);align-content:start;
  min-height:calc(var(--site-space-8) + var(--site-space-6));
  padding:var(--site-space-4);
  border-radius:var(--site-r-card);
  background:var(--site-surface);text-align:left;color:var(--site-ink);
}
.sb-table-actions__act svg{width:var(--site-space-5);height:var(--site-space-5);color:var(--site-muted)}
.sb-table-actions__act b{font-size:var(--site-h4);font-weight:600}
.sb-table-actions__act span{font-size:var(--site-small);color:var(--site-muted);line-height:1.35}
/* ГЛАВНОЕ ДЕЙСТВИЕ — КОФЕЙНАЯ ПЛАШКА, А НЕ КРАСНАЯ. Белый текст на `--site-accent` даёт 3,5:1 —
   крупной кнопке хватает, мелкой подписи внутри плитки нет (blocks-proposal-home-hub.md §6 п.3).
   На `--site-ink` та же подпись даёт 13:1. Красный остаётся значку. */
.sb-table-actions__act[data-role="primary"]{
  grid-column:1/-1;background:var(--site-btn-accent);color:var(--site-btn-on-accent);
}
/* The primary action is the pack's button pair (node dia-home-look): the pair the pack and the site's
   palette guarantee at ≥ 4.5:1; icon and sub-line are its label at 72 %, as on the «Día» tiles. */
.sb-table-actions__act[data-role="primary"] :is(svg,span){color:color-mix(in srgb,var(--site-btn-on-accent) 72%,var(--site-btn-accent))}
/* The last visible action left alone in its row takes the row (catalogue: «нечётное последнее
   действие занимает ряд целиком»). A review action without its address is out of the picture
   (`data-href="off"`), so it is left out of the count. */
.sb-table-actions__act:nth-last-child(1 of :not([data-href="off"])):nth-child(odd of :not([data-href="off"],[data-role="primary"])){grid-column:1/-1}

/* The waiter call (node call-waiter, PR 2228). In its resting form it is a real <button> dressed
   as the plate; open, it is the question with the reasons; sent, it is the state of the call in
   the same place. Every control inside is as tall as the pack's button (`--site-btn-h`) — the
   guest holds the phone in one hand at a table. */
button.sb-table-actions__act{font:inherit;cursor:pointer;width:100%}
p.sb-table-actions__act{margin:0}
.sb-table-actions__reasons{display:flex;flex-wrap:wrap;gap:var(--site-space-2)}
.sb-table-actions__reason{
  font:inherit;font-weight:600;cursor:pointer;min-height:var(--site-btn-h);padding-inline:var(--site-space-4);
  border:0;border-radius:var(--site-r-btn);background:var(--site-bg);color:var(--site-ink);
}
.sb-table-actions__reason:disabled{opacity:.6;cursor:default}
.sb-table-actions__cancel{
  justify-self:start;font:inherit;cursor:pointer;min-height:var(--site-btn-h);padding:0;
  border:0;background:none;color:inherit;text-decoration:underline;
}

@media (min-width:900px){
  /* Действий за столом три-пять — на десктопе они всегда в один ряд. */
  .sb-table-actions__grid{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:1fr}
  .sb-table-actions__act[data-role="primary"],
  .sb-table-actions__act:nth-last-child(1 of :not([data-href="off"])):nth-child(odd of :not([data-href="off"],[data-role="primary"])){grid-column:auto}
}

/* Вариант `rows` — те же действия строками, для узких мест страницы. */
.sb-table-actions[data-variant="rows"] .sb-table-actions__grid{grid-template-columns:1fr}
.sb-table-actions[data-variant="rows"] .sb-table-actions__act{
  grid-template-columns:auto 1fr;align-items:center;
  min-height:var(--site-btn-h);column-gap:var(--site-space-3);
}
.sb-table-actions[data-variant="rows"] .sb-table-actions__act svg{grid-row:1/3}

/* Variant `sheet` (node dia-home-look): on a phone the band IS the table sheet (parts.tsx `Sheet`),
   and the section box is dissolved (`display:contents`) rather than stripped of its air: a fixed
   sheet must leave nothing in the page's flow, and a section with no box is also no place for the
   browser to scroll to when the address says `#table`. On a desktop the sheet renders as the band
   (`data-desktop="band"`) and the section is an ordinary box again, with the shared band air. */
.sb-table-actions[data-variant="sheet"]{display:contents}
.sb-table-actions[data-variant="sheet"] .sb-table-actions__inner{display:block}
@media (min-width:900px){
  .sb-table-actions[data-variant="sheet"]{display:block}
}

/* THE «DÍA» TABLE SHEET'S CALL (node dia-table-review, View.tsx `SheetCall`; mockup
   `dia-table-01-idle`): the wide call tile and four reason tiles, 2×2. The tile is the home's intent
   tile (buttons/block.css `.sb-buttons__hub`) in shape and type — one tile on the home and in its
   sheet — and speaks the same three roles: `primary` the pack's button pair (ink under white on Día),
   plain the surface card, `done` the grey card of «already asked» with the ink tick. */
.sb-table-actions__tiles{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--site-space-3)}
.sb-table-actions__tile{
  display:flex;flex-direction:column;align-items:flex-start;min-width:0;margin:0;
  min-height:calc(var(--site-space-8) * 2 + var(--site-space-3));padding:var(--site-space-4);
  border:0;border-radius:var(--site-r-card);background:var(--site-surface);color:var(--site-ink);
  box-shadow:var(--site-shadow-card);font:inherit;text-align:left;
}
button.sb-table-actions__tile{cursor:pointer}
.sb-table-actions__tile svg{flex:none;width:var(--site-space-5);height:var(--site-space-5);color:var(--site-muted)}
.sb-table-actions__tile b{
  margin-top:auto;padding-top:var(--site-space-3);
  font-size:var(--site-h4);font-weight:600;letter-spacing:-.015em;line-height:1.2;
}
.sb-table-actions__tile span{margin-top:var(--site-space-1);font-size:var(--site-micro);line-height:1.3;color:var(--site-muted)}
/* The wide call tile is lower than the reason tiles, as in the mockup (128 against 142): two steps. */
.sb-table-actions__tile[data-act="call"]{grid-column:1/-1;min-height:calc(var(--site-space-8) * 2)}
/* the bill (dia-pay-at-table In-2): one row under the reasons, as tall as a reason tile's head. */
.sb-table-actions__tile[data-act="bill"]{grid-column:1/-1;min-height:0;text-decoration:none}
.sb-table-actions__tile[data-role="primary"]{background:var(--site-btn-accent);color:var(--site-btn-on-accent)}
.sb-table-actions__tile[data-role="primary"] :is(svg,span){color:color-mix(in srgb,var(--site-btn-on-accent) 72%,var(--site-btn-accent))}
.sb-table-actions__tile[data-role="done"]{background:var(--site-surface-2);box-shadow:none}
.sb-table-actions__tile[data-role="done"] :is(svg,span){color:var(--site-ink)}
/* Sending, or the short «the waiter came by» window: the tiles cannot be pressed, and the title says
   so by going quiet (still ≥ 4.5:1 — the muted ink). */
.sb-table-actions__tile:disabled{cursor:default}
.sb-table-actions__tile:disabled b{color:var(--site-muted)}
.sb-table-actions__alert{grid-column:1/-1;font-size:var(--site-small);line-height:1.35;color:var(--site-danger)}
@media (min-width:900px){
  /* The desktop band: the call over the four reasons standing in one row. */
  .sb-table-actions__tiles{grid-template-columns:repeat(4,minmax(0,1fr))}
}

/* THE REVIEW SHEET (node dia-table-review, decisions Д-9; markup `review.tsx`, state
   `web-storefront/src/site/review-sheet.tsx`). Its wrapper `.sb-table-actions__review` stands at the
   page root, beside the sections, and opens by its own address `#review` (base.css sheet rules). */
.sb-table-review{display:grid;gap:var(--site-space-4);padding-bottom:var(--site-space-2)}
.sb-table-review p{margin:0}
.sb-table-review__note{padding-block:var(--site-space-6);text-align:center;color:var(--site-muted)}
.sb-table-review__offer{display:flex;align-items:center;gap:var(--site-space-2);font-size:var(--site-small);color:var(--site-muted)}
.sb-table-review__offer svg{flex:none;width:var(--site-space-4);height:var(--site-space-4)}
.sb-table-review__card{
  display:grid;gap:var(--site-space-1);padding:var(--site-space-2) var(--site-space-4);
  border-radius:var(--site-r-card);background:var(--site-surface);color:var(--site-ink);box-shadow:var(--site-shadow-card);
}
.sb-table-review__card > b{padding-top:var(--site-space-2);font-size:var(--site-h4);font-weight:600}
.sb-table-review__card > p{padding-bottom:var(--site-space-2);font-size:var(--site-small);line-height:1.4;color:var(--site-muted)}

/* Three rows of five stars. A star is a 40-unit square (the sheet's close button) around a 20-unit
   picture: five fit beside «La atención» on a 360 phone with no row breaking. */
.sb-table-review__row{
  display:flex;align-items:center;justify-content:space-between;gap:var(--site-space-2);
  min-height:calc(var(--site-space-8) - var(--site-space-2));
}
.sb-table-review__row + .sb-table-review__row{border-top:1px solid var(--site-line)}
.sb-table-review__label{min-width:0;font-size:var(--site-body-size)}
.sb-table-review__stars{display:flex;flex:none}
.sb-table-review__star{
  display:grid;place-items:center;padding:0;border:0;background:none;cursor:pointer;
  width:calc(var(--site-space-6) + var(--site-space-2));height:calc(var(--site-space-6) + var(--site-space-2));
  color:var(--site-muted);
}
.sb-table-review__star svg{width:var(--site-space-5);height:var(--site-space-5)}
.sb-table-review__star[data-on]{color:var(--site-ink)}
.sb-table-review__star[data-on] svg{fill:currentColor}

.sb-table-review__fold + .sb-table-review__fold{border-top:1px solid var(--site-line)}
.sb-table-review__fold-head{
  display:flex;align-items:center;gap:var(--site-space-3);width:100%;padding:0;border:0;background:none;
  min-height:calc(var(--site-space-8) - var(--site-space-2));font:inherit;color:inherit;text-align:left;cursor:pointer;
}
.sb-table-review__fold-head svg{flex:none;width:var(--site-space-5);height:var(--site-space-5)}
.sb-table-review__fold-title{display:grid;flex:1;min-width:0}
.sb-table-review__fold-title small{overflow:hidden;font-size:var(--site-small);color:var(--site-muted);text-overflow:ellipsis;white-space:nowrap}
.sb-table-review__chev{color:var(--site-muted);transition:transform .2s ease}
.sb-table-review__fold[data-open] .sb-table-review__chev{transform:rotate(90deg)}
.sb-table-review__fold-body{padding-bottom:var(--site-space-3)}
.sb-table-review__input{
  box-sizing:border-box;width:100%;min-height:var(--site-input-h);padding:var(--site-space-3);
  border:1px solid var(--site-line);border-radius:var(--site-r-input);background:var(--site-bg);color:var(--site-ink);font:inherit;
}
textarea.sb-table-review__input{min-height:calc(var(--site-space-8) + var(--site-space-5));resize:vertical}
/* the photo fold (Д-15, mockup `.rv__file`): a pill that opens the phone's picker; once chosen, a 48 px
   thumbnail and the file's name. The real input is present for the picker and for tests, not for the eye. */
.sb-table-review__file{position:relative;display:flex;align-items:center;gap:var(--site-space-3);min-width:0;cursor:pointer}
.sb-table-review__file input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.sb-table-review__pick{
  display:inline-flex;align-items:center;height:var(--site-btn-h-sm);padding-inline:var(--site-space-4);
  border-radius:var(--site-btn-h-sm);background:var(--site-surface-2);font-size:var(--site-btn-size);font-weight:600;
}
.sb-table-review__thumb{width:var(--site-btn-h);height:var(--site-btn-h);flex:none;border-radius:calc(var(--site-r-card) / 2);object-fit:cover}
.sb-table-review__filename{min-width:0;overflow:hidden;font-size:var(--site-small);color:var(--site-muted);text-overflow:ellipsis;white-space:nowrap}

.sb-table-review__consent,.sb-table-review__hint{font-size:var(--site-small);line-height:1.4;color:var(--site-muted)}
.sb-table-review__hint{margin-top:calc(var(--site-space-2) * -1);text-align:center}
.sb-table-review__alert{font-size:var(--site-small);color:var(--site-danger)}
.sb-table-review__send{
  width:100%;min-height:var(--site-btn-h);padding-inline:var(--site-btn-px);border:0;border-radius:var(--site-r-btn);
  background:var(--site-btn-accent);color:var(--site-btn-on-accent);font:inherit;font-size:var(--site-btn-size);font-weight:600;cursor:pointer;
}
/* Muted until all three are rated — the words under it say why. */
.sb-table-review__send:disabled{background:var(--site-surface-2);color:var(--site-muted);cursor:default}

/* After sending: the tick, «Thanks», the apology when the rating is low, the ink code card, the map. */
.sb-table-review__thanks{display:grid;justify-items:center;gap:var(--site-space-2);padding-top:var(--site-space-3);text-align:center}
/* «Gracias, Sofía» addresses a person — the pack's lowercase headings are not for it (like the sheet's title). */
.sb-table-review__thanks h3{margin:0;font-size:var(--site-h2);letter-spacing:-.015em;text-transform:none}
.sb-table-review__thanks p{color:var(--site-muted)}
.sb-table-review__ok{
  display:grid;place-items:center;border-radius:var(--site-r-chip);background:var(--site-ok);color:var(--site-bg);
  width:calc(var(--site-space-6) + var(--site-space-3));height:calc(var(--site-space-6) + var(--site-space-3));
}
.sb-table-review__ok svg{width:var(--site-space-5);height:var(--site-space-5)}
.sb-table-review__code{
  display:flex;align-items:center;justify-content:space-between;gap:var(--site-space-3);padding:var(--site-space-5);
  border-radius:var(--site-r-card);background:var(--site-btn-accent);color:var(--site-btn-on-accent);
}
.sb-table-review__code > div{display:grid;gap:var(--site-space-1);min-width:0}
.sb-table-review__code p{font-size:var(--site-small);color:color-mix(in srgb,var(--site-btn-on-accent) 72%,var(--site-btn-accent))}
.sb-table-review__code b{overflow-wrap:anywhere;font-size:var(--site-h2);font-weight:600;letter-spacing:.02em}
.sb-table-review__copy{
  flex:none;min-height:var(--site-btn-h-sm);padding-inline:var(--site-btn-px);border:0;border-radius:var(--site-r-btn);
  background:var(--site-btn-on-accent);color:var(--site-btn-accent);font:inherit;font-weight:600;cursor:pointer;
}
.sb-table-review__maps{
  display:inline-flex;align-items:center;gap:var(--site-space-2);justify-self:start;margin-bottom:var(--site-space-2);
  min-height:var(--site-btn-h);padding-inline:var(--site-btn-px);border-radius:var(--site-r-btn);
  background:var(--site-surface-2);color:var(--site-ink);font-weight:600;text-decoration:none;
}
.sb-table-review__maps svg{width:var(--site-space-5);height:var(--site-space-5)}

/* --- today --- */
/* Полоса-строка: тоньше обычной секции по вертикали — это её форма, а не оплошность, поэтому
   вертикаль объявлена своя, а горизонтальные поля берутся общие (base.css). */
.sb-today{padding-block:var(--site-space-4);background:var(--site-surface)}
.sb-today__inner{
  max-width:var(--site-w-page);margin-inline:auto;
  display:flex;flex-wrap:wrap;gap:var(--site-space-4) var(--site-space-6);
}
.sb-today__item{display:grid;gap:var(--site-space-1);min-width:0}
.sb-today__label{
  font-size:var(--site-micro);font-weight:700;letter-spacing:var(--site-micro-ls);
  text-transform:uppercase;color:var(--site-faint);
}
.sb-today__value{display:flex;align-items:center;gap:var(--site-space-2);flex-wrap:wrap;font-size:var(--site-small);color:var(--site-ink)}
.sb-today__value b{font-family:var(--site-mono);font-variant-numeric:tabular-nums;font-weight:600}
.sb-today__item[data-kind="live"] .sb-today__value{color:var(--site-ink)}

/* `cards` — the same items as plates, for a page where the strip would be lost between two photos. */
.sb-today[data-variant="cards"] .sb-today__inner{display:grid;grid-template-columns:1fr;gap:var(--site-gap)}
.sb-today[data-variant="cards"] .sb-today__item{
  padding:var(--site-space-4);border:1px solid var(--site-line);border-radius:var(--site-r-card);
  background:var(--site-bg);
}

/* `figures` — the strip with ACCENTS (node site-blocks-ox-variants, LUMA's OX «the second block looks
   odd, think about accents»): the value is the figure a guest remembers («250 ฿», «12:00–21:00»),
   set large in the display face, and the label is the small line under it. The items share the
   whole width instead of huddling at the left; on a phone they stack, ruled. The markup is the
   strip's (label, then value — that is the reading order); only the picture puts the value first. */
.sb-today[data-variant="figures"]{padding-block:var(--site-space-5)}
.sb-today[data-variant="figures"] .sb-today__inner{display:grid;grid-template-columns:minmax(0,1fr);gap:0}
.sb-today[data-variant="figures"] .sb-today__item{
  display:flex;flex-direction:column-reverse;justify-content:flex-end;gap:var(--site-space-2);
  padding-block:var(--site-space-4);border-top:1px solid var(--site-line);
}
.sb-today[data-variant="figures"] .sb-today__item:first-child{border-top:0}
.sb-today[data-variant="figures"] .sb-today__value{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  font-size:var(--site-h2);line-height:1.05;letter-spacing:var(--site-display-ls);text-transform:var(--site-display-case);
}
.sb-today[data-variant="figures"] .sb-today__value b{font-family:inherit;font-weight:inherit}
.sb-today[data-variant="figures"] .sb-today__label{color:var(--site-muted)}

@media (min-width:900px){
  .sb-today{padding-block:var(--site-space-5)}
  .sb-today[data-variant="cards"] .sb-today__inner{grid-template-columns:repeat(4,1fr)}
  .sb-today[data-variant="figures"]{padding-block:var(--site-space-6)}
  .sb-today[data-variant="figures"] .sb-today__inner{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr)}
  .sb-today[data-variant="figures"] .sb-today__item{
    border-top:0;border-left:1px solid var(--site-line);padding-block:0;padding-inline:var(--site-space-5);
  }
  .sb-today[data-variant="figures"] .sb-today__item:first-child{border-left:0;padding-left:0}
}

/* --- venues-mosaic --- */
/* venues-mosaic — the mosaic of a group's venues. Verstka from the wave-1 mockups: the full-bleed
   card and the district rule are BLOCKS-CSS of site-editorial-01-hub-md.html, the photo-on-top card
   of `grid` is site-culinary-01-hub-md.html. Written entirely in var(--site-*), single breakpoint. */

.sb-venues-mosaic__inner{max-width:var(--site-w-page);margin-inline:auto}
.sb-venues-mosaic__group + .sb-venues-mosaic__group{margin-top:var(--site-space-5)}
.sb-venues-mosaic__district{
  display:flex;align-items:center;gap:var(--site-space-3);
  margin:var(--site-space-5) 0 var(--site-space-3);
  font-size:var(--site-h3);line-height:1;color:var(--site-ink);
}
.sb-venues-mosaic__district::after{content:"";flex:1;height:1px;background:var(--site-line)}
.sb-venues-mosaic__grid{display:grid;gap:var(--site-gap)}

/* The card is the doorway: the cover fills it, a double scrim carries the copy, and the brand's own
   accent arrives as an inline --site-accent (View.tsx), so the placeholder gradient of a venue with
   no photograph is that venue's colour rather than the site's. */
.sb-venues-mosaic__card{
  position:relative;overflow:hidden;isolation:isolate;display:flex;align-items:flex-end;
  min-height:calc(var(--site-space-8) * 2 + var(--site-space-1));padding:var(--site-space-4);
  border:1px solid var(--site-hairline);border-radius:var(--site-r-card);
}
.sb-venues-mosaic__ph{position:absolute;inset:0;z-index:0;border-radius:0}
.sb-venues-mosaic__card::after{content:"";position:absolute;inset:0;background:var(--site-scrim),var(--site-scrim);z-index:1}
.sb-venues-mosaic__in{position:relative;z-index:2;min-width:0;display:flex;flex-direction:column;gap:var(--site-space-1);color:var(--site-on-accent)}
/* THE KICKER IS CLAMPED TO TWO LINES, and the reason is a real page rather than a preference.
   The kicker prints the venue's own `StorefrontTheme.description` — a field a client fills in for
   his own storefront, where it has a paragraph's room. In this card it sits in the micro face above
   the name, and one venue whose description ran to a sentence ("Modern Greek restaurant blending
   Greece, Italy, Thailand and the French Riviera — mezze, pasta, fresh cheeses and seafood
   specialties") pushed its own name five lines down while its neighbours kept theirs on one: the row
   of doors lost its baseline and read as broken. The client's own text is not ours to shorten, so
   the CARD clamps. Two lines, not one: a two-part tagline ("All-day breakfast · Boat Avenue,
   Laguna") is the ordinary case and must survive whole. The full text stands unclamped on the
   venue's own storefront, one click away through this very card. */
.sb-venues-mosaic__k{
  font-size:var(--site-micro);font-weight:700;letter-spacing:var(--site-micro-ls);
  text-transform:uppercase;opacity:.9;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;
  overflow:hidden;
}
.sb-venues-mosaic__nm{
  font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-weight:var(--site-display-weight);
  font-size:var(--site-h2);line-height:var(--site-display-lh);
  letter-spacing:var(--site-display-ls);text-transform:var(--site-display-case);
}
.sb-venues-mosaic__meta{display:flex;flex-wrap:wrap;align-items:center;gap:var(--site-space-2);font-size:var(--site-small);opacity:.82;margin-top:var(--site-space-1)}
.sb-venues-mosaic__part + .sb-venues-mosaic__part::before{content:"·";margin-right:var(--site-space-2)}
.sb-venues-mosaic__arw{
  position:absolute;right:var(--site-space-4);top:var(--site-space-4);z-index:2;
  color:var(--site-on-accent);font-family:var(--site-display);font-stretch:var(--site-display-stretch,normal);font-size:var(--site-h3);line-height:1;
}

/* `grid` — the photograph on top and the copy under it on the page's own paper, the idiom the
   culinary hub is drawn in. Same tree: the frame simply stops being the card's background. */
.sb-venues-mosaic[data-variant="grid"] .sb-venues-mosaic__card{
  display:grid;align-content:start;gap:var(--site-space-3);padding:0;
  background:var(--site-surface);border-color:var(--site-line);
}
.sb-venues-mosaic[data-variant="grid"] .sb-venues-mosaic__ph{position:static;aspect-ratio:var(--site-ratio-card)}
.sb-venues-mosaic[data-variant="grid"] .sb-venues-mosaic__card::after{content:none}
.sb-venues-mosaic[data-variant="grid"] .sb-venues-mosaic__in{color:var(--site-ink);padding:0 var(--site-space-4) var(--site-space-4)}
.sb-venues-mosaic[data-variant="grid"] .sb-venues-mosaic__k{color:var(--site-accent);opacity:1}
.sb-venues-mosaic[data-variant="grid"] .sb-venues-mosaic__nm{font-size:var(--site-h3)}
.sb-venues-mosaic[data-variant="grid"] .sb-venues-mosaic__meta{color:var(--site-muted);opacity:1}
.sb-venues-mosaic[data-variant="grid"] .sb-venues-mosaic__arw{color:var(--site-accent)}

/* `list` — a thumbnail, the name, the address and the hours ruled into rows. */
.sb-venues-mosaic[data-variant="list"] .sb-venues-mosaic__grid{gap:0;border-top:1px solid var(--site-line)}
.sb-venues-mosaic[data-variant="list"] .sb-venues-mosaic__card{
  min-height:0;padding:var(--site-space-4) 0;gap:var(--site-space-4);align-items:center;
  border:0;border-bottom:1px solid var(--site-hairline);border-radius:0;background:transparent;
}
.sb-venues-mosaic[data-variant="list"] .sb-venues-mosaic__ph{
  position:static;flex:none;width:calc(var(--site-space-8) + var(--site-space-4));
  aspect-ratio:var(--site-ratio-tile);border-radius:var(--site-r-media);
}
.sb-venues-mosaic[data-variant="list"] .sb-venues-mosaic__card::after{content:none}
.sb-venues-mosaic[data-variant="list"] .sb-venues-mosaic__in{flex:1;color:var(--site-ink);order:1}
.sb-venues-mosaic[data-variant="list"] .sb-venues-mosaic__k{color:var(--site-accent);opacity:1}
.sb-venues-mosaic[data-variant="list"] .sb-venues-mosaic__nm{font-size:var(--site-h4)}
.sb-venues-mosaic[data-variant="list"] .sb-venues-mosaic__meta{color:var(--site-muted);opacity:1}
.sb-venues-mosaic[data-variant="list"] .sb-venues-mosaic__arw{position:static;order:2;margin-left:auto;color:var(--site-faint)}

@media (min-width:900px){
  /* `columns_d` — the author's own answer, printed as an attribute rather than an inline size, so
     the number stays a css decision and the markup stays the same for every value. */
  .sb-venues-mosaic__grid[data-columns="2"]{grid-template-columns:repeat(2,1fr)}
  .sb-venues-mosaic__grid[data-columns="3"]{grid-template-columns:repeat(3,1fr)}
  .sb-venues-mosaic__grid[data-columns="4"]{grid-template-columns:repeat(4,1fr)}
  .sb-venues-mosaic__card{min-height:calc(var(--site-space-8) * 4);padding:var(--site-space-5)}
  .sb-venues-mosaic[data-variant="grid"] .sb-venues-mosaic__card{min-height:0;padding:0}
  .sb-venues-mosaic[data-variant="list"] .sb-venues-mosaic__grid{grid-template-columns:1fr}
  .sb-venues-mosaic[data-variant="list"] .sb-venues-mosaic__card{min-height:0;padding:var(--site-space-4) 0}
}
