@layer reset, base, layout, components, theme;

/* Structural tokens: spacing, measure and chrome sizes. Colour and type scale
   are the theme's job, so they live in themes/<name>/theme.css. The --space-*
   ladder is the one scripts/css-audit.py resolves when checking box insets. */
:root {
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 2.75rem;
  --space-8: 4rem;
  --space-9: 5.5rem;

  --gutter: var(--space-5);
  --measure-text: 38rem;
  --measure-wide: 74rem;
  --section-y: clamp(3rem, 2rem + 5vw, 5.5rem);

  --header-h: 4.25rem;

  /* Sticky chrome contract. Nothing below the header may hardcode a height, do
     arithmetic on one, or measure the header at runtime — CSS cannot stack
     sticky boxes automatically (css-position-3: "Multiple sticky positioned
     boxes in the same container are offset independently, and therefore might
     overlap"), so a shared number has to exist. It exists here, once.

     --chrome-h    how far down the viewport the header's PAINT reaches. The
                   header owns it: whichever nav module changes the header's
                   shape restates this in the same file, and nobody else does.
                   The paint, not the box — a floating bar's box carries
                   transparent inset the eye does not read as header, and
                   charging that to the chrome is a phantom gap.
     --chrome-gap  air between the chrome and the first thing under it. A pure
                   design decision, deliberately not folded into --chrome-h,
                   because mixing a measurement with a preference is what makes
                   spacing untunable. This is the knob. Turn it here.
     --below-chrome the first y that clears the chrome. Every sticky rail and
                   every anchor offset uses this verbatim.

     Adding a sticky element? `top: var(--below-chrome)`. That is the whole API,
     and it stays correct when a theme swaps the nav for a different shape. */
  /* The colour the page ends on. Both the footer and the dock-clearance
     strip below it read this, so a theme that repaints the footer moves
     the strip with it by setting this one property instead of two. */
  --footer-ground: var(--ink-deep);

  --chrome-h: var(--header-h);
  --chrome-gap: 0rem;
  --below-chrome: calc(var(--chrome-h) + var(--chrome-gap));
  /* Sticky jump control under the header. Mobile = the closed <details> field;
     desktop = one pill row. site.js overwrites --jump-h with the measured height. */
  --menu-jump-h: 4.5rem;
  /* Apple HIG / WCAG 2.5.5 enhanced: stand-alone controls ≥ 44px. */
  --touch-min: 2.75rem;
  /* Floating pill + 12px inset + capped safe-area. Constant, never toggled. */
  --dock-clearance: 5.25rem;

  --radius-sm: 0.375rem;
  --radius-md: 0.75rem;
  --radius-lg: 1.25rem;
  --radius-pill: 999px;

  /* How a photograph's corners look, in one place: photo surfaces consume this
     and never pick their own. Three of them had picked three different answers,
     so no theme could restyle them together. It fixes the value, not the guest
     list — a full-bleed hero still takes no radius (a corner cut against the
     viewport edge reads as a mistake), and a 4rem thumbnail may keep the
     smaller one. */
  --radius-media: var(--radius-md);
}

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

  /* :where() keeps specificity at zero, so component rules never need to fight
     the reset. A blanket `* { margin: 0 }` would also hit form controls. */
  :where(body, h1, h2, h3, h4, p, figure, blockquote, dl, dt, dd, ul, ol) {
    margin: 0;
  }

  :where(ul, ol) {
    padding-left: 0;
    list-style: none;
  }

  html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    scroll-padding-top: calc(var(--below-chrome) + var(--space-4));
  }

  body {
    min-height: 100dvh;
  }

  :where(img, picture, video, svg) {
    display: block;
    max-width: 100%;
  }

  :where(input, button, textarea, select) {
    font: inherit;
    color: inherit;
  }

  :where(button) {
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
  }

  :where(a) {
    color: inherit;
  }

  :where(summary) {
    cursor: pointer;
  }

  :where(summary)::-webkit-details-marker {
    display: none;
  }

  :where(h1, h2, h3, h4) {
    font-weight: inherit;
    font-size: inherit;
    text-wrap: balance;
  }

  :where(p, li, dd, figcaption) {
    text-wrap: pretty;
    overflow-wrap: break-word;
  }

  /* Without this every tap waits ~300ms for a possible double-tap. */
  :where(a, button, summary, label, select, [role="button"]) {
    touch-action: manipulation;
  }

  :where(:focus-visible) {
    outline: 3px solid var(--focus);
    outline-offset: 2px;
  }
}

@layer base {
  body {
    /* The dock clearance below is outside every section and outside the
       footer, so the page ground cannot live here: on mobile it painted a
       pale strip under the ink footer, around the floating dock. The ground
       moves to <main>; body takes the footer's colour so the reserved space
       reads as part of the footer instead of as a gap after it. */
    background: var(--footer-ground);
    color: var(--text);
    font-family: var(--font-body);
    font-size: var(--step-0);
    line-height: 1.6;
    /* Room for the mobile action bar so it never covers the last element. */
    padding-bottom: var(--dock-clearance);
  }

  main {
    background: var(--sand);
  }

  .skip-link {
    position: fixed;
    z-index: 60;
    top: var(--space-2);
    left: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-sm);
    background: var(--ink);
    color: var(--sand);
    /* Moves via transform, not `top`, so it does not force layout each frame. */
    transform: translateY(-200%);
    transition: transform 180ms ease;
  }

  .skip-link:focus-visible {
    transform: translateY(0);
  }

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

  a {
    text-underline-offset: 0.18em;
  }

  .link {
    color: var(--sea-deep);
    text-decoration-thickness: from-font;
    transition: color 180ms ease;
  }

  .link:hover {
    color: var(--ink);
  }
}

@layer layout {
  .wrap {
    width: min(100% - var(--gutter) * 2, var(--measure-wide));
    margin-inline: auto;
  }

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

  .section--band {
    background: var(--sand-deep);
  }

  .head {
    max-width: var(--measure-text);
    margin-bottom: var(--space-6);
  }

  .head__lead {
    margin-top: var(--space-3);
    color: var(--text-muted);
    font-size: var(--step-1);
  }

  .eyebrow {
    margin-bottom: var(--space-2);
    color: var(--accent-ink);
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
  }

  .h2 {
    font-family: var(--font-display);
    font-size: var(--step-3);
    line-height: 1.08;
  }

  .h3 {
    font-family: var(--font-display);
    font-size: var(--step-2);
    line-height: 1.15;
  }
}

