/* Self-hosted webfonts. GENERATED by scripts/fetch-fonts.js — do not edit by hand. */

/* marcellus · latin-ext */
@font-face {
  font-family: 'Marcellus';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/marcellus-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;
}

/* marcellus · latin */
@font-face {
  font-family: 'Marcellus';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/marcellus-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;
}

/* italiana · latin */
@font-face {
  font-family: 'Italiana';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/italiana-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;
}

/* archivo · latin-ext */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 700;
  font-stretch: 100%;
  font-display: swap;
  src: url(../fonts/archivo-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;
}

/* archivo · latin */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 700;
  font-stretch: 100%;
  font-display: swap;
  src: url(../fonts/archivo-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;
}



/* =========================================================================
   Castro's Reef & Beef

   The palette is read off the restaurant itself, not chosen from a mood board:
   the dining room has rust and terracotta walls, filament bulbs, tan leather and
   a near-black ceiling, and the logo is gold. Every colour below is one of those.

   Contrast for every pair used here is verified by `npm run contrast`, which
   fails if a combination drops under its WCAG 2.2 minimum. Change a colour, run it.
   ========================================================================= */

:root {
  /* Surfaces — the room after dark */
  --ink: #0b0a09;
  --coal: #14100d;
  --slate: #1d1713;
  --line: #332a23;   /* decorative hairlines only */
  --edge: #7a6857;   /* control boundaries — must stay >= 3:1 on --ink */

  /* Text */
  --bone: #f4ede3;
  --dim: #bcac99;
  --faint: #8c7e70;

  /* Accents */
  --ember: #e2551f;      /* the terracotta wall */
  --ember-lift: #f2703a; /* hover / links */
  --amber: #f0a64a;      /* filament bulb — prices, focus ring */
  --gold: #c9a961;       /* the logo — eyebrows, rules */
  --tide: #6fb0c4;       /* the bar's LED — the "Reef" half, used sparingly */

  /* Type. The display role is split in two on purpose — see .hero__title. */
  --wordmark: "Italiana", "Didot", "Bodoni MT", Georgia, serif;
  --display: "Marcellus", "Optima", "Palatino Linotype", Georgia, serif;
  --ui: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  /* Layout */
  --wrap: 76rem;
  --gutter: clamp(1.25rem, 5vw, 4rem);
  --section-y: clamp(4.5rem, 11vw, 9rem);
  --radius: 2px;

  /* Motion. One duration and one curve, so everything feels like one hand. */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --t-fast: 180ms;
  --t: 380ms;
  --t-slow: 900ms;

  color-scheme: dark;
}

/* ---------- reset ---------- */

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchored sections must clear the sticky header. */
  scroll-padding-top: 5.5rem;
}

body {
  background: var(--ink);
  color: var(--bone);
  font-family: var(--ui);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

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

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

a { color: inherit; }

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

:target { scroll-margin-top: 6rem; }

/* ---------- focus ---------- */

/* One ring everywhere. Amber on ink is 9.7:1, and the offset keeps it off the glyphs. */
:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 3px;
  border-radius: 1px;
}
:focus:not(:focus-visible) { outline: none; }

.skip {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translate(-50%, -120%);
  z-index: 100;
  padding: 0.75rem 1.25rem;
  background: var(--ember);
  color: var(--ink);
  font-weight: 600;
  transition: transform var(--t-fast) var(--ease);
}
.skip:focus { transform: translate(-50%, 0); }

.u-sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

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

/* Marcellus is an inscriptional roman — the same tradition as the letterspaced
   "REEF & BEEF" under the script in the restaurant's own logo, which is the reason it
   is here. It is drawn with generous sidebearings, so unlike a Didone it wants no
   negative tracking: tightening it closes the counters and kills the thing that makes
   it look carved rather than typed. */
h1, h2, h3 {
  font-family: var(--display);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: 0;
  text-wrap: balance;
}

p { text-wrap: pretty; }

/* ---------- layout ---------- */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

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

/* One heading per section, and nothing under it but the thing itself. The section
   names are the restaurant's own — O Restaurante, Ementa, Avaliações, Contactos,
   Reservas — so they need no explaining. */
.shead {
  font-size: clamp(1.9rem, 4.4vw, 3.4rem);
  margin-bottom: 1.25rem;
}
.shead-block { margin-bottom: clamp(1.75rem, 3.5vw, 2.75rem); }

/* The single line of prose a section is allowed. */
.lede {
  max-width: 46ch;
  margin-bottom: clamp(2rem, 4vw, 3rem);
  color: var(--dim);
  font-size: clamp(1.02rem, 1.35vw, 1.15rem);
}

/* ---------- images ---------- */

/* The LQIP sits on the <picture> as a background, so the blur-up costs no request
   and no JavaScript: it is simply what shows while the real bytes decode. */