@layer components {
  /* ---------------------------------------------------------------- images */

  /* `<picture>` is inline by default, so a child sized with height:100% would
     collapse it to the image's natural height and leave a colour gap. */
  .pic {
    display: block;
    width: 100%;
    height: 100%;
  }

  .pic > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* ---------------------------------------------------------------- buttons */

  .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 3rem;
    padding: var(--space-3) var(--space-5);
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    font-size: var(--step-0);
    font-weight: 600;
    line-height: 1.2;
    text-decoration: none;
    transition: background-color 180ms ease, border-color 180ms ease,
      color 180ms ease, transform 180ms ease;
  }

  .btn:active {
    transform: translateY(1px);
  }

  .btn--primary {
    background: var(--sea);
    color: var(--surface);
  }

  .btn--primary:hover {
    background: var(--sea-deep);
  }

  .btn--ghost {
    border-color: var(--sea);
    color: var(--sea-deep);
  }

  .btn--ghost:hover {
    background: var(--sea-tint);
  }

  /* ---------------------------------------------------------------- header */

  .header {
    position: sticky;
    z-index: 40;
    top: 0;
    background: var(--ink);
    color: var(--sand);
  }

  .header__bar {
    display: flex;
    gap: var(--space-4);
    align-items: center;
    min-height: var(--header-h);
  }

  .brand {
    display: inline-flex;
    gap: var(--space-3);
    align-items: center;
    margin-right: auto;
    text-decoration: none;
  }

  .brand__mark {
    display: grid;
    flex: 0 0 auto;
    place-items: center;
    width: 2.5rem;
    height: 2.5rem;
    border: 1px solid var(--accent);
    border-radius: 50%;
    color: var(--accent);
    font-family: var(--font-display);
    font-size: var(--step-0);
    letter-spacing: 0.04em;
  }

  .brand__mark--lg {
    width: 3.5rem;
    height: 3.5rem;
    font-size: var(--step-1);
  }

  .brand__logo {
    display: block;
    flex: 0 0 auto;
    width: 2.5rem;
    height: 2.5rem;
    object-fit: contain;
  }

  .brand__logo--lg {
    width: 4.5rem;
    height: 4.5rem;
    margin-inline: auto;
  }

  .brand__text {
    display: grid;
  }

  .brand__name {
    font-family: var(--font-display);
    font-size: var(--step-1);
    line-height: 1.1;
  }

  .brand__place {
    color: var(--sand-dim);
    font-size: var(--step--1);
    letter-spacing: 0.1em;
    text-transform: uppercase;
  }

  .header__toggle {
    display: grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    border-radius: var(--radius-sm);
    color: inherit;
  }

  .header__toggle-bars {
    position: relative;
    display: block;
    width: 1.25rem;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
    transition: background-color 180ms ease;
  }

  .header__toggle-bars::before,
  .header__toggle-bars::after {
    content: "";
    position: absolute;
    left: 0;
    width: 100%;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
    transition: transform 180ms ease;
  }

  .header__toggle-bars::before {
    top: -6px;
  }

  .header__toggle-bars::after {
    top: 6px;
  }

  /* Native popover has no open class on the invoker. :has() is the state. */
  .header:has(.nav:popover-open) .header__toggle-bars {
    background: transparent;
  }

  .header:has(.nav:popover-open) .header__toggle-bars::before {
    transform: translateY(6px) rotate(45deg);
  }

  .header:has(.nav:popover-open) .header__toggle-bars::after {
    transform: translateY(-6px) rotate(-45deg);
  }

  .header__cta {
    display: none;
  }

  /* audit-ok: chip frame only; 44px target is on .lang__link */
  .lang {
    display: inline-flex;
    flex: 0 0 auto;
    gap: var(--space-1);
    align-items: center;
    height: 2.5rem;
    padding: var(--space-1);
    border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
    border-radius: var(--radius-sm);
    white-space: nowrap;
  }

  .lang__link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.5rem;
    min-height: 2.2rem;
    padding: 0 var(--space-2);
    border-radius: calc(var(--radius-sm) - 2px);
    color: inherit;
    font-size: var(--step--1);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-decoration: none;
  }

  a.lang__link:hover {
    background: color-mix(in srgb, currentColor 12%, transparent);
  }

  .lang__link.is-current {
    background: var(--sand);
    color: var(--ink);
  }

  /* ---------------------------------------------------------------- nav */

  /* Sheet under the header, not over it. A second close control in the top
     layer sits on the hamburger; the popover leaves the top layer and the
     same pointerup hits the toggle, so the menu flashes shut and open.
     Closed state stays UA `display: none`. Do not transition display/overlay
     on the way out — that keeps a full box in the page after top-layer. */
  .nav {
    position: fixed;
    inset: var(--below-chrome) 0 auto;
    width: 100%;
    max-width: none;
    height: fit-content;
    max-height: calc(100dvh - var(--below-chrome));
    margin: 0;
    padding: var(--space-5) var(--gutter);
    overflow: auto;
    border: 0;
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    background: var(--ink);
    color: var(--sand);
    overscroll-behavior: contain;
  }

  .nav:popover-open {
    display: grid;
    align-content: start;
    gap: var(--space-4);
    transform: translateY(0);
    transition: transform 200ms ease;
  }

  @starting-style {
    .nav:popover-open {
      transform: translateY(-0.5rem);
    }
  }

  /* UA ::backdrop is transparent. A painted backdrop is full-viewport in the
     top layer, behind the popover only (MDN Popover API), so it sits on the
     header X and fails WCAG 1.4.11 non-text contrast. The sheet is opaque. */
  .nav::backdrop {
    background: transparent;
  }

  .nav:popover-open .lang {
    justify-self: start;
  }

  .nav__list {
    display: grid;
    gap: var(--space-2);
  }

  .nav__link {
    display: block;
    min-height: 3rem;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-sm);
    font-size: var(--step-1);
    text-decoration: none;
    transition: background-color 180ms ease, color 180ms ease;
  }

  .nav__link:hover {
    background: var(--ink-lift);
    color: var(--accent);
  }

  /* ---------------------------------------------------------------- hero */

  .hero__grid {
    display: grid;
  }

  .hero__media {
    /* The slot owns the ratio; the art-directed sources match it per breakpoint. */
    aspect-ratio: 3 / 2;
    order: -1;
  }

  .hero__copy {
    display: grid;
    justify-items: start;
    gap: var(--space-4);
    width: min(100% - var(--gutter) * 2, var(--measure-wide));
    margin-inline: auto;
    padding-block: var(--space-5);
  }

  .hero__title {
    max-width: 22ch;
    font-family: var(--font-display);
    font-size: var(--step-4);
    line-height: 1.02;
  }

  .hero__lead {
    max-width: var(--measure-text);
    color: var(--text-muted);
    font-size: var(--step-1);
  }

  .hero__actions {
    display: flex;
    flex-wrap: wrap;
    /* The split hero's grid stretches this row to the media column's height;
       keep the buttons at their own height instead of stretching with it. */
    align-items: start;
    gap: var(--space-3);
  }

  .rating {
    display: inline-flex;
    gap: var(--space-2);
    align-items: baseline;
    font-size: var(--step--1);
    text-decoration: none;
  }

  .rating__stars {
    color: var(--accent-ink);
  }

  .rating__value {
    font-size: var(--step-0);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }

  .rating__count {
    color: var(--text-muted);
  }

  /* Fact strip under the hero. Full-bleed band; the list sits in .wrap. */
  .strip {
    padding-block: var(--space-5);
    background: var(--ink);
    color: var(--sand);
  }

  .strip__list {
    display: grid;
    gap: 1px;
  }

  .strip__item {
    display: grid;
    gap: 2px;
    padding: var(--space-3) var(--space-4);
  }

  .strip__label {
    color: var(--accent);
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
  }

  .strip__value {
    font-size: var(--step-0);
    font-variant-numeric: tabular-nums;
  }

  /* ---------------------------------------------------------------- story */

  .story__grid {
    display: grid;
    gap: var(--space-6);
  }

  .story__copy {
    display: grid;
    gap: var(--space-4);
    align-content: start;
    max-width: var(--measure-text);
  }

  .story__notes {
    display: grid;
    gap: var(--space-2);
    padding: var(--space-4);
    border-left: 3px solid var(--accent);
    background: var(--surface);
    font-size: var(--step--1);
  }

  .story__media {
    position: relative;
    aspect-ratio: 3 / 4;
    max-width: 26rem;
    margin-inline: auto;
    border-radius: var(--radius-media);
    overflow: hidden;
  }

  .story__caption {
    padding: var(--space-3) var(--space-4);
    background: var(--ink);
    color: var(--sand);
    font-size: var(--step--1);
  }

  /* ---------------------------------------------------------------- picks */

  .picks__grid {
    display: grid;
    gap: var(--space-6);
    /* auto-fit avoids the half-viewport card jump a rigid 3/2/1 ladder causes. */
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  }

  .pick {
    display: grid;
    container-type: inline-size;
    gap: var(--space-4);
    /* A grid item's automatic minimum size is its content, so an image can push
       the column wider than its track. minmax(0, ...) above plus this fixes it. */
    min-width: 0;
  }

  .pick__media {
    aspect-ratio: 4 / 3;
    border-radius: var(--radius-media);
    overflow: hidden;
  }

  /* Flex, not grid: auto grid rows stretch, which pushed the name of a card
     with a shorter note away from its image. Here the name stays under the
     image and only the price is pushed down. */
  .pick__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
  }

  .pick__name {
    font-family: var(--font-display);
    font-size: var(--step-2);
    line-height: 1.1;
  }

  .pick__note {
    color: var(--text-muted);
  }

  .pick__price {
    /* Prices line up across cards whose notes run to different lengths. */
    margin-block-start: auto;
    color: var(--sea-deep);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }

  @container (min-width: 22rem) {
    .pick__name {
      font-size: var(--step-2);
    }
  }

  /* ---------------------------------------------------------------- menu */

  /* Compact sticky jump: a <details> of links, not a <select>. Focusing a form
     control inside stuck sticky chrome scrolls the page to its unstuck position
     in Chromium (csswg-drafts#3009), and a select that navigates on change fails
     WCAG 3.2.2. Hidden on desktop, where the pill rail owns this slot.
     See docs/patterns/interactions/P-menu-jump-disclosure.md. */
  .menu__jump {
    position: sticky;
    z-index: 30;
    top: var(--below-chrome);
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-2);
    background: var(--sand);
  }

  /* Sticky controls dock --chrome-gap below the header, and page content
     scrolls through that gap. A scrim in the page ground covers it: solid
     where it meets the control so nothing shows through, fading out above so
     there is no hard edge against the header. Zero height, and therefore
     invisible, on any site that leaves --chrome-gap at its 0rem default. */
  .menu__jump::before,
  .menu__pills::before {
    content: "";
    position: absolute;
    z-index: -1;
    inset: auto 0 100%;
    height: calc(var(--chrome-gap) + 0.5rem);
    background: linear-gradient(to top, var(--sand) 58%, transparent);
    pointer-events: none;
  }

  .menu__jump-field {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: var(--space-3);
    min-height: var(--touch-min);
    /* ≥12px inset: css-audit bordered-box rule (section 7b). */
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    background: var(--surface);
    cursor: pointer;
    list-style: none;
  }

  .menu__jump-field::-webkit-details-marker {
    display: none;
  }

  .menu__jump[open] .menu__jump-field {
    border-color: var(--sea);
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
  }

  .menu__jump-icon {
    display: grid;
    place-items: center;
    width: 2.375rem;
    height: 2.375rem;
    border-radius: var(--radius-sm);
    background: var(--sea-tint);
    color: var(--sea-deep);
  }

  .menu__jump-copy {
    min-width: 0;
  }

  .menu__jump-label {
    display: block;
    margin: 0 0 2px;
    color: var(--accent-ink);
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
  }

  .menu__jump-value {
    display: block;
    overflow: hidden;
    color: var(--ink);
    font-size: 1.02rem;
    font-weight: 600;
    line-height: 1.25;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .menu__jump-go {
    display: grid;
    place-items: center;
    width: var(--touch-min);
    height: var(--touch-min);
    border-radius: var(--radius-sm);
    background: var(--sea);
    color: var(--sand);
    transition: transform 180ms ease;
  }

  .menu__jump[open] .menu__jump-go {
    transform: rotate(180deg);
  }

  .menu__jump-list {
    margin: 0;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--sea);
    border-top: 0;
    border-radius: 0 0 var(--radius-md) var(--radius-md);
    background: var(--surface);
    max-height: min(60dvh, 24rem);
    overflow: auto;
    overscroll-behavior: contain;
  }

  .menu__jump-option {
    display: flex;
    align-items: center;
    min-height: var(--touch-min);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    color: var(--ink);
    font-weight: 600;
    text-decoration: none;
  }

  .menu__jump-option:hover,
  .menu__jump-option:focus-visible {
    background: var(--sea-tint);
    color: var(--sea-deep);
  }

  /* Desktop pills: hidden on mobile, where the jump field owns the sticky slot. */
  .menu__pills {
    display: none;
  }

  .menu__pills-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  .pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-height: var(--touch-min);
    padding: var(--space-2) var(--space-4);
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    background: var(--surface);
    font-size: var(--step--1);
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    text-decoration: none;
    transition: background-color 180ms ease, border-color 180ms ease, color 180ms ease;
  }

  .pill:hover {
    border-color: var(--sea);
    background: var(--sea-tint);
    color: var(--sea-deep);
  }

  .menu__list {
    display: grid;
    gap: var(--space-3);
  }

  /* The inset lives on .cat__head and .row. Padding on the container would inset
     the zebra stripes from the card edge, the bug the menu pattern warns about. */
  /* audit-ok: inset is on the children, by design */
  .cat {
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-md);
    background: var(--surface);
    overflow: hidden;
    /* Only the jump bar: html's scroll-padding-top already clears the header. */
    scroll-margin-top: calc(var(--jump-h, var(--menu-jump-h)) + var(--space-3));
  }

  /* Focus stops, not only jump targets: without this, tabbing into the menu
     parks focus under the sticky pills/jump bar (WCAG 2.4.11, same as .cat). */
  .menu :is(a, button, summary, input, select) {
    scroll-margin-top: calc(var(--jump-h, var(--menu-jump-h)) + var(--space-3));
  }

  /* Category header is the primary tap target: ≥44px (Apple HIG / WCAG 2.5.5). */
  .cat__head {
    display: flex;
    gap: var(--space-4);
    align-items: center;
    justify-content: space-between;
    min-height: var(--touch-min);
    padding: var(--space-4) var(--space-5);
    background: var(--sea-tint);
    cursor: pointer;
    list-style: none;
    transition: background-color 180ms ease;
  }

  .cat__head::-webkit-details-marker {
    display: none;
  }

  .cat__head:hover {
    background: var(--sea-tint-deep);
  }

  .cat__title {
    font-family: var(--font-display);
    font-size: var(--step-2);
    line-height: 1.1;
  }

  .cat__count {
    color: var(--text-muted);
    font-size: var(--step--1);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  /* Ledger rows: not interactive, so they stay denser than 44px. */
  .rows {
    container-type: inline-size;
    padding: 0;
  }

  .row {
    display: flex;
    gap: var(--space-4);
    align-items: baseline;
    padding: var(--space-3) var(--space-5);
  }

  .row:nth-child(even) {
    background: var(--zebra);
  }

  .row__name {
    flex: 1 1 auto;
    min-width: 0;
    font-weight: 600;
  }

  .row__desc {
    display: block;
    color: var(--text-muted);
    font-size: var(--step--1);
    font-weight: 400;
  }

  .row__price {
    flex: 0 0 auto;
    color: var(--sea-deep);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  /* ---------------------------------------------------------------- services

     The services block's list. Deliberately none of the menu chrome above:
     every row is visible, so there is nothing to jump to and nothing to
     count. Cards rather than a ledger because these rows carry a sentence
     each and no price column to align to. */

  .svc-group + .svc-group {
    margin-top: var(--space-7);
  }

  .svc-group__title {
    margin-bottom: var(--space-4);
    font-family: var(--font-display);
    font-size: var(--step-2);
  }

  .svc-list {
    display: grid;
    /* Same auto-fit shape as the other card grids, so a group of three and a
       group of ten sit on one rhythm instead of two. */
    gap: var(--space-3);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .svc {
    display: grid;
    gap: var(--space-1);
    align-content: start;
    padding: var(--space-4);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface);
  }

  .svc__name {
    font-weight: 600;
  }

  .svc__note {
    color: var(--text-muted);
    font-size: var(--step--1);
  }

  .svc__price {
    color: var(--sea-deep);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }

  /* ---------------------------------------------------------------- gallery */

  .gallery__grid {
    display: grid;
    gap: var(--space-3);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  }

  .gallery__cell {
    min-width: 0;
  }

  .tile {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    border-radius: var(--radius-media);
    overflow: hidden;
  }

  .tile > .pic > img {
    transition: transform 220ms ease;
  }

  .tile:hover > .pic > img,
  .tile:focus-visible > .pic > img {
    transform: scale(1.04);
  }

  /* Stage lightbox (P-lightbox-dialog): the photo is the page, chrome sits on
     the edges. Transparent dialog + ::backdrop scrim, not a padded card.
     Load-bearing: `display: grid` lives only on [open]. On the closed dialog
     it beats the UA `display: none`, so the arrows stay on the page and eat
     clicks after close ([Chrome entry/exit](https://developer.chrome.com/blog/entry-exit-animations)).
     `overlay` stays in the transition list so the exit is seen. The dialog
     takes programmatic focus; its close button keeps the visible ring. */
  .lightbox {
    grid-template-columns: var(--touch-min) minmax(0, 1fr) var(--touch-min);
    grid-template-rows: var(--touch-min) minmax(0, 1fr);
    column-gap: var(--space-2);
    row-gap: var(--space-3);
    align-items: center;
    width: 100%;
    max-width: none;
    height: 100%;
    max-height: none;
    margin: 0;
    padding: var(--space-3);
    border: 0;
    background: transparent;
    color: var(--sand);
    overscroll-behavior: contain;
    transform: translateY(0.75rem) scale(0.985);
    transition:
      transform 200ms ease,
      overlay 200ms allow-discrete,
      display 200ms allow-discrete;
  }

  /* audit-ok: dialog takes programmatic focus; close keeps the ring */
  .lightbox:focus {
    outline: none;
  }

  .lightbox[open] {
    display: grid;
    transform: none;
  }

  @starting-style {
    .lightbox[open] {
      transform: translateY(0.75rem) scale(0.985);
    }
  }

  .lightbox::backdrop {
    background: color-mix(in srgb, var(--ink-deep) 92%, transparent);
  }

  .lightbox__count {
    grid-column: 1 / 3;
    grid-row: 1;
    margin: 0;
    color: var(--sand-dim);
    font-size: var(--step--1);
    font-variant-numeric: tabular-nums;
    text-shadow: 0 0 0.4rem var(--ink-deep);
  }

  .lightbox__close,
  .lightbox__step {
    display: grid;
    place-items: center;
    width: var(--touch-min);
    height: var(--touch-min);
    border: 0;
    border-radius: var(--radius-pill);
    color: var(--sand);
    background: color-mix(in srgb, var(--ink-deep) 45%, transparent);
    filter: drop-shadow(0 0 0.35rem var(--ink-deep));
    transition: background-color 180ms ease;
  }

  .lightbox__close {
    grid-column: 3;
    grid-row: 1;
    justify-self: end;
  }

  .lightbox__close:hover,
  .lightbox__step:hover {
    background: color-mix(in srgb, var(--ink-deep) 72%, transparent);
  }

  .lightbox__step--prev {
    grid-column: 1;
    grid-row: 2;
  }

  .lightbox__step--next {
    grid-column: 3;
    grid-row: 2;
  }

  .lightbox__stage {
    grid-column: 2;
    grid-row: 2;
    display: grid;
    min-width: 0;
    min-height: 0;
    margin: 0;
    place-items: center;
  }

  .lightbox__img {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
  }

  /* Native order wizard. Focus stays inside the dialog via showModal(). */
  .order {
    position: relative;
    width: min(92vw, 32rem);
    max-height: 90dvh;
    padding: var(--space-6);
    border: 0;
    border-radius: var(--radius-md);
    background: var(--surface);
    color: var(--text);
    overflow: auto;
    overscroll-behavior: contain;
  }

  .order::backdrop {
    background: var(--scrim-deep);
  }

  .order__close {
    position: absolute;
    top: var(--space-3);
    right: var(--space-3);
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: inherit;
    font-size: var(--step-2);
    line-height: 1;
    cursor: pointer;
  }

  .order__progress {
    margin: 0 var(--space-7) var(--space-2) 0;
    color: var(--text-muted);
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .order__title {
    margin: 0 var(--space-7) var(--space-4) 0;
    font-family: var(--font-display);
    font-size: var(--step-2);
  }

  .order__body {
    display: grid;
    gap: var(--space-4);
  }

  .order__body textarea,
  .order__body input,
  .order__body select {
    width: 100%;
    min-height: 2.75rem;
    padding: var(--space-3);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--sand);
    color: var(--ink);
    font: inherit;
    /* iOS zooms the page on focusing any control under 16px; floor the size. */
    font-size: max(1em, 1rem);
  }

  .order__body textarea {
    min-height: 8rem;
    resize: vertical;
  }

  .order__error:empty {
    display: none;
  }

  .order__error {
    margin: var(--space-3) 0 0;
    color: var(--accent-ink);
    font-size: var(--step--1);
  }

  .order__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    justify-content: flex-end;
    margin-top: var(--space-5);
  }

  .order__summary {
    display: grid;
    gap: var(--space-3);
    margin: 0;
  }

  .order__summary > div {
    display: grid;
    gap: 2px;
  }

  .order__summary dt {
    color: var(--text-muted);
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .order__note {
    color: var(--text-muted);
    font-size: var(--step--1);
  }

  /* ---------------------------------------------------------------- reviews */

  .quotes {
    display: grid;
    gap: var(--space-6);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  }

  .quote {
    display: grid;
    gap: var(--space-3);
    align-content: start;
    min-width: 0;
    padding-inline: var(--space-4);
    border-left: 2px solid var(--accent);
  }

  .quote__text {
    font-family: var(--font-display);
    font-size: var(--step-1);
    line-height: 1.4;
  }

  .quote__by {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: baseline;
    font-size: var(--step--1);
  }

  .quote__author {
    font-weight: 600;
  }

  .quote__role {
    color: var(--text-muted);
  }

  .quote__stars {
    color: var(--accent-ink);
    letter-spacing: 0.1em;
  }

  .reviews__more {
    margin-top: var(--space-6);
  }

  /* A link on its own line is a tap target, not prose: pad it past the 24px
     WCAG 2.2 floor without changing the text size. */
  .reviews__more .link {
    display: inline-block;
    /* audit-ok: sized to the 24px floor at this font size, not to the rhythm */
    padding-block: 0.45rem;
  }

  /* ---------------------------------------------------------------- visit */

  /* Eyebrow + heading (+ optional booking lead) span the section; the two-column
     grid below holds contact details and the map panel (Familija shape). */
  .visit__intro {
    display: grid;
    gap: var(--space-3);
    max-width: var(--measure-text);
    margin-bottom: var(--space-6);
  }

  /* Delivery copy + optional coverage drawing, above Find us. */
  .visit__top--with-map {
    margin-bottom: var(--space-8);
  }

  /* audit-ok: coverage map is the content, not copy needing inset */
  .visit__coverage-map {
    margin: 0;
    overflow: hidden;
    min-width: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    background: var(--surface);
  }

  .visit__coverage-map .pic,
  .visit__coverage-map img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    object-fit: cover;
  }

  .visit__grid {
    display: grid;
    gap: var(--space-6);
  }

  .visit__copy {
    display: grid;
    gap: var(--space-5);
    align-content: start;
  }

  .visit__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
  }

  /* NAP is the left column's primary content; no top rule once the heading
     lives above the grid. */
  .visit__details {
    min-width: 0;
  }

  .visit__panel-title {
    margin-bottom: var(--space-4);
    font-family: var(--font-display);
    font-size: var(--step-2);
  }

  /* One bordered unit: map flush on top, CTA strip below, no inner seam.
     Inset lives on .visit__panel-foot so the iframe can share the container's
     top corners edge-to-edge. */
  /* audit-ok: inset is on the children; map must be flush */
  .visit__panel {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    min-width: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    background: var(--surface);
  }

  /* Media slot: the iframe fills the box edge-to-edge; padding would letterbox it.
     Mobile keeps 4 / 3; desktop drops the ratio so the map absorbs row slack. */
  /* audit-ok: map iframe is the content, not copy needing inset */
  .visit__map {
    position: relative;
    flex: 1 1 auto;
    aspect-ratio: 4 / 3;
    min-height: 12rem;
    overflow: hidden;
    background: var(--surface);
  }

  .visit__map iframe {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
  }

  .visit__panel-foot {
    flex: 0 0 auto;
    padding: var(--space-4) var(--space-5);
  }

  .visit__maps-cta {
    width: 100%;
  }

  .visit__list {
    margin-bottom: var(--space-6);
  }

  .visit__list-title {
    margin-bottom: var(--space-3);
    font-weight: 600;
  }

  .visit__list ul {
    display: grid;
    gap: var(--space-2);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .visit__list li {
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface);
  }

  .visit__map--photo .pic,
  .visit__map--photo img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .nap {
    display: grid;
    gap: var(--space-3);
  }

  .nap > dt {
    color: var(--text-muted);
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
  }

  .nap > dd {
    display: grid;
    gap: 2px;
    font-variant-numeric: tabular-nums;
  }

  .nap__note {
    color: var(--text-muted);
    font-size: var(--step--1);
  }

  /* ---------------------------------------------------------------- faq */

  /* One reading measure, centred by .wrap's own auto margins. Nothing in this
     section is wide — the head and the questions are both one measure — so a
     wide inner just parked the whole column against the left of a container
     twice its width. Capping the inner is what centres it; capping the children
     individually cannot, and reads as deliberate left alignment. */
  .faq__inner {
    max-width: var(--measure-text);
  }

  .faq__list {
    display: grid;
    gap: var(--space-2);
  }

  .qa {
    border-bottom: 1px solid var(--line);
  }

  .qa__q {
    display: flex;
    gap: var(--space-4);
    align-items: baseline;
    justify-content: space-between;
    padding: var(--space-4) var(--space-3);
    font-size: var(--step-1);
    font-weight: 600;
    transition: color 180ms ease;
  }

  .qa__q::after {
    content: "+";
    color: var(--accent-ink);
    font-size: var(--step-2);
    line-height: 1;
  }

  .qa[open] > .qa__q::after {
    content: "\2212";
  }

  .qa__q:hover {
    color: var(--sea-deep);
  }

  .qa__a {
    padding: 0 var(--space-3) var(--space-4);
    color: var(--text-muted);
  }

  /* ---------------------------------------------------------------- cta */

  .cta {
    padding-block: var(--section-y);
    background: var(--ink);
    color: var(--sand);
  }

  .cta__inner {
    display: grid;
    justify-items: center;
    gap: var(--space-4);
    text-align: center;
  }

  .cta__title {
    max-width: 26ch;
    font-family: var(--font-display);
    font-size: var(--step-3);
    line-height: 1.06;
  }

  .cta__lead {
    max-width: var(--measure-text);
    color: var(--sand-dim);
  }

  .cta__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    justify-content: center;
  }

  .cta .btn--ghost {
    border-color: var(--sand-dim);
    color: var(--sand);
  }

  .cta .btn--ghost:hover {
    background: var(--ink-lift);
  }

  /* ---------------------------------------------------------------- footer */

  .footer {
    padding-block: var(--space-8) var(--space-6);
    background: var(--footer-ground);
    color: var(--sand);
  }

  .footer__inner {
    display: grid;
    gap: var(--space-7);
  }

  .footer__brand {
    display: grid;
    justify-items: center;
    gap: var(--space-3);
    text-align: center;
  }

  .footer__name {
    font-family: var(--font-display);
    font-size: var(--step-2);
  }

  .footer__blurb {
    max-width: 44ch;
    color: var(--sand-dim);
    font-size: var(--step--1);
  }

  .footer__socials {
    display: flex;
    gap: var(--space-2);
  }

  .footer__social {
    display: grid;
    place-items: center;
    width: var(--touch-min);
    height: var(--touch-min);
    color: var(--sand-dim);
    transition: color 180ms ease;
  }

  .footer__social:hover {
    color: var(--sand);
  }

  .footer__social svg {
    width: var(--step-1);
    height: var(--step-1);
  }

  .footer__cols {
    display: grid;
    gap: var(--space-6);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
    text-align: center;
  }

  .footer__title {
    margin-bottom: var(--space-3);
    color: var(--accent);
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
  }

  .footer__list {
    display: grid;
    gap: var(--space-2);
  }

  .footer__link {
    display: inline-block;
    padding-block: var(--space-1);
    color: var(--sand-dim);
    text-decoration: none;
    transition: color 180ms ease;
  }

  .footer__link:hover {
    color: var(--sand);
    text-decoration: underline;
  }

  .footer__oib {
    color: var(--sand-dim);
    font-size: var(--step--1);
    text-align: center;
  }

  .footer__fine {
    padding-top: var(--space-5);
    border-top: 1px solid var(--ink-lift);
    color: var(--sand-dim);
    font-size: var(--step--1);
    text-align: center;
  }

  /* ---------------------------------------------------------------- dock */

  /* Floating pill, inset from the edges. Pointer-events only on the inner so
     the full-bleed positioning layer does not steal taps. */
  .dock {
    position: fixed;
    z-index: 50;
    inset: auto 0 0;
    padding: 0 var(--space-3)
      max(var(--space-2), min(env(safe-area-inset-bottom, 0px), var(--space-3)));
    pointer-events: none;
    visibility: hidden;
    transform: translateY(calc(100% + 0.375rem));
    transition: transform 200ms ease, visibility 200ms;
  }

  .dock.is-visible {
    visibility: visible;
    transform: translateY(0);
  }

  /* The fixed dock covers the viewport's bottom edge: keep scrolled-to focus
     stops above it (WCAG 2.4.11). Cleared at 64rem with the dock itself. */
  html {
    scroll-padding-bottom: var(--dock-clearance);
  }

  .dock.is-visible .dock__inner {
    pointer-events: auto;
  }

  .dock__inner {
    display: flex;
    gap: var(--space-2);
    align-items: center;
    justify-content: space-between;
    max-width: 25rem;
    margin-inline: auto;
    /* audit-ok: 5px around the 2.75rem items keeps the pill at 54px; --space-2 gives 60px */
    padding: 0.3125rem var(--space-3);
    border: 1px solid color-mix(in srgb, var(--ink) 18%, transparent);
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--surface) 97%, transparent);
    box-shadow:
      0 8px 28px color-mix(in srgb, var(--ink-deep) 18%, transparent),
      0 1px 0 color-mix(in srgb, var(--surface) 85%, transparent) inset;
    backdrop-filter: blur(12px);
  }

  .dock__item {
    display: flex;
    flex: 1 1 0;
    flex-direction: column;
    gap: 2px;
    align-items: center;
    justify-content: center;
    min-width: 2.75rem;
    min-height: 2.75rem;
    padding: var(--space-1) 2px;
    border: 0;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--ink);
    font: inherit;
    cursor: pointer;
    text-decoration: none;
    transition: background-color 150ms ease, transform 150ms ease;
  }

  .dock__item:active {
    background: var(--sand-deep);
    transform: scale(0.96);
  }

  .dock__icon {
    display: grid;
    place-items: center;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--ink) 8%, transparent);
    color: var(--sea);
  }

  .dock__icon svg {
    display: block;
    width: 1.125rem;
    height: 1.125rem;
  }

  .dock__label {
    color: var(--sea-deep);
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    line-height: 1.1;
  }

  .dock__item--primary {
    flex: 0 1 auto;
    min-width: 5.5rem;
    margin-inline: 1px;
    /* audit-ok: optical pad for the icon+label stack; min-height already sets the target */
    padding: 0.4375rem var(--space-4);
    background: linear-gradient(180deg, var(--sea) 0%, var(--sea-deep) 100%);
    box-shadow: 0 4px 14px color-mix(in srgb, var(--sea) 34%, transparent);
    color: var(--surface);
  }

  .dock__item--primary .dock__icon {
    background: color-mix(in srgb, var(--ink-deep) 12%, transparent);
    color: var(--surface);
  }

  .dock__item--primary .dock__label {
    color: var(--surface);
    font-size: 0.72rem;
  }

  .dock__item--primary:active {
    background: var(--sea-deep);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--sea) 28%, transparent);
  }

  /* ---------------------------------------------------------------- doc pages */

  .doc {
    padding-block: var(--section-y);
  }

  .doc__inner {
    display: grid;
    gap: var(--space-4);
    max-width: var(--measure-text);
  }

  .doc__title {
    font-family: var(--font-display);
    font-size: var(--step-3);
    line-height: 1.06;
  }

  .doc__h2 {
    margin-top: var(--space-4);
    font-family: var(--font-display);
    font-size: var(--step-2);
  }

  .doc__meta {
    color: var(--text-muted);
    font-size: var(--step--1);
  }

  .doc__list {
    display: grid;
    gap: var(--space-2);
    padding-left: var(--space-5);
    list-style: disc;
  }

  .doc__back {
    margin-top: var(--space-5);
  }

  /* ---------------------------------------------------------------- desktop */

  @media (min-width: 48rem) {
    .hero__media {
      aspect-ratio: 16 / 9;
    }

    .hero__copy {
      padding-block: var(--space-7);
    }

    .strip__list {
      grid-auto-columns: 1fr;
      grid-auto-flow: column;
    }

    .strip__item {
      border-left: 1px solid var(--ink-lift);
    }

    .strip__item:first-child {
      border-left: 0;
    }
  }

  @media (min-width: 64rem) {
    .header__toggle {
      display: none;
    }

    .header__cta {
      display: inline-flex;
    }

    /* Beats the UA `[popover]:not(:popover-open) { display: none }` rule so the
       same markup is a dropdown on mobile and a plain nav here. */
    .nav {
      position: static;
      display: flex;
      gap: var(--space-3);
      align-items: center;
      width: auto;
      max-width: none;
      height: auto;
      max-height: none;
      margin: 0;
      padding: 0;
      overflow: visible;
      border-radius: 0;
      background: none;
      transform: none;
      transition: none;
    }

    .nav:not(:popover-open),
    .nav:popover-open {
      display: flex;
      transform: none;
      transition: none;
    }

    .nav .lang {
      order: 1;
    }

    .nav__list {
      display: flex;
      gap: var(--space-2);
    }

    .nav__link {
      min-height: 2.5rem;
      padding: var(--space-2) var(--space-3);
      font-size: var(--step-0);
    }

    .hero__grid {
      grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
      align-items: stretch;
    }

    .hero__media {
      aspect-ratio: auto;
      order: 0;
      min-height: 32rem;
    }

    .hero__copy {
      width: auto;
      margin: 0;
      padding: var(--space-9) var(--space-7) var(--space-9)
        max(var(--gutter), calc((100vw - var(--measure-wide)) / 2));
    }

    .story__grid {
      grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
      gap: var(--space-8);
      align-items: start;
    }

    /* Contact details vs map panel. Narrower copy (1fr) / wider map (1.2fr);
       equal-height stretch lets the map fill the row without a dead band. */
    .visit__top--with-map {
      display: grid;
      grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
      gap: var(--space-8);
      align-items: start;
    }

    .visit__top--with-map .visit__intro {
      margin-bottom: 0;
    }

    .visit__top--with-map .visit__list {
      grid-column: 1;
      margin-bottom: 0;
    }

    .visit__top--with-map .visit__coverage-map {
      grid-column: 2;
      grid-row: 1 / span 2;
    }

    .visit__grid {
      grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
      gap: var(--space-8);
      align-items: stretch;
    }

    .visit__panel {
      min-height: 100%;
    }

    .visit__map {
      aspect-ratio: auto;
      min-height: 14rem;
    }

    .story__media {
      margin-inline: 0;
    }

    /* Desktop: pills; the jump field is for narrow viewports only. */
    .menu__jump {
      display: none;
    }

    .menu__pills {
      display: block;
      position: sticky;
      z-index: 30;
      top: var(--below-chrome);
      margin-bottom: var(--space-5);
      padding-block: var(--space-2);
      background: var(--sand);
    }

    .dock {
      display: none;
    }

    html {
      scroll-padding-bottom: 0;
    }

    body {
      padding-bottom: 0;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .dock {
      transition: none;
      transform: none;
    }

    .menu__jump-go {
      transition: none;
    }
  }
}

/* chrome.placeholder: blur — P-media-blur-up

   Every slot paints a tiny blurred copy of its own photograph until the real
   file arrives, so a scrolled-to image resolves out of its own colours instead
   of flashing the page background.

   There is no reveal to run and nothing to fade. An <img> paints nothing until
   it has decoded, so the backdrop simply shows through and is covered the
   moment the file lands. No opacity, no transition, no state that can strand an
   image invisible if a script never runs.

   The data URI is written per element by core/images.py; a slot without one
   leaves var(--lqip) invalid, which resolves to no background at all. */
@layer components {
  .pic {
    background-image: var(--lqip);
    background-position: center;
    background-size: cover;
  }
}

/* chrome.reveal: wipe — P-reveal-wipe

   The assertive reveal. Each element is unmasked from the top down as it enters
   the viewport, rather than sliding the last few pixels into place.

   Safe by construction, which is the reason to prefer a clip over a fade. The
   resting state — the one an unsupporting browser paints and the one the
   element holds forever if the timeline never runs — is `inset(0)`, meaning no
   clip at all. There is no state in which content ends up hidden, so this
   passes the same test `scripts/design-audit.py` enforces with its ban on an
   `opacity` of zero, without the ban having to know about it.

   Selector: see reveal-settle.css. Same list, same reasons. */