.pic {
  position: relative;
  display: block;
  overflow: hidden;
  background-size: cover;
  background-position: center;
  background-color: var(--coal);
}
.pic img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

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

.btn {
  --btn-bg: transparent;
  --btn-fg: var(--bone);
  --btn-edge: var(--edge);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem 1.5rem;
  border: 1px solid var(--btn-edge);
  border-radius: var(--radius);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn--primary {
  --btn-bg: var(--ember);
  --btn-fg: var(--ink);
  --btn-edge: var(--ember);
}
.btn--primary:hover { --btn-bg: var(--ember-lift); --btn-edge: var(--ember-lift); }

.btn--ghost:hover { --btn-bg: rgba(244, 237, 227, 0.06); --btn-edge: var(--bone); }

.btn--lg { padding: 1.05rem 2rem; font-size: 0.95rem; }
.btn--sm { padding: 0.6rem 1.05rem; font-size: 0.78rem; }

.link {
  display: inline-block;
  color: var(--ember-lift);
  font-weight: 600;
  font-size: 0.92rem;
  letter-spacing: 0.04em;
  text-decoration: none;
  padding-block: 0.2rem 0.25rem;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 100% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size var(--t) var(--ease), color var(--t-fast) var(--ease);
}
.link:hover { background-size: 0% 1px; color: var(--amber); }
.link--lg { font-size: 1.05rem; }

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

.site-head {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  transition: background var(--t) var(--ease), border-color var(--t) var(--ease),
    backdrop-filter var(--t) var(--ease);
  border-bottom: 1px solid transparent;
}
.site-head.is-stuck {
  background: rgba(11, 10, 9, 0.86);
  backdrop-filter: blur(14px) saturate(1.2);
  border-bottom-color: var(--line);
}
/* Hide on scroll down, reveal on scroll up — the phone viewport is small enough
   that a permanently pinned bar costs more than it gives. */
.site-head.is-hidden { transform: translateY(-100%); }
.site-head { transition-property: background, border-color, backdrop-filter, transform; }

.site-head__in {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: 0.9rem var(--gutter);
  display: flex;
  align-items: center;
  gap: clamp(1rem, 3vw, 2.5rem);
}

.brand { flex: none; line-height: 0; }
.brand__mark {
  width: auto;
  height: clamp(2.1rem, 3.6vw, 2.9rem);
  transition: height var(--t) var(--ease);
}
.site-head.is-stuck .brand__mark { height: clamp(1.9rem, 2.8vw, 2.3rem); }

.nav { margin-left: auto; }
.nav__list { display: flex; gap: clamp(1rem, 2.2vw, 2rem); }
.nav__list a {
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--dim);
  transition: color var(--t-fast) var(--ease);
}
.nav__list a:hover,
.nav__list a[aria-current="page"] { color: var(--bone); }

.site-head__end { display: flex; align-items: center; gap: 0.85rem; margin-left: auto; }
.nav + .site-head__end { margin-left: 0; }

/* Padding, not decoration: WCAG 2.2 2.5.8 wants 24px of target and 12px of uppercase
   type only draws 20. The same reasoning applies to every small control below. */
.lang {
  display: inline-block;
  padding-block: 0.35rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--faint);
  transition: color var(--t-fast) var(--ease);
}
.lang:hover { color: var(--gold); }

.burger {
  display: none;
  width: 2.75rem; height: 2.75rem;
  padding: 0;
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  background: transparent;
  cursor: pointer;
}
.burger__box { display: grid; place-items: center; height: 100%; }
.burger__bar,
.burger__bar::before,
.burger__bar::after {
  display: block;
  width: 1.1rem; height: 1.5px;
  background: var(--bone);
  transition: transform var(--t) var(--ease), opacity var(--t-fast) var(--ease);
}
.burger__bar::before,
.burger__bar::after { content: ""; position: absolute; }
.burger__bar::before { transform: translateY(-6px); }
.burger__bar::after { transform: translateY(6px); }
.burger[aria-expanded="true"] .burger__bar { background: transparent; }
.burger[aria-expanded="true"] .burger__bar::before { transform: rotate(45deg); }
.burger[aria-expanded="true"] .burger__bar::after { transform: rotate(-45deg); }

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

.mnav {
  position: fixed;
  inset: 0;
  z-index: 55;
  background: var(--ink);
  display: grid;
  place-items: center;
  opacity: 0;
  transition: opacity var(--t) var(--ease);
}
.mnav[hidden] { display: none; }
.mnav.is-open { opacity: 1; }