@layer components {
  @supports (animation-timeline: view()) {
    .section:not(.menu) > .wrap > *,
    .section.menu > .wrap > .head {
      animation: wipe linear both;
      animation-timeline: view();
      animation-range: entry 5% entry 80%;
    }

    @keyframes wipe {
      from {
        clip-path: inset(0 0 100% 0);
        transform: translateY(1.5rem);
      }

      to {
        clip-path: inset(0 0 0 0);
        transform: translateY(0);
      }
    }
  }
}

/* chrome.progress: bar — P-scroll-progress

   A hairline across the top of the viewport showing how far down the page the
   reader is. On a single-page site carrying a full menu, that is the one piece
   of orientation the design otherwise withholds.

   Drawn on `body::after` rather than a real element: it is decoration with no
   semantics, and giving it markup would mean an empty div in every page's
   source and an `aria-hidden` to remember. Inside the @supports block only, so
   a browser without scroll timelines paints nothing rather than a bar stuck at
   zero width. */
@layer components {
  @supports (animation-timeline: scroll()) {
    body::after {
      content: "";
      position: fixed;
      z-index: 45;
      inset: 0 0 auto;
      height: 0.1875rem;
      background: var(--accent);
      transform: scaleX(0);
      transform-origin: 0 50%;
      animation: scroll-progress linear both;
      animation-timeline: scroll(root block);
    }

    @keyframes scroll-progress {
      to {
        transform: scaleX(1);
      }
    }

    /* Reduced motion removes the bar. The unlayered 99-motion reset hands
       scroll timelines back to the document timeline, which completes this
       animation instantly and parks the bar at full width: a permanent
       "you are at the end" lie. Carving an exemption into that reset would
       ship progress-bar knowledge to every site, including ones that never
       claimed this module, so the module removes its own paint instead. The
       bar is decoration (no semantics, no markup); the scrollbar still shows
       position. */
    @media (prefers-reduced-motion: reduce) {
      body::after {
        content: none;
      }
    }
  }
}