.mnav__in { text-align: center; padding: 6rem var(--gutter) 3rem; width: 100%; }
.mnav__list { display: grid; gap: 0.25rem; }
.mnav__list a {
  display: block;
  padding: 0.5rem 0;
  font-family: var(--display);
  font-size: clamp(2rem, 9vw, 3rem);
  line-height: 1.1;
  text-decoration: none;
  opacity: 0;
  transform: translateY(14px);
}
.mnav.is-open .mnav__list a {
  opacity: 1;
  transform: none;
  transition: opacity var(--t) var(--ease) calc(60ms * var(--i, 0) + 80ms),
    transform var(--t) var(--ease-out) calc(60ms * var(--i, 0) + 80ms);
}
.mnav__foot {
  margin-top: 2.5rem;
  display: grid;
  gap: 1.25rem;
  justify-items: center;
}
.lang--block { padding: 0.5rem; }

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

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  padding-block: 8rem clamp(4rem, 12vh, 7rem);
  isolation: isolate;
  overflow: hidden;
}

.hero__media { position: absolute; inset: 0; z-index: -2; }
.hero__pic { position: absolute; inset: 0; height: 100%; }

/* A very slow push-in. 18 seconds is long enough that it reads as atmosphere
   rather than as an animation, which is the entire point. */
.hero__pic img {
  transform: scale(1.08);
  animation: hero-drift 24s var(--ease) forwards;
}
@keyframes hero-drift { to { transform: scale(1); } }

/* Two layers: a vertical scrim so the copy always has contrast, and a warm pool of
   light from the lower left that mimics the filament bulbs in the photograph. */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(70% 55% at 18% 88%, rgba(226, 85, 31, 0.24), transparent 68%),
    linear-gradient(to top, var(--ink) 4%, rgba(11, 10, 9, 0.82) 34%, rgba(11, 10, 9, 0.28) 68%, rgba(11, 10, 9, 0.55) 100%);
}

.hero__in { position: relative; }
/* The name — and only the name — is set in Italiana.

   Italiana is light, wide and deco-ish: it is the most elegant face tried here at this
   size, and it falls apart at the 30px of a section heading on a dark background, where
   the thin strokes start dropping out. So the display role is split: the wordmark face
   for this one element, Marcellus for every other heading. Each face is used only where
   it works, and Italiana's latin subset is 9.9 KB, so the second family is close to
   free.

   Open tracking, because the face is drawn wide and the gold logo directly above it is
   letterspaced too. Line-height is loose enough that the clipping wrapper on
   .enter-rise never crops the caps. */
.hero__title {
  font-family: var(--wordmark);
  font-size: clamp(2.8rem, 9vw, 7rem);
  line-height: 1.08;
  letter-spacing: 0.02em;
  max-width: 15ch;
}
.hero__lead {
  margin-top: 1.5rem;
  max-width: 44ch;
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  color: var(--dim);
}
.hero__cta { margin-top: 2.25rem; display: flex; flex-wrap: wrap; gap: 0.85rem; }

/* ---------- proof bar ---------- */

.proof {
  border-block: 1px solid var(--line);
  background: var(--coal);
}
.proof__in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem clamp(1.5rem, 4vw, 3rem);
  padding-block: 1.1rem;
}
.proof__rating {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
}
.proof__score {
  font-family: var(--display);
  font-size: 1.5rem;
  line-height: 1;
  color: var(--amber);
}
.proof__count { font-size: 0.85rem; color: var(--dim); }
.proof__rating:hover .proof__count { color: var(--bone); }

.proof__fact { font-size: 0.85rem; color: var(--dim); margin-left: auto; }

.stars { display: inline-flex; gap: 2px; }
.star { width: 0.8rem; height: 0.8rem; fill: var(--amber); }

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

.band { overflow: hidden; }
.band__pic { height: clamp(14rem, 34vw, 26rem); }
.band__pic img { transform: scale(1.14); will-change: transform; }

/* =========================================================================
   The gallery band

   Eight frames crossfading on a timer, with no JavaScript. Each slide runs the same
   keyframes on the same 40s loop and is offset by its index, so exactly one is at
   full opacity at any moment. --slide is the cycle divided by the slide count; change
   the count in the template and only --slides here needs to follow.

   The default state below is the REDUCED-MOTION state: a static, scrollable strip.
   The animation is added back inside the no-preference query further down. Building it
   in that order means a visitor who asked for less motion gets a gallery that simply
   works, rather than one animation stripped out and a blank rectangle left behind.
   ========================================================================= */

.gal {
  --slides: 8;
  --cycle: 40s;
  position: relative;
  background: var(--coal);
  border-block: 1px solid var(--line);
}

.gal__stage {
  display: flex;
  gap: 2px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
}
.gal__slide {
  margin: 0;
  flex: 0 0 min(88%, 46rem);
  scroll-snap-align: center;
}
.gal__pic { height: clamp(15rem, 40vw, 30rem); }

/* The pause control only exists when there is motion to pause. */
.gal__pause { display: none; }
.gal__toggle { display: none; }