/* chrome.texture: wash — P-ambient-wash

   A warm pool of light drifting behind every section: monochromatic, low, and
   painted *inside* the section rather than over the page.

   That last part is the whole design. The version this replaced was a fixed
   layer screened over the whole document, which lifts dark values by
   definition — every ground on the page came out brighter. A wash inside the
   section paints above that section's own background and below its copy, so
   the ground keeps its token value at the edges and the text never sits on
   anything the theme did not choose.

   Accessible-gradient guidance for dark grounds is consistent about the shape:
   one hue moving through lightness, kept low, tested at its lightest point
   under the text rather than on average. At the default strength the worst
   case under copy is `--sea` at 20% over the page ground.

   `overflow: clip`, never `hidden`. Clip keeps the pool inside the section
   without creating a scroll container, so a sticky rail inside a section goes
   on sticking (css-best-practices 7e).

   Tune from the theme with --wash-ink, --wash-x and --wash-y. */
@layer components {
  .section {
    --wash-ink: color-mix(in srgb, var(--sea) 20%, transparent);
    --wash-x: 22%;
    --wash-y: 18%;

    position: relative;
    overflow: clip;

    /* Content above the pool. */
    & > .wrap {
      position: relative;
      z-index: 1;
    }

    &::before {
      content: "";
      position: absolute;
      z-index: 0;
      inset: -25% -12%;
      background: radial-gradient(
        ellipse 42% 40% at var(--wash-x) var(--wash-y),
        var(--wash-ink),
        transparent 72%
      );
      pointer-events: none;
      animation: wash-drift 46s ease-in-out infinite alternate;
    }

    /* Each section lights from somewhere else, and the even ones drift against
       the odd, so no two neighbours read as the same gradient. */
    &:nth-of-type(even)::before {
      --wash-x: 78%;
      --wash-y: 30%;

      animation-duration: 61s;
      animation-direction: alternate-reverse;
    }

    &:nth-of-type(3n)::before {
      --wash-x: 50%;
      --wash-y: 84%;
    }
  }

  /* Transform only on a section-sized layer: opacity or filter here would
     re-blend the whole surface every frame (P-ambient-loop rule 2). */
  @keyframes wash-drift {
    from {
      transform: translate3d(-3%, -2%, 0) scale(1);
    }

    to {
      transform: translate3d(4%, 3%, 0) scale(1.12);
    }
  }

  /* Rule 5: `animation: none`, never a 1ms duration on an infinite animation.
     The pools stay where they are — this is a lit room before it is a motion. */
  @media (prefers-reduced-motion: reduce) {
    .section::before {
      animation: none;
    }
  }
}

/* chrome.surface: lit — P-surface-lit

   The house material for every raised surface: menu categories, the menu's
   jump control, the visit panel. One implied light source from above and to
   the left, a hairline of it on the top edge, the fill falling away beneath,
   and a shadow tinted to the ground rather than to black.

   Flat fills with a border are what make a dark interface read as a
   wireframe. This is the rule that stops that, stated once for every surface
   instead of per component.

   It also carries the compact form of the menu's jump control, because the two
   were designed together: the control is a lit card with one line of type on
   it, and splitting them would ship half a look.

   **Nothing here declares a colour.** Every value is a `color-mix()` of a
   token the theme already declares, so a palette swap moves the light with it
   and `scripts/design-audit.py` still sees a palette it knows.

   Selector lists are grouped with `:is()` and shared blocks are nested, which
   is the difference between one module and four near-identical ones. */

/* Registered so the glow's radius can transition: an unregistered custom
   property animates as a discrete swap. Radius, not opacity — a zero-radius
   gradient paints nothing without any rule declaring `opacity: 0`, which
   design-audit refuses on a page that must read without JS. */
@property --glow-r {
  syntax: "<length-percentage>";
  inherits: true;
  initial-value: 0%;
}

@layer components {
  /* ---- the material ----------------------------------------------------- */

  :is(.cat, .menu__jump-field, .menu__jump-list, .visit__panel) {
    --lit: color-mix(in srgb, var(--surface) 10%, transparent);
    --fall: color-mix(in srgb, var(--surface) 7%, transparent);
    --cast: color-mix(in srgb, var(--ink-deep) 30%, transparent);

    /* Where the light falls and how far it reaches. A resting origin, so the
       surface is lit before anything is hovered: most traffic has no cursor,
       and a card that only comes alive under a pointer is dead on a phone.
       A percentage radius, so the pool scales with the surface — a fixed
       length is a wash on a 342px card and a blob on an 1184px one. */
    --px: 22%;
    --py: -10%;
    --glow-r: 42%;

    position: relative;
    background-image: linear-gradient(to bottom, var(--fall) 0%, transparent 52%);
    box-shadow:
      inset 0 1px 0 var(--lit),
      0 0.75rem 1.75rem var(--cast);
  }

  /* The rim: a radial gradient clipped to the border box by two masks that
     cancel out everywhere except the 1px padding ring. Lit where the light
     is, fading to nothing round the back. */
  :is(.cat, .menu__jump-field)::before {
    content: "";
    position: absolute;
    z-index: 1;
    inset: 0;
    padding: 1px;
    border-radius: inherit;
    background: radial-gradient(
      ellipse var(--glow-r) 260% at var(--px) var(--py),
      color-mix(in srgb, var(--accent) 62%, transparent),
      transparent
    );
    mask:
      linear-gradient(black 0 0) content-box,
      linear-gradient(black 0 0);
    mask-composite: exclude;
    pointer-events: none;
  }

  /* The pool inside it: wider, much fainter, warm. */
  :is(.cat, .menu__jump-field)::after {
    content: "";
    position: absolute;
    z-index: 0;
    inset: 0;
    border-radius: inherit;
    background: radial-gradient(
      ellipse calc(var(--glow-r) * 1.6) 320% at var(--px) var(--py),
      color-mix(in srgb, var(--sea) 26%, transparent),
      transparent
    );
    pointer-events: none;
  }

  .menu__jump-field > * {
    position: relative;
    z-index: 1;
  }

  /* ---- light under the header ------------------------------------------- */

  /* The bar sits above the page rather than butting against it. Absolute
     inside a sticky header so it travels with it; no pointer events, because
     it covers the top of the content. */
  .header::after {
    content: "";
    position: absolute;
    inset: 100% 0 auto;
    height: 3.5rem;
    background: linear-gradient(
      to bottom,
      color-mix(in srgb, var(--sea) 24%, transparent) 0%,
      color-mix(in srgb, var(--sea) 7%, transparent) 42%,
      transparent 100%
    );
    pointer-events: none;
  }

  /* ---- the jump control, compact ---------------------------------------- */

  .menu__jump-icon {
    width: 1.25rem;
    height: 1.25rem;
    background: none;
    color: var(--text-muted);
  }

  /* Hidden from the eye, kept for the accessibility tree: site.js rewrites the
     value to the chosen category, so without the label the summary announces a
     bare noun ("Starters") with no hint of what it does. */
  .menu__jump-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  .menu__jump-value {
    font-family: var(--font-display);
    font-size: var(--step-0);
    font-weight: 400;
    letter-spacing: -0.005em;
  }

  .menu__jump-go {
    width: 1.5rem;
    height: 1.5rem;
    background: none;
    color: var(--accent);
  }

  .menu__jump-field {
    border-radius: var(--radius-md);
    transition: border-color 180ms ease, background-color 180ms ease;
  }

  /* Open, the disclosure itself becomes the container and the children stop
     drawing their own edges. They cannot line up otherwise: a summary and a
     list each carrying a border and a radius meet along two vertical seams
     whose colours and corners never quite agree. One border, one radius, one
     shadow, and `overflow: hidden` clips both children to the parent's curve.

     Safe on a sticky element: overflow on the sticky box itself does not
     unstick it, only overflow on an ancestor does. */
  /* audit-ok: inset is on the children, by design */
  .menu__jump[open] {
    padding-bottom: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    overflow: hidden;
    box-shadow:
      0 0.5rem 1rem color-mix(in srgb, var(--ink-deep) 38%, transparent),
      0 1.5rem 3rem color-mix(in srgb, var(--ink-deep) 42%, transparent);

    & .menu__jump-field {
      border: 0;
      border-radius: 0;
      box-shadow: inset 0 1px 0 var(--lit);
    }

    /* The container draws the outline now, so the field's own rim would be a
       second line just inside it. */
    & .menu__jump-field::before {
      content: none;
    }
  }

  .menu__jump-list {
    border: 0;
    border-top: 1px solid var(--line-soft);
    border-radius: 0;
    box-shadow: none;
  }

  .menu__jump-option {
    position: relative;

    /* A quiet chevron per row that slides on hover, so the row feels like it
       goes somewhere. */
    &::after {
      content: "";
      width: 0.4rem;
      height: 0.4rem;
      margin-left: auto;
      border-top: 1.5px solid currentColor;
      border-right: 1.5px solid currentColor;
      rotate: 45deg;
      opacity: 0.45;
      transition: transform 180ms ease, opacity 180ms ease;
    }

    &:is(:hover, :focus-visible)::after {
      transform: translateX(0.2rem);
      opacity: 1;
    }
  }

  /* Inset to the text and only between rows. A rule that stops where the
     words stop is the difference between a list and a table. */
  .menu__jump-list li + li .menu__jump-option::before {
    content: "";
    position: absolute;
    top: 0;
    right: var(--space-3);
    left: var(--space-3);
    height: 1px;
    background: var(--line-soft);
  }

  /* ---- the visit panel --------------------------------------------------- */

  /* A default OpenStreetMap embed is the one element on the page wearing
     somebody else's palette. Pulling the saturation down and warming it
     slightly settles it into the theme; kept light on purpose, because roads,
     labels and the pin all have to keep their contrast. */
  .visit__map {
    filter: saturate(0.72) contrast(1.04) brightness(0.94) sepia(0.12);
  }

  /* The action becomes the foot of the panel rather than a button parked in a
     strip under the map: no padding around it, one hairline above it, and the
     whole bar is the target. */
  .visit__panel-foot {
    padding: 0;
    border-top: 1px solid var(--line);
  }

  .visit__maps-cta {
    height: 3.25rem;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--text);

    &:is(:hover, :focus-visible) {
      background: var(--sea-tint);
      color: var(--accent);
    }
  }
}

/* chrome.gallery: justified — P-gallery-justified

   Rows of varying widths, flush at both edges, every photograph keeping its own
   shape. The arithmetic is done at build time: core/images.py reads each source
   file's real dimensions and the template writes --ar per cell, so there is no
   measuring pass, no reflow on load and no JavaScript.

   Why it lines up: a row's free space is shared out in proportion to flex-grow,
   and both grow and basis are set to the item's aspect ratio. Every item in a
   row therefore scales by the same factor, which means one row height. */
@layer components {
  .gallery__grid {
    /* Target row height. The real height lands near this once a row is
       justified, and varies by a few percent between rows, which is the point:
       identical rows are a grid, not a justified gallery. */
    --jg-row: clamp(8.5rem, 30vw, 13rem);

    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
  }

  .gallery__cell {
    flex: var(--ar, 1.333) 1 calc(var(--ar, 1.333) * var(--jg-row));
  }

  /* Without this the final row stretches its one or two survivors across the
     full width and they tower over every row above. A spacer that takes all
     remaining space leaves them at their natural size instead. */
  .gallery__grid::after {
    content: "";
    flex-grow: 1000000;
  }

  .tile {
    aspect-ratio: var(--ar, 4 / 3);
  }
}

/* Wenge Glaze. Lovage Bistro's room after dark: wenge ground, limestone type,
   terracotta from the plates, one sage leaf from the logo. Self-hosted fonts,
   so no third-party origin at runtime.

   A dark theme on core's light-first components. Core paints the header, the
   fact strip, the nav sheet, the closing panel and the footer on --ink with
   --sand text, and cards, pills and the jump field on --surface. Here --sand is
   the page ground and --surface is the limestone, so every one of those is
   restated below; a rule that looks redundant against core is there because
   the token it inherits has changed sides. */

@font-face {
  font-family: "Young Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/young-serif-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Young Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/young-serif-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: Karla;
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/fonts/karla-var-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: Karla;
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/fonts/karla-var-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Every hex here is declared in theme.yaml tokens:, or design-audit fails. */
  --sand: #1E1714;
  --sand-deep: #271E1A;
  --sand-dim: #A89A8C;
  --surface: #F1E9DC;
  --ink: #17110E;
  --ink-deep: #100C0A;
  --ink-lift: #322824;
  --sea: #A8471F;
  --sea-deep: #8E3A19;
  --sea-tint: #2C2220;
  --sea-tint-deep: #372B27;
  --accent: #E0895F;
  --accent-ink: #E0895F;
  --glaze: #8FA98F;
  --glaze-deep: #37342D;
  --text: #F1E9DC;
  --text-muted: #C2B5A6;
  --line: #3D312B;
  --line-soft: #2E2521;
  --zebra: #231A16;

  --focus: var(--accent);
  --scrim: color-mix(in srgb, var(--ink-deep) 55%, transparent);
  --scrim-deep: color-mix(in srgb, var(--ink-deep) 86%, transparent);

  --font-display: "Young Serif", Georgia, "Times New Roman", serif;
  --font-body: Karla, "Segoe UI", system-ui, sans-serif;

  /* Young Serif is a heavy text face with a large x-height, so the display
     steps run tight and the body step stays at a plain reading size. */
  --step--1: clamp(0.8125rem, 0.79rem + 0.12vw, 0.875rem);
  --step-0: clamp(1rem, 0.97rem + 0.16vw, 1.0625rem);
  --step-1: clamp(1.125rem, 1.06rem + 0.32vw, 1.3125rem);
  --step-2: clamp(1.375rem, 1.22rem + 0.75vw, 1.75rem);
  --step-3: clamp(1.75rem, 1.4rem + 1.6vw, 2.5rem);
  --step-4: clamp(2.25rem, 1.5rem + 3.4vw, 3.75rem);

  /* Photographs take a tight corner. The plates are round; the frames are not. */
  --radius-media: 0.5rem;

  /* The progress hairline sits at the bottom edge of the header's paint, so
     --chrome-h is where it goes and --chrome-gap is what everything sticky
     below it clears. 8px leaves the 3px bar plus air; without it the sticky
     jump control docked underneath the bar and the two overlapped. This is
     the knob the contract in 00-tokens.css says to turn. */
  --chrome-gap: 0.5rem;

  /* Signature: the client's own three-leaf mark, cut out of the white wordmark
     (sites/lovage/images/brand/lovage-leaf.png, the leaves only, no ring) and
     carried as a 64px alpha mask. Painted in sage by .eyebrow::before. A mask,
     not an <img>, so the colour is a token and the glyph is the real leaf. */
  --sprig: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAOWUlEQVR42t1bfWxk1XU/970Z2+uPRrte7ICX7FLYDabAlmSzDVRbNjSplJaNmpBFUZPiBDVto4hUTRRUlCA2Aimglq7URS2m0SJgK6GhpBYENkuc2sDuej/GeNeywev153g84zcznq/3ed+9953+wX2bx2CPPfaMBT3SSPM8z/fde77P75wHUB0iwQtEVBCRwMeAQutdABEJIQQTicR20zT/cNOmTTFCyJD8TQUAJIR48P+UCCKSEydONFFKLyEics6xWCz+19jY2NYgkz42h0FEta+vLxRQZVVK0j+M6h8IERUAgFwudxu+TwwRhWTEQDKZPDA3N3ef/3+RSETdiIM88sgjSnDPq1FjhZAPCqn0GhFJd3d3OHAd8hl1/vz5/YjoycN7iMglQ1AIIWKx2C3BZ9Xy8JVqmyIP6yEiIOLVyWTygGVZ9yIiJJPJf7Vt+8VsNruPEILNzc07FhYW/rm3t7edEMLvuusujoghIURTwBESAFABAAGAKYqitLa2/uDNN9+8rlgs/o18Vk00IRKJqIQQPHfu3LVTU1P/sGqOIeLXHcc5j4iGLzld10+apqn516Zpvq5p2kOIiJTSZLFY/MnZs2dbAQDOnTt3py9wDJAQwkNEjzEWy+fzryIizs3N/YV8briavsE3r97e3nbbtscYY85NN91UtyqtSCQSfxvYNw+qsPzuBa6Z/4VSGtN1/YeTk5NfkvcE71uKhOM4qenp6U8uF0LXoPJX7P348eNXW5Y1jIjIGLMSicSeIHOWXQAAYGZm5ltCCCGlKOR3bxnGeEFGcM6NFQ7v+weGiJhIJP76nXfeuXNubu4L6/ELQckuLi5ea9v2sHyeg4iYSqW+CwDg+6pyC6kAALquHwwcZCVp+irPcfUkENFzXXeUUhqjlI5Go9HwWhjgH/7MmTOfPXny5DWapv1xQEMZIqJlWUeliYdXs2AYAMBxnD/nnC8GPPpqyMM1UqFQ6PKjSiX2johqLpe7zrKsFKU0ZRjGQGDPQjJgpKLogIjhvr6+5ng8/shSTq2KJBDRRUSvUCi8EY1GGxExtFqn6N+3sLDw3ApC4aZp9qdSqdtWNDXfDGzb7hdCuEIIjrUnLoRguq4/thopSXUmZ8+ebZ2dnf1sLBb7sTwolT7rQ+sjImqadg8ikrK+wGdAKpX6Ro2l/6ENjo6OfhkRP5nNZj+xGl+1uLj4KGPMNgyjv8xePRkNjJ6enmuWY7ASyPwEIiptbW0vGobxP/I3UeOsVQEA0dHRcWs+nz8qhPBkBkqWilaKooh33313V0tLy49CoVBDU1PTnaXn+FB+T4jpum5mbGzsurIhV6qXcurUqRvT6XQEEb1l1Kq6zkAIhoiYy+VeC0p5uXCt6/rx0rqjnGO2bTtuWdaJbDb7rF/rLFcOq4QQzhj7q1AodFCmsWGotQooCgAANjU1pZdLjGSEEKOjo39QX1//pff/hKHSemUpjKKhoaEDADocx/k2IQRLzSCoOggAYBhGH+fcAwAFETesEg2Hw+XUmBNCcNu2bdeHw2EVALwVDh88Ewoh3Pn5+ZPy8F45H6Bu3ry5T9f1wwCgIiLfKA7oul5Yzizz+fx/F4vFJy3L+lxQWCuR53kIAIQxNnHzzTfPEULKgzPygaEHHnig3rKskaCnrnUkGB4evj+Ytvr5eywWu7kk5a4k8WKIiMVi8UkAgKmpqe0jIyN1q8qtE4nEVZZlRYOZVS0ZkM1m7w46QT8xyufzD8l72BrW9hARXdcdNE3zLdM0x6LRaGMw0igltoYjIyN1zz//fNvk5OQ1dXV1i/LGmjuDlpYWVqrBhBBsbGz8M4kvwBr2QQAAwuHwZxobG/cBwMCePXssz/N8vAJCQckPDg62dnZ2/mrnzp27CCGbVfVKxKg5lBUKhbBk49jd3d3IOb86HA6D53mKoihrLZ05AKj5fP6V5VBhlRDCM5nM9xVF+aO6urqgF90QQJNzTn6niAQJISql9A1VVXcBgKfIeLmWqhkAQowxw7btU752lUYBDwDANM1f+fvxPehGRYF8Pl8HANDf3w+e5ykAIDjnRFXV9ZqgJxn8vzfccEMKEVVCCC6FCSrbt28fnJmZeQgAQoqiwAbmAaBp2jXB8IyIiud5b63R9j+kBZZljU9OTrZLDVsRHXqQc04RUXieV+tsmCEiGobxH6VocyKRuKdKoZghIk5PT/+wLPbg58pdXV0NpmkOyXJVbAQDEPF5uYc6ACADAwP3FAqFN1aJNa4YZi3LGkDEJkSsW7bs9nt677333h7Hcfh60Z5KGOC67lG5h00AAJZldZeCsGsEXpBSamuadn1FWNv09PR+wzB+wzn3aswELgHMbwQ0AGKx2F7GmFshNPe7DOh90+Wcc5pMJg8AgJpOp//OsqzD0Wi0sSwAE/xB07QH5Sbd9WSEJb7Ek4gTRUTOGEv39PS0+IiP74uy2ezP1+ED/Cwwh4j/YlnWu/4PmqbdUa70hkDjQi0Wi71VwgBRHnqpwzizs7MHgr1HRFQikcgWSmki0GRZL1FEZBcvXvyK/yxlhewJTdPstizruBDiMgAMe55nyHp8lQWZJwBAYYyhoigqAKiMsYJt2y8BwM/z+fzrAFDf3t7+75FIZAsAYH9/v0oI8fbu3bsjFAq1AYBYex4EKM/iyYw2pOv6mqpcJRaLfY6xKz6JBSKEV9JP+ECD1DCMF8bGxh42DOOldDr9vampqe0lpfBRWRA9GyiEVACAZDL54yo4ww9oYjwe/76mac2r6kcE2+OFQmGnruv3WpaVLXViS21S1/XZxcXFw5FIZMnWuEy2QgcPHtxkWdYFubm7/bLYf65lWS9VKR8QQgiWy+VejMfjrRX1JoM3v/rqqztN0/yqpmmPyYWLQggqnY5JKTUMw3jz5ZdfbpP9+ivFxYULF+6bmZk5nEwmv3Py5Mkr2d/8/PyNjuPoruvGI5HIlsBsgvL4449/wnGcyfUwwddWwzDOr7kvWQoq9vb2dkxNTX2lWCxunZiY+GoymfzZ7Ozs9RKBVQEAxsfH7zdNcwIRnx4cHNyzuLg4FugKDQ0PD9+bTqcfBABIp9PflADp06XaNzo6ehul1F6iWVsJ+c2Yx5YCSCudwAitAHF9gTF2KZ/PD1yxD8aEEMIK9u8opZxSyhYWFr4oMf8jiIiXL1++I8CEkN8PWIc/8J9nplKp7wbD7bpHUfzFELEBEcPpdPpHjDFe4nzYcs1SH74eHx+/qq+vL2QYxnlK6SU5tqPKtZVIJNJMKZ1dK0rlOM7w8PDwrVWdW/JxxMCCxHXd4jLYvVdOOoVC4ZcAAGNjY9dxzmk2m/1JqSnMz89/s0JfIDjnrq7rzz711FPNq2qXV3D4D9iQ67r/qWnaC4horcFOmczSumQW+D1ExGg0+ilEJLIjrEjo/tQqmeDjjceX2/O66e233/5UNpt9yHGcaBVitOc4TmZoaKgDAIjjOCOWZf02mCGeOXPm9yzLmlxl//KK6c3Pzz9aFbv3F0kmk025XO5+SmmqJNrw9VaG+Xz+FwAAc3Nzn5e5wQEfxEin0w+u0hF6gfmmF+Px+K51T7D6zggAYHJysp1S6uP0tBq4gSyYBGOMjY2N3QoAUCwWjzHGUtLphhzHmZKM9krGdfwPF0Jwz/OQUrqYyWS+U3X4qqurq+Ho0aPXuq77m9K0t1r4gK7r3YQQGBgYaGeMWQsLCz8dHx+/u5Lhk8uXL99QOty5pllhKXWSTCY/09ra+iQhZBvn/KpwONxcA9hcQUQIh8NfPHLkSPPtt9+uTU9PP7ljx45Hm5qaErlc7uHx8fHeLVu2FB3HCS0uLm7ZvXt35+bNm1symUxjQ0PD55ubm6/K5XLKsWPHUtLpeUEgtGKKRqNhaX9/iRtDHmOMZzKZDhkRehFR2LYdqyBH2drT09NSNbH09PTclslk/lH280WV6vOyDqxQKDyRz+dfCIa1S5cudcqQGJLJkf/d/1RvVJ8QAohY98orr9xommY1gYm1aISDiJjJZO5bzVTZupkQKEX3McboEhOkuEFDVFQmSPfZtv2WZVm/rGZCs2xScOjQIQQAeO655+YYY668t6aT3kuQ6rfE2traxnVdP6Ioyj7pk2r7EoavQl1dXQ2U0uwGzQqU6xvcHYlENtm2bWuatnsjRu+v9AkymcwPJES9EX2C5RhwjzTJC8Vi8WG/CKuZCfg9QwCArVu3/tvExMR+zrkmG6dig00BstlsWJbHryuK8mUZ172aMsAfmkDEUGdn52kAyAJAWKK7G0qWZXUCAObz+ddUVb0pFottkU1dUlMGSBKIqCQSiUMA8AvTNE8DgFnStfWq0E0ulSr6n23btt0CAPDMM8+cJ4Sw+vr6/RWeobpkGMZbssPjVOAXyrW5eAA6cwPX/ktYL/nPNk3z14ZhHKt0ynw9GhCEyMOI2Oh5XjMAEEVR6mXtHuec04AURUCaKK+VJZBYzx9hcV23mEwmv+04zmsAoHqeZ3meR4UQIpVKHQ0ALyfC4fCfAoBCCOEbLn1EJBcuXGianJzc67ru32uadkdPT09LoVAYLePF0XGcGdd108HSNVCz/3p+fv5Guf6fZDKZr8VisY65ublto6Oj+/r6+hoCY/K3MMb41NTU7hVfidlIYoydcxzHKxQKE4yxQc75hOwVFHVd/9np06dvKU2lbdu+mM1mv1UyFlt26qu7uztMKS0Ui8WfVsMM1oUM+W0sef378Xh8V3t7e5OsIq/XNO3wxYsXPw0AMDQ0tD+TyTyNiIey2ew/ZbPZx5944omW4HpBEBQRiUSeldIpFsuyXqeUTgTfI4CPEpVuqFzuXokE/Xt1XT/EOX/n4MGDqmQS+Sgc2pcWKYHMlUB1GSxf1TVsnAAADA8Pt8/Pzzd+nN5N/kjS/wEMr+00g1+SfQAAAABJRU5ErkJggg==");
  --sprig-size: 1.5rem;
}