@media (prefers-reduced-motion: no-preference) {
  .gal__stage {
    display: grid;
    overflow: visible;
    scroll-snap-type: none;
    gap: 0;
  }
  /* --delay is written per slide by the template, and is negative: every slide is
     already mid-loop at t=0, so the first transition crossfades instead of cutting.
     See the comment on GAL_CYCLE in templates/home.js for why the offsets descend. */
  .gal__slide {
    grid-area: 1 / 1;
    flex: none;
    animation: gal-fade var(--cycle) linear infinite;
    animation-delay: var(--delay);
  }
  /* A slow push-in on whichever frame is showing. Same loop and same offset, so the
     movement stays in step with the crossfade. */
  .gal__slide img {
    animation: gal-drift var(--cycle) linear infinite;
    animation-delay: var(--delay);
  }

  #gal-pause:checked ~ .gal__stage .gal__slide,
  #gal-pause:checked ~ .gal__stage .gal__slide img { animation-play-state: paused; }

  .gal__pause {
    position: absolute;
    right: clamp(1rem, 3vw, 2rem);
    bottom: clamp(1rem, 3vw, 2rem);
    z-index: 2;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.95rem;
    background: rgba(11, 10, 9, 0.72);
    backdrop-filter: blur(8px);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    color: var(--bone);
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
  }
  .gal__pause:hover { background: rgba(11, 10, 9, 0.9); border-color: var(--bone); }
  #gal-pause:focus-visible ~ .gal__pause { outline: 2px solid var(--amber); outline-offset: 3px; }

  /* Two bars, becoming a triangle when paused. */
  .gal__ico {
    width: 0.6rem; height: 0.7rem;
    border-left: 3px solid currentColor;
    border-right: 3px solid currentColor;
  }
  #gal-pause:checked ~ .gal__pause .gal__ico {
    width: 0; height: 0;
    border: 0;
    border-left: 8px solid currentColor;
    border-top: 5px solid transparent;
    border-bottom: 5px solid transparent;
  }
  .gal__lbl--play { display: none; }
  #gal-pause:checked ~ .gal__pause .gal__lbl--pause { display: none; }
  #gal-pause:checked ~ .gal__pause .gal__lbl--play { display: inline; }
}

/* A slide owns 12.5% of the loop (100 / 8). It is opaque from 0% to 10.5%, fades out
   by 12.5%, stays hidden, then fades back in over the last 2.5% — so 100% and 0% are
   both opacity 1 and the loop closes seamlessly. The fade-in of the next slide happens
   during the fade-out of the current one, which is what makes it a crossfade rather
   than a cut. */
@keyframes gal-fade {
  0% { opacity: 1; }
  10.5% { opacity: 1; }
  12.5% { opacity: 0; }
  97.5% { opacity: 0; }
  100% { opacity: 1; }
}
@keyframes gal-drift {
  0% { transform: scale(1.045); }
  14% { transform: scale(1); }
  100% { transform: scale(1.045); }
}

/* ---------- the room: three photographs ---------- */

.section--room { background: var(--ink); }

.shots { display: grid; gap: clamp(0.75rem, 1.5vw, 1.25rem); }
.shots__item .pic { aspect-ratio: 4 / 3; }

/* ---------- quotes ---------- */

.quotes {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  margin-top: clamp(2.5rem, 6vw, 4.5rem);
}

.quote { margin: 0; position: relative; padding-left: 1.5rem; }
.quote::before {
  content: "";
  position: absolute;
  left: 0; top: 0.35em; bottom: 0.35em;
  width: 2px;
  background: linear-gradient(to bottom, var(--gold), transparent);
}
.quote__text p {
  font-family: var(--display);
  font-size: clamp(1.1rem, 1.7vw, 1.35rem);
  line-height: 1.45;
  color: var(--bone);
}
.quote__by {
  margin-top: 0.9rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.7rem;
  font-size: 0.8rem;
  color: var(--faint);
}
.quote__author { color: var(--dim); font-weight: 600; }
.quote__meta { display: inline-flex; align-items: center; gap: 0.45rem; flex-wrap: wrap; }
.quote__src {
  display: inline-block;
  padding-block: 0.2rem;
  color: var(--faint);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.quote__src:hover { color: var(--gold); }
.quote__translated { flex-basis: 100%; font-style: italic; }

.quote--card {
  padding: clamp(1.5rem, 3vw, 2rem);
  padding-left: clamp(1.5rem, 3vw, 2rem);
  background: var(--slate);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.quote--card::before { left: 0; top: 0; bottom: auto; width: 100%; height: 2px;
  background: linear-gradient(to right, var(--gold), transparent); }

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

.section--menu { background: var(--coal); }

.picks {
  display: grid;
  gap: 0;
  max-width: 54rem;
  margin-inline: auto;
  border-top: 1px solid var(--line);
}
.picks__item { border-bottom: 1px solid var(--line); }
.picks__link {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 1.35rem 0.5rem;
  text-decoration: none;
  transition: background var(--t-fast) var(--ease), padding-inline var(--t) var(--ease);
}
.picks__link:hover { background: rgba(244, 237, 227, 0.04); padding-inline: 1rem 1rem; }
.picks__n {
  flex: none;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--faint);
  min-width: 2.2rem;
}
.picks__name {
  font-family: var(--display);
  font-size: clamp(1.1rem, 1.9vw, 1.45rem);
  line-height: 1.2;
}
/* Same leader rule as the printed menu, so the two read as one document. */
.picks__leader {
  flex: 1 1 1.5rem;
  min-width: 1rem;
  border-bottom: 1px dotted var(--line);
  transform: translateY(-0.3em);
}
.picks__price {
  flex: none;
  font-family: var(--display);
  font-size: clamp(1rem, 1.6vw, 1.2rem);
  color: var(--amber);
  white-space: nowrap;
  font-feature-settings: "tnum" 1;
}
.picks__foot { margin-top: 2.5rem; display: grid; gap: 0.9rem; justify-items: center; text-align: center; }

/* The dish list, with the one photograph of the food beside it. */
.menu-grid { display: grid; gap: clamp(2rem, 4vw, 3rem); align-items: center; }
.menu-grid .picks { margin-inline: 0; max-width: none; }
.menu-grid__shot .pic { aspect-ratio: 4 / 5; }

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

.section--reviews { background: var(--ink); }
.reviews__cta { margin-top: 2.5rem; text-align: center; }

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

.section--visit { background: var(--coal); }
.visit { display: grid; gap: clamp(2rem, 5vw, 4rem); align-items: start; }

.facts { display: grid; gap: 1.5rem; margin-block: 2rem; }
.facts__row { display: grid; gap: 0.35rem; }
.facts__row > dt {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
}
.facts__row > dd { margin: 0; color: var(--bone); }
.facts address { font-style: normal; }

.hours { display: grid; gap: 0.35rem; }
.hours__row { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; }
.hours__row dt { color: var(--dim); min-width: 11rem; }
.hours__row dd { margin: 0; }
.hours__row.is-closed dd { color: var(--faint); }
.hours__note { color: var(--faint); font-size: 0.85em; }

.visit__shot .pic { aspect-ratio: 3 / 4; }

/* ---------- book ---------- */

.section--book { background: var(--ink); }
.book { max-width: 52rem; margin-inline: auto; }

.book__phones {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  margin-bottom: 2rem;
}
.phone {
  display: grid;
  gap: 0.2rem;
  padding: 1.5rem;
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  text-decoration: none;
  text-align: center;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.phone:hover { background: rgba(226, 85, 31, 0.08); border-color: var(--ember); }
.phone__label {
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
}
.phone__n {
  font-family: var(--display);
  font-size: clamp(1.6rem, 4vw, 2.4rem);
  line-height: 1.1;
  font-feature-settings: "tnum" 1;
}
.phone--alt .phone__n { font-size: clamp(1.3rem, 3vw, 1.8rem); color: var(--dim); }

.book__or {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-block: 2rem;
  color: var(--faint);
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.book__or::before,
.book__or::after { content: ""; flex: 1; height: 1px; background: var(--line); }

.book__form {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.1rem;
  padding: clamp(1.5rem, 4vw, 2.5rem);
  background: var(--slate);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.book__formtitle,
.book__formintro,
.book__submit,
.book__fallback,
.field--name,
.field--notes { grid-column: 1 / -1; }

.book__formtitle { font-size: 1.3rem; }
.book__formintro { font-size: 0.88rem; color: var(--faint); margin-top: -0.6rem; }

.field { display: grid; gap: 0.4rem; }
.field label {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
}
.field input {
  width: 100%;
  padding: 0.8rem 0.9rem;
  background: var(--coal);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  color: var(--bone);
  transition: border-color var(--t-fast) var(--ease);
}
.field input:hover { border-color: var(--dim); }
.field input::placeholder { color: var(--faint); }
.field__hint { font-size: 0.78rem; color: var(--faint); }

.field.is-invalid input { border-color: var(--ember-lift); }
.field__error { font-size: 0.78rem; color: var(--ember-lift); }

.book__submit { display: grid; gap: 0.75rem; justify-items: start; margin-top: 0.5rem; }
.book__note { font-size: 0.8rem; color: var(--faint); max-width: 46ch; }
.book__fallback:empty { display: none; }
.book__fallback { font-size: 0.85rem; color: var(--amber); }
.book__noscript { margin-top: 1.5rem; text-align: center; color: var(--dim); }

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

.menu-main { padding-top: 7rem; }
.mhead { padding-block: clamp(2rem, 6vw, 4rem) clamp(1.5rem, 4vw, 2.5rem); }
.mhead .shead { max-width: 34ch; }
.mhead .shead { font-size: clamp(2.4rem, 7vw, 5rem); }

.mjump {
  position: sticky;
  top: 4.25rem;
  z-index: 40;
  background: rgba(11, 10, 9, 0.9);
  backdrop-filter: blur(12px);
  border-block: 1px solid var(--line);
}
.mjump__list {
  display: flex;
  gap: 1.5rem;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 0.85rem var(--gutter);
  max-width: var(--wrap);
  margin-inline: auto;
}
.mjump__list::-webkit-scrollbar { display: none; }
.mjump__list a {
  display: inline-block;
  padding-block: 0.3rem;
  white-space: nowrap;
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--faint);
  transition: color var(--t-fast) var(--ease);
}
.mjump__list a:hover,
.mjump__list a.is-current { color: var(--gold); }

.menu-body { padding-block: clamp(2.5rem, 6vw, 4.5rem) 0; }

.msec { margin-bottom: clamp(3rem, 8vw, 5.5rem); scroll-margin-top: 8.5rem; }
.msec__title {
  font-size: clamp(1.8rem, 4vw, 2.9rem);
  padding-bottom: 0.8rem;
  border-bottom: 1px solid var(--gold);
  margin-bottom: 1.75rem;
}
.msec__note { color: var(--faint); font-size: 0.95rem; margin-top: -0.9rem; margin-bottom: 1.75rem; }

.mgroup { margin-bottom: 2.75rem; }
.mgroup__title {
  font-size: 1.28rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 1rem;
}

/* Dish rows.

   These were set a size too small. Two reasons, both worth recording. Marcellus is an
   inscriptional roman with a small x-height for its cap height, so it reads noticeably
   smaller than the same nominal size in a grotesque — the figure that looked right
   while the display face was Fraunces stopped being right when the face changed. And
   the menu page was ending up smaller than the five-dish teaser on the home page,
   which is backwards: this is the page people actually read, often standing up on a
   phone deciding whether to drive over.

   --mrow-num keeps the number column and the description's indent in step. They were
   two independent magic numbers before, which is a silent misalignment waiting to
   happen the next time either one moves. */
.mlist {
  --mrow-num: 2.4rem;
  display: grid;
  gap: 1.5rem;
  max-width: 48rem;
}
.mrow__head { display: flex; align-items: baseline; gap: 0.5rem; }
.mrow__n {
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--faint);
  min-width: var(--mrow-num);
  flex: none;
  font-feature-settings: "tnum" 1;
}
.mrow__name {
  font-family: var(--display);
  font-size: clamp(1.2rem, 1.5vw, 1.38rem);
  line-height: 1.3;
  /* Bigger type in a narrow column leaves long dish names wrapping with a single word
     stranded on the last line, right where the leader and the price meet it. */
  text-wrap: pretty;
}
/* The leader rule. A flexible spacer with a dotted bottom border stretches to fill
   whatever is left of the line, which is how a printed menu does it and what a
   fixed row of dots cannot do responsively. */
.mrow__leader {
  flex: 1 1 1rem;
  min-width: 1rem;
  border-bottom: 1px dotted var(--line);
  transform: translateY(-0.3em);
}
.mrow__price {
  font-family: var(--display);
  font-size: clamp(1.14rem, 1.4vw, 1.3rem);
  color: var(--amber);
  white-space: nowrap;
  font-feature-settings: "tnum" 1;
}
.mrow__desc {
  margin-top: 0.25rem;
  padding-left: calc(var(--mrow-num) + 0.5rem);
  font-size: 0.92rem;
  color: var(--faint);
  max-width: 52ch;
}

.mnotices {
  margin-block: clamp(2rem, 5vw, 3rem);
  padding: clamp(1.25rem, 3vw, 2rem);
  background: var(--coal);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.mnotices__title {
  font-size: 0.75rem;
  font-family: var(--ui);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.9rem;
}
.mnotices ul { display: grid; gap: 0.6rem; }
.mnotices li { font-size: 0.82rem; color: var(--faint); line-height: 1.55; }

.mfoot {
  display: grid;
  gap: 1rem;
  justify-items: center;
  text-align: center;
  padding-block: clamp(2rem, 6vw, 4rem);
}
.mfoot__pdf { display: grid; gap: 0.3rem; }

/* ---------- 404 ---------- */

.nf { min-height: 70svh; display: grid; place-items: center; padding-block: 9rem 6rem; }
.nf__in { text-align: center; }
.nf__code {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  color: var(--gold);
}
.nf__title { font-size: clamp(2.2rem, 6vw, 4rem); margin-top: 0.75rem; }
.nf__body { margin-top: 1rem; color: var(--dim); }
.nf__cta { margin-top: 2rem; display: flex; gap: 0.75rem; justify-content: center; flex-wrap: wrap; }

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

.site-foot {
  background: var(--coal);
  border-top: 1px solid var(--line);
  padding-top: clamp(3rem, 8vw, 5rem);
}
.site-foot__grid {
  display: grid;
  gap: clamp(2rem, 4vw, 3rem);
  grid-template-columns: 1fr;
}
.site-foot__mark { height: 3.5rem; width: auto; }
.site-foot__h {
  font-family: var(--ui);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.9rem;
}
.site-foot__addr { font-style: normal; color: var(--dim); line-height: 1.9; margin-bottom: 0.75rem; }
.site-foot__addr a { text-decoration: none; color: var(--bone); }
.site-foot__addr a:hover { color: var(--amber); }
.site-foot__social { display: grid; gap: 0.25rem; justify-items: start; }
.site-foot__social a {
  display: inline-block;
  padding-block: 0.35rem;
  color: var(--dim);
  text-decoration: none;
  font-size: 0.9rem;
}
.site-foot__social a:hover { color: var(--bone); }
.hours--foot .hours__row { display: grid; gap: 0; }
.hours--foot .hours__row dt { min-width: 0; font-size: 0.85rem; }
.hours--foot .hours__row dd { color: var(--dim); font-size: 0.9rem; margin-bottom: 0.5rem; }

.site-foot__base {
  margin-top: clamp(2.5rem, 6vw, 4rem);
  padding-block: 1.5rem;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2rem;
  justify-content: space-between;
  font-size: 0.78rem;
  color: var(--faint);
}
.site-foot__base a {
  display: inline-block;
  padding-block: 0.3rem;
  color: var(--dim);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.site-foot__base a:hover { color: var(--bone); }

/* ---------- mobile action bar ---------- */

.actionbar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 50;
  display: none;
  grid-template-columns: 1fr 1fr;
  background: rgba(11, 10, 9, 0.94);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
  transform: translateY(110%);
  transition: transform var(--t) var(--ease-out);
}
.actionbar.is-in { transform: translateY(0); }
.actionbar__item {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.95rem 0.5rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
}
.actionbar__item + .actionbar__item { border-left: 1px solid var(--line); }
.actionbar__item svg {
  width: 1.05rem; height: 1.05rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.actionbar__item--call { background: var(--ember); color: var(--ink); }
.actionbar__item--call svg { fill: currentColor; stroke: none; }

/* =========================================================================
   Motion

   Everything below is opt-in and additive: with JavaScript off, or with
   prefers-reduced-motion set, none of these rules apply and the page renders
   fully visible and static. That is why the hiding is scoped to .js.
   ========================================================================= */

@media (prefers-reduced-motion: no-preference) {
  /* Scroll-driven. `is-in` is added by an IntersectionObserver in main.js.
     The `unhide` animation is a safety net, not decoration: if main.js 404s, throws,
     is blocked by an extension, or the observer never fires because the page is in a
     context that is not compositing, the copy would otherwise stay invisible forever.
     After 1.4s it becomes visible on its own. In the normal case the observer has
     long since won and this never runs. */
  .js .reveal {
    opacity: 0;
    transform: translateY(22px);
    animation: unhide 1ms linear 1.4s forwards;
  }
  .js .reveal.is-in {
    opacity: 1;
    transform: none;
    animation: none;
    transition: opacity var(--t-slow) var(--ease-out) calc(70ms * var(--i, 0)),
      transform var(--t-slow) var(--ease-out) calc(70ms * var(--i, 0));
  }

  /* Headings wipe up from behind their own baseline. The wrapper clips, the span
     moves — no text is ever mid-transform when it is read by a screen reader,
     because the wrapper keeps its box. */
  .js .rise { overflow: hidden; }
  .js .rise > span {
    display: block;
    transform: translateY(102%);
    animation: unrise 1ms linear 1.4s forwards;
  }
  .js .rise.is-in > span {
    transform: none;
    animation: none;
    transition: transform 1100ms var(--ease-out);
  }

  /* Above the fold. These animate on load and are never observed: hero copy must not
     wait on an observer to become readable, and the h1 is a candidate for LCP. */
  .js .enter {
    animation: enter-fade 900ms var(--ease-out) both;
    animation-delay: calc(90ms * var(--i, 0) + 180ms);
  }
  .js .enter-rise { overflow: hidden; }
  .js .enter-rise > span {
    display: block;
    animation: enter-rise 1100ms var(--ease-out) both;
    animation-delay: calc(90ms * var(--i, 0) + 100ms);
  }

  .js .quotes .quote:nth-child(2) { --i: 1; }
  .js .quotes .quote:nth-child(3) { --i: 2; }

  /* Photographs unveil rather than fade: the frame wipes open from the bottom while
     the image inside settles back from a slight push-in. It is the difference between
     a picture appearing and a picture being revealed, and it costs two properties. */
  .js .shots__item .pic,
  .js .visit__shot .pic,
  .js .menu-grid__shot .pic {
    clip-path: inset(0 0 100% 0);
  }
  .js .shots__item .pic img,
  .js .visit__shot .pic img,
  .js .menu-grid__shot .pic img {
    transform: scale(1.12);
  }
  .js .shots__item.is-in .pic,
  .js .visit__shot.is-in .pic,
  .js .menu-grid__shot.is-in .pic {
    clip-path: inset(0 0 0 0);
    transition: clip-path 1200ms var(--ease-out) calc(90ms * var(--i, 0));
  }
  .js .shots__item.is-in .pic img,
  .js .visit__shot.is-in .pic img,
  .js .menu-grid__shot.is-in .pic img {
    transform: none;
    transition: transform 1600ms var(--ease-out) calc(90ms * var(--i, 0));
  }
  /* The wipe replaces the generic fade-up on these, or they would do both. */
  .js .shots__item.reveal,
  .js .visit__shot.reveal,
  .js .menu-grid__shot.reveal {
    opacity: 1;
    transform: none;
    animation: none;
  }

  /* The primary button fills from the left on hover instead of just changing colour. */
  .js .btn--primary { position: relative; overflow: hidden; isolation: isolate; }
  .js .btn--primary::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--ember-lift);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--t) var(--ease-out);
  }
  .js .btn--primary:hover::before { transform: scaleX(1); }
}

@keyframes unhide { to { opacity: 1; transform: none; } }
@keyframes unrise { to { transform: none; } }
@keyframes enter-fade {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: none; }
}
@keyframes enter-rise {
  from { transform: translateY(102%); }
  to { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .hero__pic img { transform: none; }
  .actionbar { transform: none; }
}

/* =========================================================================
   Breakpoints

   Mobile-first. The layout changes at 40rem (large phone / small tablet),
   48rem (tablet) and 62rem (laptop). Each one is a real layout change, not a
   scaled-down desktop.
   ========================================================================= */

/* This breakpoint is also declared as MQ.phone in src/lib/media.js, where the hero's
   art-directed <source media> reads it. The two must stay identical: if they drift, the
   portrait hero crop renders inside the desktop layout for a range of widths. */
@media (max-width: 47.999rem) {
  .nav { display: none; }
  .site-head__book { display: none; }
  .burger { display: block; }
  .actionbar { display: grid; }
  /* Clear the action bar so the last section is never trapped under it. */
  body { padding-bottom: 3.75rem; }

  .book__form { grid-template-columns: 1fr; }
  .mjump { top: 3.9rem; }
  /* Give the dish name back the width the number column was holding — on a phone the
     name is competing with the number, the leader and the price for ~180px. */
  .mlist { --mrow-num: 1.9rem; }
  .mrow__leader { flex-basis: 0.5rem; min-width: 0.5rem; }
}

@media (min-width: 40rem) {
  .book__phones { grid-template-columns: 1fr 1fr; }
  .quotes--two { grid-template-columns: repeat(2, 1fr); }
  .proof__in { flex-wrap: nowrap; }
  /* Two square-ish shots, then the third full width beneath them. */
  .shots { grid-template-columns: 1fr 1fr; }
  .shots__item:nth-child(3) { grid-column: span 2; }
  .shots__item:nth-child(3) .pic { aspect-ratio: 21 / 9; }
}

@media (min-width: 62rem) {
  /* Three across, the middle one dropped — the room photographs are all the same
     shape, and a flat row of three reads as a stock grid. */
  .shots { grid-template-columns: repeat(3, 1fr); }
  .shots__item:nth-child(3) { grid-column: auto; }
  .shots__item:nth-child(3) .pic { aspect-ratio: 4 / 3; }
  .shots__item:nth-child(2) { transform: translateY(clamp(1rem, 3.5vw, 2.75rem)); }
  .visit { grid-template-columns: 1.25fr 0.75fr; }
  .quotes--three { grid-template-columns: repeat(3, 1fr); }
  .site-foot__grid { grid-template-columns: 1.4fr 1fr 1fr 0.8fr; }
  .menu-grid { grid-template-columns: 1fr 0.42fr; }
}

/* Fine pointers get hover affordances that would be dead weight on touch. */
@media (hover: none) {
  .btn:hover { transform: none; }
  .picks__link:hover { padding-inline: 0.5rem; }
}

@media print {
  .site-head, .actionbar, .mjump, .site-foot__social { display: none !important; }
  body { background: #fff; color: #000; }
  .msec__title { border-color: #000; }
  .mrow__price { color: #000; }
}