@layer theme {
  ::selection {
    background: var(--sea);
    color: var(--surface);
  }

  body {
    background: var(--sand);
    color: var(--text);
    font-family: var(--font-body);
  }

  /* ---------------------------------------------------------------- type */

  /* One weight ships for the display face. Declaring it stops the browser
     synthesising a bold for h1/h2 and smearing the serifs. */
  .hero__title,
  .h2,
  .h3,
  .cta__title,
  .doc__title,
  .doc__h2,
  .cat__title,
  .pick__name,
  .visit__panel-title,
  .footer__name,
  .brand__name {
    font-weight: 400;
  }

  .hero__title,
  .h2,
  .cta__title,
  .doc__title {
    letter-spacing: -0.015em;
    text-wrap: balance;
  }

  .h2 {
    line-height: 1.06;
  }

  .head__lead {
    color: var(--text-muted);
  }

  .link {
    color: var(--accent);
  }

  .link:hover {
    color: var(--text);
  }

  /* ---------------------------------------------------------------- signature
     The eyebrow above every section opens with the leaf. Sage is the one
     place the green appears at type size; the reviews band is its other. */
  .eyebrow {
    display: flex;
    gap: var(--space-2);
    align-items: center;
    color: var(--accent);
  }

  .eyebrow::before {
    content: "";
    flex: 0 0 auto;
    width: var(--sprig-size);
    height: var(--sprig-size);
    background-color: var(--glaze);
    mask: var(--sprig) center / contain no-repeat;
  }

  /* ---------------------------------------------------------------- buttons
     Limestone at rest, terracotta on hover: on a dark page the booking
     button is the brightest object, which is what a primary is for. */
  .btn--primary {
    background: var(--surface);
    color: var(--ink);
    border-color: var(--surface);
  }

  .btn--primary:hover,
  .btn--primary:focus-visible {
    background: var(--sea);
    border-color: var(--sea);
    color: var(--surface);
  }

  .btn--ghost {
    border-color: color-mix(in srgb, var(--text) 42%, transparent);
    background: transparent;
    color: var(--text);
  }

  .btn--ghost:hover,
  .btn--ghost:focus-visible {
    background: var(--ink-lift);
    border-color: var(--text);
    color: var(--text);
  }

  /* ---------------------------------------------------------------- header
     Plain strip on --ink. Core sets the header's text to --sand, which is the
     page ground here, so the colour is restated. */
  .header {
    color: var(--text);
    border-bottom: 1px solid var(--line-soft);
  }

  /* Core's progress bar is fixed to the top of the viewport, where this theme's
     header already is, so it drew across the top of the bar. Moved below it
     with the documented offset rather than a literal height. Overridden here,
     not in the module: paper-shoal claims `progress: bar` too, and its header
     is a floating pill that wants the bar where core puts it. */
  body::after {
    top: var(--chrome-h);
    /* A warm ramp with the bright end leading. The module scales the bar on
       the X axis from a left origin, so the right edge is the head and the
       gradient rides along with it: the further you read, the more of the
       light the bar carries. Deep terracotta behind, accent at the tip. */
    background: linear-gradient(
      90deg,
      color-mix(in srgb, var(--sea) 55%, transparent) 0%,
      var(--sea) 42%,
      var(--accent) 100%
    );
  }

  /* images.logo is the full wordmark, so it sets its own width from a fixed
     height. Core sizes .brand__logo as a 40px square for a round mark; that
     squashes a 520x178 lock-up, and it also caught the footer's --lg variant,
     which sits in an earlier layer and cannot win. Both are restated. */
  .brand__logo {
    width: auto;
    height: 2.75rem;
    max-width: min(14rem, 56vw);
  }

  .brand__logo--lg {
    width: auto;
    height: 3.25rem;
    max-width: 17rem;
    margin-inline: auto;
  }

  /* The wordmark already reads "lovage BISTRO", and the link takes its
     accessible name from the image alt, so the text beside it is a second
     copy of the same words. */
  .brand__text,
  .footer__name {
    display: none;
  }

  .header__toggle {
    color: var(--text);
  }

  .nav__link {
    color: var(--text);
  }

  .nav__link:hover,
  .nav__link:focus-visible {
    background: var(--ink-lift);
    color: var(--accent);
  }

  /* The mobile sheet drops out of the bar on --ink; core gives it --sand text.
     Scoped: above 64rem core turns .nav into a plain flex row of links, where
     a background and a border are a 576px rule floating under the nav. */
  @media (max-width: 63.9375rem) {
    .nav {
      background: var(--ink);
      color: var(--text);
      border-bottom: 1px solid var(--line);
    }
  }

  .skip-link {
    background: var(--ink);
    color: var(--text);
  }

  /* ---------------------------------------------------------------- hero
     P-hero-split on the ink panel. The photograph is flush to the viewport
     edge with no frame: its marble runs into the wenge ground. Type sits on
     the panel, never on the plate. Core owns the copy's width, margin and
     padding at every breakpoint, including the 64rem shorthand that aligns
     the copy with the wrap's left edge; nothing here touches them. */
  .hero--split {
    background: var(--ink);
  }

  .hero--split .hero__copy {
    color: var(--text);
  }

  .hero--split .hero__title {
    max-width: 14ch;
    color: var(--text);
  }

  .hero--split .hero__lead {
    max-width: 40ch;
    color: var(--text-muted);
  }

  /* The photograph, whole, dissolved into the ground rather than cut out of
     it. No frame, no radius, no ring: the mask feathers all four edges so the
     dark marble the dish sits on becomes the wenge of the page, and there is
     no hard edge anywhere for the eye to read as a box. The left edge fades
     hardest, because that is the one that meets the copy.

     Feathering is why this can run to the viewport edge without reading as a
     bleed: an edge you cannot find is not an edge. */
  .hero--split .hero__media {
    mask-image:
      linear-gradient(to right, transparent 0%, black 26%, black 88%, transparent 100%),
      linear-gradient(to bottom, transparent 0%, black 16%, black 84%, transparent 100%);
    mask-composite: intersect;
  }

  .hero--split .hero__media .pic > img {
    object-position: center;
  }

  .rating {
    color: var(--sand-dim);
  }

  .rating__value {
    color: var(--text);
  }

  .rating__stars,
  .quote__stars {
    color: var(--accent);
  }

  /* Fact rail under the hero. Thin, on --ink, hairlines above and below. */
  .strip {
    padding-block: var(--space-4);
    background: var(--ink);
    color: var(--text);
    border-top: 1px solid var(--line-soft);
    border-bottom: 1px solid var(--line-soft);
  }

  .strip__label {
    color: var(--accent);
  }

  .strip__value {
    color: var(--text);
  }

  /* ---------------------------------------------------------------- bands */

  .section--band {
    background: var(--sand-deep);
  }

  /* ---------------------------------------------------------------- story
     P-story-offset: the photograph's height follows the copy at 64rem. */
  .story__copy p {
    color: var(--text-muted);
  }

  /* Core puts the 3:4 ratio on the figure and clips it, which leaves the
     figcaption outside the box and invisible. The ratio moves to the picture,
     so the figure is as tall as photo plus caption and the rounded clip still
     covers both. */
  .story__media {
    aspect-ratio: auto;
    border-radius: var(--radius-media);
  }

  /* height: auto is load-bearing. Core gives .pic `height: 100%`, and a
     definite height plus an aspect-ratio derives the *inline* size from the
     block size: the figure computed 376px inside a 342px column at 390, which
     overflowed the viewport and bled its parent. With the height auto, the
     width is authoritative and the ratio sets the height. */
  .story__media .pic {
    aspect-ratio: 3 / 4;
    height: auto;
  }

  /* Portrait source in a 3:4 slot: the crop takes height, so bias it up to
     keep the head clear of the top edge. */
  .story__media .pic > img {
    object-position: center 24%;
  }

  .story__caption {
    background: var(--ink);
    color: var(--sand-dim);
  }

  /* ---------------------------------------------------------------- picks
     P-picks-zigzag: one dish per row, photo first, copy beside it from 56rem
     with the sides alternating. Square crops, because the plates are round. */
  .picks__grid {
    grid-template-columns: minmax(0, 1fr);
    /* audit-ok: the pattern asks for a row gap wider than the ladder so each dish reads as its own row */
    gap: clamp(2.5rem, 6vw, 3.75rem);
  }

  .pick {
    grid-template-columns: minmax(0, 1fr);
    align-items: center;
  }

  .pick__media {
    aspect-ratio: 1;
    max-width: 30rem;
  }

  .pick__body {
    gap: var(--space-3);
  }

  .pick__name {
    font-size: var(--step-3);
    line-height: 1.06;
  }

  .pick__note {
    max-width: 40ch;
    color: var(--text-muted);
  }

  .pick__price {
    margin-block-start: var(--space-2);
    color: var(--accent);
  }

  /* ---------------------------------------------------------------- menu
     P-menu-ledger on the dark ground. Core paints the accordion cards, the
     jump field and the pills on --surface, which is limestone here. */
  .menu__jump-field {
    border-color: var(--line);
    background: var(--sand-deep);
  }

  .menu__jump-field:hover {
    border-color: var(--sand-dim);
    background: var(--sea-tint);
  }

  .menu__jump[open] .menu__jump-field {
    background: var(--sea-tint);
  }

  .menu__jump-value {
    color: var(--text);
  }



  .menu__jump-list {
    background: var(--sand-deep);
  }

  .menu__jump-option {
    color: var(--text);
  }

  .menu__jump-option:hover,
  .menu__jump-option:focus-visible {
    background: var(--sea-tint-deep);
    color: var(--accent);
  }

  .pill {
    border-color: var(--line);
    background: var(--sand-deep);
    color: var(--text-muted);
  }

  .pill:hover,
  .pill:focus-visible {
    border-color: var(--accent);
    background: var(--sea-tint-deep);
    color: var(--text);
  }

  .cat {
    border-color: var(--line-soft);
    background: var(--sand-deep);
  }

  .cat__head {
    background: var(--sea-tint);
  }

  .cat__head:hover {
    background: var(--sea-tint-deep);
  }

  /* A count is a number: tabular figures so four rows of them line up, and a
     touch of tracking so it reads as a label beside the serif title. */
  .cat__count {
    color: var(--sand-dim);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
  }

  .row {
    border-bottom: 1px solid var(--line-soft);
  }

  .row:last-child {
    border-bottom: 0;
  }

  .row:nth-child(even) {
    background: var(--zebra);
  }

  /* No sibling dimming here. It was tried: hovering a dish dropped the rest of
     its category to 62%, which reads as the menu greying out under the cursor
     rather than as focus. A price list is for comparing, so every line stays
     at full strength and the card's light does the feedback. */

  .row__price {
    color: var(--accent);
  }

  /* ---------------------------------------------------------------- gallery
     P-gallery-justified; the module does the rows. The band sits on --ink so
     the contact sheet reads as its own block between two wenge sections. */
  .gallery.section--band {
    background: var(--ink);
  }

  .tile {
    border-radius: var(--radius-media);
    background: var(--sand-deep);
  }

  /* ---------------------------------------------------------------- reviews
     P-reviews-band on ink, the quotes as sage slabs lifted off it. Core's left
     accent rule on every quote is replaced by the slab's own hairline; the
     slab is a flex column so the three bylines share one bottom edge. The
     quote text is body copy, not a heading, so it takes the body face. */
  /* The gallery band above this is also --ink, so the two ran together as one
     dark block with no seam. Reviews drops to the page ground and takes a
     hairline, which puts a real edge between the photographs and the quotes
     and keeps the step to the sand-deep visit band below. */
  .reviews {
    background: var(--sand);
    border-top: 1px solid var(--line);
  }

  .quotes {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
  }

  .quote {
    display: flex;
    flex-direction: column;
    padding: var(--space-5);
    border: 1px solid color-mix(in srgb, var(--glaze) 28%, var(--glaze-deep));
    border-radius: var(--radius-md);
    background: var(--glaze-deep);
  }

  .quote__text {
    font-family: var(--font-body);
    font-size: var(--step-0);
    line-height: 1.55;
  }

  .quote__by {
    flex-direction: column;
    gap: var(--space-1);
    align-items: start;
    margin-top: auto;
  }

  .quote__author {
    color: var(--text);
  }

  .quote__role {
    color: var(--text-muted);
  }

  /* ---------------------------------------------------------------- visit */

  .visit__panel {
    border-color: var(--line);
    background: var(--sand);
  }

  .visit__map {
    background: var(--sand);
  }

  .visit__list li,
  .visit__coverage-map {
    border-color: var(--line);
    background: var(--sand);
  }

  .nap > dt {
    color: var(--sand-dim);
  }

  .nap__note {
    color: var(--text-muted);
  }

  /* ---------------------------------------------------------------- faq
     Core narrows the FAQ's .wrap to the reading measure, which re-centres it
     and starts its copy 288px right of every other section at 1440. The wrap
     stays a wrap here and the two children take the cap instead. */
  .faq__inner {
    max-width: var(--measure-wide);
  }

  .faq .head,
  .faq__list {
    max-width: var(--measure-text);
  }

  .qa {
    border-bottom-color: var(--line);
  }

  .qa__q {
    color: var(--text);
  }

  .qa__q::after {
    color: var(--accent);
  }

  .qa__q:hover {
    color: var(--accent);
  }

  .qa__a {
    color: var(--text-muted);
  }

  /* ---------------------------------------------------------------- cta */

  .cta {
    background: var(--ink);
    color: var(--text);
    border-top: 1px solid var(--line-soft);
  }

  .cta__title {
    color: var(--text);
  }

  .cta__lead {
    color: var(--text-muted);
  }

  .cta .btn--ghost {
    border-color: color-mix(in srgb, var(--text) 42%, transparent);
    color: var(--text);
  }

  .cta .btn--ghost:hover,
  .cta .btn--ghost:focus-visible {
    background: var(--ink-lift);
    border-color: var(--text);
  }

  /* ---------------------------------------------------------------- footer */

  .footer {
    background: var(--ink-deep);
    color: var(--sand-dim);
    border-top: 1px solid var(--line-soft);
  }

  .footer__name {
    color: var(--text);
  }

  .footer__blurb,
  .footer__link,
  .footer__social,
  .footer__fine,
  .footer__oib {
    color: var(--sand-dim);
  }

  .footer__link:hover,
  .footer__social:hover,
  .footer__social:focus-visible {
    color: var(--text);
  }

  .footer__title {
    color: var(--accent);
  }

  .footer__fine {
    border-top-color: var(--ink-lift);
  }

  /* ---------------------------------------------------------------- dock
     Core's pill is limestone with dark type, which is right on this ground.
     Only the tap flash is restated: core's --sand-deep is dark here. */
  .dock__item:active {
    background: color-mix(in srgb, var(--ink) 10%, var(--surface));
  }

  /* ---------------------------------------------------------------- surfaces
     Core paints these on --surface. None renders on the Lovage build today
     (no i18n, no order wizard), but a theme is reused, so they are dark too. */
  .lang__link.is-current {
    background: var(--sand-deep);
    color: var(--text);
  }

  .order {
    background: var(--sand-deep);
    color: var(--text);
  }

  .order__body textarea,
  .order__body input,
  .order__body select {
    border-color: var(--line);
    background: var(--sand);
    color: var(--text);
  }

  /* ---------------------------------------------------------------- lightbox */

  .lightbox,
  .lightbox__close,
  .lightbox__step {
    color: var(--text);
  }

  /* ---------------------------------------------------------------- doc pages */

  .doc__meta {
    color: var(--sand-dim);
  }

  /* ---------------------------------------------------------------- wider */

  @media (min-width: 48rem) {
    .quotes {
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }
  }

  @media (min-width: 56rem) {
    /* Two equal tracks; the plate is capped at 26rem and hugs the centre
       gutter, so photo and copy meet in the middle of the row on both the
       odd and the even rows. Uncapped, three 33rem plates ran the section to
       2.4 screens for 84 words. */
    .pick {
      grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
      gap: var(--space-7);
    }

    .pick__media {
      width: 100%;
      max-width: 26rem;
      justify-self: end;
    }

    .pick:nth-child(even) .pick__media {
      order: 2;
      justify-self: start;
    }

    .pick:nth-child(even) .pick__body {
      order: 1;
      justify-self: end;
    }
  }

  @media (min-width: 64rem) {
    /* The copy column is stretched to the media's 32rem; centre it in that
       row so the headline sits level with the bowl, not at the top corner. */
    .hero--split .hero__copy {
      align-content: center;
    }

    /* Wide: the photograph fills its column and its own darkness carries the
       feather into the page, so it wants no gutter and no centring. */
    .hero--split .hero__media {
      align-self: stretch;
    }

    /* P-story-sidebar: prose beside a portrait that keeps its own shape.
       This was P-story-offset, where the photograph's height follows the copy.
       That pattern is for a text column that runs long; once the notes box
       came out, the copy was short enough to make the figure landscape, and a
       3:4 portrait cover-cropped into a 1.16 box loses half its height. The
       photograph keeps core's ratio and the row is sized by the copy. */
    .story__grid {
      grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
      column-gap: var(--space-8);
    }
  }
}

/* Deliberately unlayered.

   Unlayered rules beat every @layer regardless of source order, so this single
   block neutralises motion across every component without needing !important
   and without per-component reduced-motion rules. Keep it last in the build. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms;
    animation-iteration-count: 1;
    transition-duration: 1ms;
    /* A scroll-driven animation takes its progress from the scroll position,
       so animation-duration does not reach it. Handing it back the document
       timeline lets the 1ms above apply, and `both` fill then leaves the
       element at its finished state: settled, in place, never mid-reveal. */
    animation-timeline: auto;
    animation-range: normal;
  }

  html {
    scroll-behavior: auto;
  }
}
