/* Template 4 — coastal. Three pages off one stylesheet: index, board, visit.
   Spec: design/salt-and-pine/*.dc.html (published canvas).
   Why it looks like this: design/salt-and-pine/RESEARCH.md — three real seafood
   sites, and what was taken from each.

   THE DESIGN LOCK, in one line: rules, never cards.

   Not one selector in this file sets a border-radius or a box-shadow. Depth
   comes from four rule weights and two pine bands. That is the whole reason
   this template does not read as the restaurant one wearing a green coat —
   which is what Salt & Pine shipped as before, and the problem this fixes.

   The second lock is typographic: the display serif carries VOICE, the mono
   carries FACT. Prices, hours, addresses, landing times and boat names are all
   mono; no heading is ever set in it. Both locks are enforced by eye, not by a
   tool — audit-page.js cannot see either.

   Container standard, from the page-build skill:
     stacked content  -> .wrap
     full-width band  -> the SECTION spans 100%, with a .wrap inside it
   --maxw is 1312 because the artboard is 1440 with 64px gutters. Never 100vw:
   it includes the scrollbar and pushes a horizontal scrollbar on every desktop
   with a classic one. */

:root {
  --maxw: 1312px;
  --gutter: 64px;

  /* Overridden per business by {{CSS_VARS}} in the head. These are the
     fallbacks, and they are the artboard's values. */
  --bg: #f6f4ee;
  --surface: #ffffff;
  --ink: #1a1e1c;
  --muted: #6e7472;
  --line: #dfdbd1;
  --brand: #2f4a42;
  --brand-dark: #1f332d;
  --on-brand: #f6f4ee;
  --accent: #8a7a5c;
  --foot-bg: #1f332d;
  --foot-ink: #f6f4ee;
  --band-up: #fbfaf6;
  --band-down: #edeae1;

  /* Derived, so a business that recolours the template does not have to supply
     twelve hexes to keep the rules coherent. */
  /* Opaque on purpose: mixed toward the page ground rather than to transparent,
     so the same token reads the same over bone and over the tonal band, and so
     it computes to an rgb() the spec diff can actually compare. */
  --ink-dim: color-mix(in srgb, var(--ink) 78%, var(--bg));
  /* The same dim ink, read against the tonal band instead of the page ground.
     One token, two grounds - which is what the artboard draws. */
  --ink-dim-band: color-mix(in srgb, var(--ink-dim) 90%, var(--band-down));
  --line-strong: color-mix(in srgb, var(--ink) 22%, transparent);
  --on-dark: #bfc8c3;
  --on-dark-dim: #8fa097;
  --rule-dark: color-mix(in srgb, var(--foot-ink) 18%, transparent);

  --font-display: "Newsreader", Georgia, "Times New Roman", serif;
  --font-body: "Newsreader", Georgia, "Times New Roman", serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --ease: cubic-bezier(.2, .7, .3, 1);
  /* Entrances only. Nearly all of the distance is covered in the first third,
     so a short travel still reads as deliberate instead of as a slow slide. */
  --ease-out: cubic-bezier(.22, 1, .36, 1);
}

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

.wrap {
  width: min(var(--maxw), 100% - calc(var(--gutter) * 2));
  margin-inline: auto;
}

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

/* --- type ------------------------------------------------------------------
   Newsreader ships 200-800 as a variable face; 300 is the display weight and it
   is a real instance, not a synthesised one. */

.dsp { font-family: var(--font-display); font-weight: 300; letter-spacing: -0.02em; }

.h1 { font-size: clamp(42px, 5.3vw, 76px); line-height: 1.02; margin: 0; letter-spacing: -0.02em; }
.h2 { font-size: clamp(32px, 3.9vw, 56px); line-height: 1.04; margin: 0; letter-spacing: -0.015em; }
.h3 { font-size: clamp(26px, 3.4vw, 46px); line-height: 1.06; margin: 0; letter-spacing: -0.015em; }
.h4 { font-size: 26px; line-height: 1.15; margin: 0; font-weight: 400; }

.hl { font-style: italic; color: var(--accent); }

.mono { font-family: var(--font-mono); }

/* The factual layer. One class, three sizes, used everywhere a value appears. */
.tag {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--muted); margin: 0;
}
.fact { font-family: var(--font-mono); font-size: 14px; overflow-wrap: anywhere; }
.fact--lg { font-size: 15px; line-height: 1.8; }
/* The phone and the email on the visit page are the two things a visitor
   actually taps. They sit inside a text block, so each gets the target height
   rather than the paragraph getting it. */
.fact a { display: inline-flex; align-items: center; min-height: 44px; }
.micro { font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; }

.lede { font-size: 18px; line-height: 1.55; color: var(--ink-dim); margin: 0; max-width: 46ch; }
/* The visit copy is body size, not lede size - it sits under a heading that is
   already doing the work - and it sits on the tonal band. */
.lede--body { font-size: 17px; color: var(--ink-dim-band); }
.p { margin: 0; color: var(--muted); line-height: 1.6; }
.muted { color: var(--muted); }

/* --- controls --------------------------------------------------------------
   Square. A pill would read as a different template. outline, never border: a
   1px border makes an outlined button 2px wider than a filled one, so the pair
   never lines up; outline draws inside and takes no space. */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 16px 30px;
  font: inherit; font-size: 15px;
  border: 0; background: none; cursor: pointer;
  min-height: 48px;
  transition: background-color .16s ease, color .16s ease;
}
.btn--brand { background: var(--brand); color: var(--on-brand); }
.btn--brand:hover { background: var(--brand-dark); }
.btn--ghost { outline: 1px solid var(--ink); outline-offset: -1px; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--bg); }
.btn--light { background: var(--bg); color: var(--brand-dark); }
.btn--light:hover { background: var(--surface); }
.btn--onDark { outline: 1px solid var(--on-dark-dim); outline-offset: -1px; color: var(--foot-ink); }
.btn--onDark:hover { background: var(--foot-ink); color: var(--brand-dark); }
.btn--sm { padding: 14px 26px; font-size: 14px; min-height: 44px; letter-spacing: .06em; }
/* Brass, so it is visible on bone and on pine alike. */
.btn:focus-visible, a:focus-visible, button:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 3px;
}

/* The quiet link: a rule that draws in on hover. The one animated line here. */
.qlink {
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .13em;
  text-transform: uppercase; padding-bottom: 3px;
  border-bottom: 1px solid transparent;
  transition: border-color .18s var(--ease), color .18s var(--ease);
  /* A 12px line is a 17px box; the padding is what makes it a target. */
  display: inline-flex; align-items: center; min-height: 44px;
}
.qlink:hover { border-bottom-color: var(--brand); color: var(--brand); }

.icon { width: 18px; height: 18px; flex: none; }

/* Status dot. A live fact, so it sits in the mono layer. */
.dot { width: 7px; height: 7px; background: var(--brand); flex: none; }
.dot--shut { background: var(--muted); }

/* --- status strip + nav ----------------------------------------------------
   The strip is the dated, changing thing, above everything else — the move
   taken from The Ordinary's announcement bar and from every seafood site that
   treats freshness as a layout problem rather than a copy one. */

.strip {
  background: var(--brand); color: var(--on-brand);
  padding: 11px 0;
}
.strip__in { display: flex; gap: 32px; align-items: baseline; justify-content: space-between; }
.strip__t { font-family: var(--font-mono); font-size: 12px; letter-spacing: .13em; text-transform: uppercase; margin: 0; }
.strip__n { font-family: var(--font-mono); font-size: 12px; letter-spacing: .13em; text-transform: uppercase; margin: 0; opacity: .72; }

.nav {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  backdrop-filter: saturate(1.3) blur(10px);
  border-bottom: 1px solid var(--line);
  transition: border-color .2s ease;
}
.nav__in { display: flex; align-items: center; justify-content: space-between; gap: 48px; min-height: 82px; transition: min-height .2s var(--ease); }
/* The builder nests the mark: .mark__stack wraps .mark__text and .mark__sub.
   Styling the anchor as the flex row put the gap between the anchor and one
   child, so the two words ran together as SALT& PINE. */
.nav__mark { display: flex; align-items: center; min-height: 44px; font-family: var(--font-display); font-weight: 300; font-size: 25px; letter-spacing: .22em; text-transform: uppercase; transition: font-size .2s var(--ease); }
.nav__mark .mark__stack, .foot__mark .mark__stack { display: flex; align-items: baseline; gap: 10px; }
.nav__mark .mark__sub, .foot__mark .mark__sub { color: var(--accent); }
.nav__links { display: flex; gap: 34px; align-items: center; list-style: none; margin: 0; padding: 0; }
.nav__links a {
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .15em;
  text-transform: uppercase;
  border-bottom: 1px solid transparent;
  /* A 12px line is a 17px box. The rule has to sit at the bottom of a 44px
     target, so the box is padded to the target and the underline rides its
     edge - not the other way round. */
  display: inline-flex; align-items: flex-end; min-height: 44px; padding-bottom: 13px;
}
.nav__links a:hover { border-bottom-color: var(--line-strong); }
.nav__links [aria-current="page"] { border-bottom-color: var(--ink); }
.nav__cta { display: flex; gap: 18px; align-items: center; flex: none; }
.nav__tel { font-family: var(--font-mono); font-size: 13px; display: inline-flex; align-items: center; min-height: 44px; }

/* Condensed past the hero. It swaps the link row for the live status line — the
   one fact worth the space once you are reading the board. The rule under it
   darkens instead of a shadow appearing, because nothing here lifts. */
.nav.is-stuck { border-bottom-color: var(--line-strong); }
.nav.is-stuck .nav__in { min-height: 56px; }
.nav.is-stuck .nav__mark { font-size: 18px; }

/* --- hero ------------------------------------------------------------------
   Split: the type panel sits BESIDE the photograph, never over it. On track A
   the photo comes straight off the lead's own site and we do not choose it, so
   a dark or badly lit frame must not be able to make the page unreadable. */

.hero { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: stretch; border-bottom: 1px solid var(--line); }
.hero__copy {
  display: flex; flex-direction: column; justify-content: center; gap: 30px;
  padding: 96px var(--gutter);
  padding-left: max(var(--gutter), calc((200% - var(--maxw)) / 2));
  min-height: 660px;
}
.hero__lede { max-width: 44ch; }
.hero__cta { display: flex; gap: 14px; flex-wrap: wrap; }
.hero__rule { border: 0; border-top: 1px solid var(--line); margin: 0; }
.hero__facts {
  display: flex; gap: 30px; flex-wrap: wrap; list-style: none; margin: 0; padding: 0;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted);
}
.hero__facts li { display: inline-flex; align-items: center; gap: 8px; }
.hero__facts .fact--now { color: var(--brand); }
.hero__media { border-left: 1px solid var(--line); overflow: hidden; }
.hero__img { width: 100%; height: 100%; min-height: 660px; object-fit: cover; }

/* Hero entrance — CSS, not the JS reveal.
   Everything else on the page is hidden by a .js class and un-hidden when the
   observer says the visitor reached it. Correct below the fold, wrong here:
   site.js is deferred, so gating the hero on it leaves the headline — the LCP
   element — invisible until the script has downloaded and run. A keyframe off
   this render-blocking stylesheet starts at first paint and still plays with JS
   broken, blocked or slow. Under a third of a second, first line to last. */
@media (prefers-reduced-motion: no-preference) {
  [data-reveal="hero"] > * { animation: hero-in .45s var(--ease-out) both; }
  [data-reveal="hero"] > *:nth-child(1) { animation-delay: .04s; }
  [data-reveal="hero"] > *:nth-child(2) { animation-delay: .09s; }
  [data-reveal="hero"] > *:nth-child(3) { animation-delay: .14s; }
  [data-reveal="hero"] > *:nth-child(4) { animation-delay: .19s; }
  [data-reveal="hero"] > *:nth-child(5) { animation-delay: .24s; }
  [data-reveal="hero"] > *:nth-child(6) { animation-delay: .29s; }
  /* The photograph comes up under the type so the eye gets the headline first.
     No travel: a full-bleed panel has nowhere to slide from, and a crop shifting
     on load reads as a layout bug. */
  [data-reveal="hero-media"] { animation: hero-fade .6s var(--ease-out) .1s both; }
}
@keyframes hero-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes hero-fade { from { opacity: 0; } to { opacity: 1; } }

/* --- sections --------------------------------------------------------------- */

.sec { padding: 104px 0 88px; }
.sec--tight { padding: 88px 0; }
.sec--flush { padding: 0; }
/* A section that opens with its own 2px rule does not also need the previous
   section-s bottom padding doubled above it. */
.sec--joined { padding-top: 0; }
.band-down { background: var(--band-down); }
.band-dark { background: var(--brand-dark); color: var(--foot-ink); }

.sec__head { display: flex; align-items: flex-end; justify-content: space-between; gap: 40px; padding-bottom: 26px; }
.sec__headings { display: flex; flex-direction: column; gap: 14px; }
.sec__stamp { font-family: var(--font-mono); font-size: 12px; letter-spacing: .13em; text-transform: uppercase; color: var(--muted); text-align: right; margin: 0; }

/* Rule weights. Four, and that is all — see the Identity artboard.
     2px ink   section opens
     1px ink   group head
     1px line  row divider
     1px dot   price leader */
.rule-open { border-top: 2px solid var(--ink); }
.rule-head { border-top: 1px solid var(--ink); }
.rule { border: 0; border-top: 1px solid var(--line); margin: 0; }

/* --- the board -------------------------------------------------------------
   The centrepiece, and the reason this template exists. A dated manifest: the
   section label sits in its own narrow column the way a manifest is set, every
   item gets a rule under it, and the price rides a dotted leader in mono.

   The builder emits menu__h, an optional menu__note and menu__items as three
   siblings. Grid places the first two in the label column and spans the items
   beside them, so the markup stays the shared one. */

.board__intro { margin: 22px 0 0; max-width: 62ch; color: var(--ink-dim); }
.board__list { padding-top: 42px; }

.menu__section {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  /* auto then 1fr: the label row hugs the label, and the standfirst starts at
     the top of what is left. Two auto rows would split the column height and
     drop the standfirst into the middle of it, which is what shipped first. */
  grid-template-rows: auto 1fr;
  column-gap: 48px;
  padding: 34px 0;
  border-top: 1px solid var(--line);
}
.menu__section:last-child { border-bottom: 1px solid var(--line); }
.menu__h {
  grid-column: 1; grid-row: 1;
  display: flex; align-items: baseline; gap: 10px; margin: 0;
  font-family: var(--font-mono); font-size: 13px; font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase; color: var(--brand);
}
/* The shared builder puts a category icon in every menu head. This design has
   none — the mono label is the whole affordance — so it is hidden rather than
   the markup forked. */
.menu__h svg { display: none; }
.menu__note {
  grid-column: 1; grid-row: 2; align-self: start;
  margin: 8px 0 0;
  font-family: var(--font-mono); font-size: 11px; color: var(--muted);
}
.menu__items {
  grid-column: 2; grid-row: 1 / span 2;
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column;
}
/* No note: the items still span from the first row. */
.menu__section:not(:has(.menu__note)) .menu__items { grid-row: 1 / span 2; }

.item { display: flex; flex-direction: column; gap: 5px; padding: 18px 0; border-top: 1px solid var(--band-down); }
.item:first-child { padding-top: 0; border-top: 0; }
.item:last-child { padding-bottom: 0; }
.item__top { display: flex; align-items: baseline; gap: 14px; margin: 0; }
.item__name { font-size: 22px; }
.item__tags { display: inline-flex; gap: 6px; }
.item__tag {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--accent);
  outline: 1px solid var(--line); outline-offset: -1px; padding: 2px 6px;
}
.item__lead { flex-grow: 1; border-bottom: 1px dotted var(--line); transform: translateY(-5px); }
.item__price { font-family: var(--font-mono); font-size: 15px; flex: none; }
.item__desc { margin: 0; color: var(--muted); font-size: 16px; }

/* The one line that changed since yesterday. It fills and bleeds 18px past the
   text column: a ledger row marked, not a card lifted. */
.item--today { background: var(--band-down); margin: 0 -18px; padding-left: 18px; padding-right: 18px; }
.item--today .item__lead { border-bottom-color: color-mix(in srgb, var(--line) 70%, var(--ink)); }
.item--today .item__desc { color: var(--ink-dim-band); }
.item__today {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--on-brand); background: var(--brand);
  padding: 3px 7px; flex: none;
}

.board__foot { display: flex; align-items: baseline; justify-content: space-between; gap: 30px; padding-top: 22px; }
.board__note { font-family: var(--font-mono); font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin: 0; }


/* --- the board, full-page variant -------------------------------------------
   On its own page the board has the whole measure, so it stops being a label
   column beside a list and becomes what a printed board actually is: the
   movement named across the top with a rule under it, and the dishes set in two
   columns beneath. Same markup, same builder - only the grid changes. */
.board--wide .menu__section {
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto auto;
  column-gap: 20px;
  padding: 0 0 54px;
  border-top: 0;
}
.board--wide .menu__section:last-child { border-bottom: 0; }
.board--wide .menu__h { grid-column: 1; grid-row: 1; font-size: 14px; letter-spacing: .22em; }
.board--wide .menu__note { grid-column: 2; grid-row: 1; margin: 0; justify-self: start; align-self: baseline; }
.board--wide .menu__items {
  grid-column: 1 / span 2; grid-row: 2;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 72px;
  border-top: 1px solid var(--ink); margin-top: 12px;
}
.board--wide .item { padding: 22px 0; border-top: 0; border-bottom: 1px solid var(--line); }
.board--wide .item:first-child { padding-top: 22px; }
.board--wide .item:last-child { padding-bottom: 22px; }
.board--wide .item--today { margin: 0 -18px; }

/* The page head is a 1.6/1 split, so the title column has the same measure the
   artboard drew it at rather than shrinking to its longest line. */
.sec__head--split { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 72px; align-items: end; }

/* --- landings --------------------------------------------------------------
   A ruled frame, not a card: one hairline box, no fill, no shadow. Angler's
   double-ruled hours panel is the reference. */

.landings { border: 1px solid var(--brand); padding: 30px 34px; display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 48px; align-items: center; }
.landings__lab { display: flex; flex-direction: column; gap: 8px; }
.landings__lab p { margin: 0; }
.landings__list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 34px; }
.land { display: flex; flex-direction: column; gap: 5px; border-left: 1px solid var(--line); padding-left: 20px; }
.land__what { margin: 0; font-size: 21px; }
.land__from { margin: 0; font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }

/* --- the catch -------------------------------------------------------------- */

.craft { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 88px; align-items: start; }
.craft__copy { display: flex; flex-direction: column; gap: 26px; }
.craft__kicker { font-family: var(--font-mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--accent); margin: 0; }
.craft__body { margin: 0; color: var(--on-dark); max-width: 50ch; }
.stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; list-style: none; margin: 0; padding: 16px 0 0; }
.stat { display: flex; flex-direction: column; gap: 10px; border-top: 1px solid var(--rule-dark); padding-top: 16px; }
.stat__n { font-family: var(--font-mono); font-size: 44px; line-height: 1; margin: 0; color: var(--foot-ink); }
.stat__l { font-family: var(--font-mono); font-size: 11px; letter-spacing: .11em; text-transform: uppercase; color: var(--on-dark-dim); margin: 0; }
.prints { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.print { width: 100%; height: 420px; object-fit: cover; }
.print--2 { align-self: end; }

/* --- the room: an edge-to-edge photo band, no page gutter, no captions.
   Hog Island's three-up, taken as four. --- */

.gallery { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; list-style: none; margin: 0; padding: 0; }
.gallery li { overflow: hidden; }
.gallery img { width: 100%; height: 300px; object-fit: cover; transition: transform .5s var(--ease); }
.gallery li:hover img { transform: scale(1.03); }

/* --- reviews: ruled quotes, not cards --------------------------------------- */

.rating { display: flex; align-items: baseline; gap: 20px; padding-bottom: 34px; font-family: var(--font-mono); font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.rating strong { font-size: 34px; font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--ink); }
.quotes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 72px; list-style: none; margin: 0; padding: 0; }
.quote { display: flex; flex-direction: column; gap: 14px; padding: 30px 0; border-top: 1px solid var(--line); }
/* The rating summary already carries the score. A row of star glyphs on top of
   it is the second telling, and glyph stars are a dingbat — see the repo rule. */
.quote__stars { display: none; }
.quote__text { margin: 0; font-size: 20px; line-height: 1.5; }
.quote__by { margin: 0; font-family: var(--font-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }

/* --- three ways in ---------------------------------------------------------- */

.ways { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 56px; padding-top: 40px; }
.util { display: flex; flex-direction: column; gap: 12px; }
/* The numeral is the template's, not the content's — the content supplies three
   headings and the design counts them. */
.util::before {
  content: counter(util, decimal-leading-zero);
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .16em; color: var(--accent);
}
.ways { counter-reset: util; }
.util { counter-increment: util; }
.util__img { display: none; }
/* The standfirst. On the home page it sits under the numeral as a label; on
   the visit split it is the whole eyebrow. */
.util__k {
  margin: 0; font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
}
/* Shown in both places. Hiding it on the home columns did not remove a
   decoration, it removed a fact - "ten stools, no bookings" exists nowhere else
   on the page once the standfirst is lifted out of the body. */
.util__h { margin: 0; font-size: 26px; font-weight: 400; }
.util__p { margin: 0; color: var(--muted); font-size: 16px; }

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

.visit { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 88px; }
.visit__copy { display: flex; flex-direction: column; gap: 26px; }
.visit__addr { display: flex; flex-direction: column; gap: 4px; font-family: var(--font-mono); font-size: 14px; }
.visit__addr .muted { color: var(--muted); }
.visit__cta { display: flex; gap: 14px; flex-wrap: wrap; }

.hours__head { display: flex; align-items: baseline; justify-content: space-between; border-bottom: 2px solid var(--ink); padding-bottom: 12px; }
.hours__lab { font-family: var(--font-mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; margin: 0; }
.hours__now { font-family: var(--font-mono); font-size: 11px; letter-spacing: .13em; text-transform: uppercase; color: var(--brand); margin: 0; display: inline-flex; align-items: center; gap: 8px; }
.hours {
  display: grid; grid-template-columns: auto auto; align-content: start;
  margin: 0; font-family: var(--font-mono); font-size: 14px;
}
.hours dt, .hours dd { padding: 15px 0; border-bottom: 1px solid var(--line); margin: 0; }
.hours dd { text-align: right; }
.hours dd.closed { color: var(--muted); }
.hours dt[data-today], .hours dt[data-today] + dd { font-weight: 500; }
.hours__note { margin: 18px 0 0; font-family: var(--font-mono); font-size: 12px; line-height: 1.7; color: var(--muted); }

/* Map: a ruled frame with a drawn pin. Never a dingbat glyph. */
.visit__map { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 56px; align-items: stretch; }
.map { border: 1px solid var(--line); background: var(--band-down); min-height: 380px; display: flex; align-items: center; justify-content: center; }
.map__in { display: flex; flex-direction: column; align-items: center; gap: 12px; }

/* --- split panel (the bar / private evenings) -------------------------------- */

.split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: stretch; border-top: 1px solid var(--line); }
.split__copy {
  display: flex; flex-direction: column; justify-content: center; gap: 20px;
  padding: 72px var(--gutter);
  padding-left: max(var(--gutter), calc((200% - var(--maxw)) / 2));
}
.split__media { border-left: 1px solid var(--line); overflow: hidden; }
.split__copy .util { gap: 16px; }
.split__copy .util::before { content: none; }
.split__copy .util__k { color: var(--muted); }
.split__copy .util__h { font-family: var(--font-display); font-size: clamp(28px, 3vw, 42px); font-weight: var(--display-weight, 300); line-height: 1.06; letter-spacing: -0.015em; }
.split__copy .util__p { font-size: 17px; line-height: 1.55; color: var(--ink-dim); max-width: 42ch; }
.split__media img { width: 100%; height: 100%; min-height: 560px; object-fit: cover; }

/* --- call band --------------------------------------------------------------- */

.call { background: var(--brand); color: var(--on-brand); padding: 60px 0; }
.call__in { display: flex; align-items: center; justify-content: space-between; gap: 48px; flex-wrap: wrap; }

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

.foot { background: var(--foot-bg); color: var(--foot-ink); padding: 72px 0 44px; }
.foot__cols { display: grid; grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr)); gap: 56px; }
.foot__col { display: flex; flex-direction: column; gap: 12px; }
.foot__h {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .16em;
  text-transform: uppercase; margin: 0;
  border-bottom: 1px solid var(--accent); padding-bottom: 8px; align-self: flex-start;
}
.foot__col a, .foot__col span { font-family: var(--font-mono); font-size: 13px; color: var(--on-dark); overflow-wrap: anywhere; }
.foot__col a { display: inline-flex; align-items: center; min-height: 44px; align-self: flex-start; }
/* The column is a flex stack, so the taller targets would space themselves
   apart twice; take the gap back rather than let the footer grow. */
.foot__col { gap: 0; }
.foot__col .foot__h { margin-bottom: 12px; }
.foot__col span { padding: 10px 0; }
.foot__col a:hover { color: var(--foot-ink); }
.foot__mark { display: flex; font-family: var(--font-display); font-weight: 300; font-size: 22px; letter-spacing: .22em; text-transform: uppercase; }
.foot__blurb { margin: 0; font-family: var(--font-mono); font-size: 12px; line-height: 1.8; color: var(--on-dark-dim); }
.foot__legal { border-top: 1px solid var(--rule-dark); margin-top: 48px; padding-top: 22px; }
/* The credit is a link inside a sentence, so it cannot be a 44px box without
   breaking the line it sits in. Padded to a comfortable target instead. */
.foot__legal a { padding: 12px 0; }
.foot__legal p { margin: 0; font-family: var(--font-mono); font-size: 11px; color: color-mix(in srgb, var(--foot-ink) 45%, transparent); }
.foot__legal a { color: inherit; border-bottom: 1px solid currentColor; }

/* --- motion ------------------------------------------------------------------
   The hidden state only ever applies when the script has set .js on <html>.
   No JS -> no hidden state -> the page renders complete. The failure mode is
   "no animation", never "no content". */

.js .reveal { opacity: 0; transform: translateY(10px); }
.js .reveal.is-in { opacity: 1; transform: none; transition: opacity .4s var(--ease-out), transform .4s var(--ease-out); }
/* On screen at load: shown with no transition. Content in the first viewport
   fading in after load is worse than no animation. */
.js .reveal.is-now { transition: none; }

/* ONE FADE PER ELEMENT. The children slide, they do not fade: a row inside a
   section that is itself fading has both opacities multiplied together, so it
   sits under 20% for most of the transition and the band reads as washed out
   rather than as arriving. The section owns the fade; the stagger owns the
   travel, and the cascade is legible because it is the only thing moving. */
.js .reveal [data-stagger] > * { transform: translateY(16px); }
.js .reveal.is-in [data-stagger] > * {
  transform: none;
  transition: transform .42s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 45ms);
}
.js .reveal.is-now,
.js .reveal.is-now [data-stagger] > * { transition: none; }

/* Capture: screenshot.js and export-assets.js set this so a half-revealed page
   never lands in an exported carousel slide. */
html[data-capture] .reveal,
html[data-capture] .reveal.is-in { opacity: 1 !important; transform: none !important; }
html[data-capture] .reveal [data-stagger] > * { opacity: 1 !important; transform: none !important; }
html[data-capture] [data-reveal="hero"] > *,
html[data-capture] [data-reveal="hero-media"] { animation: none !important; opacity: 1 !important; transform: none !important; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
  .js .reveal { opacity: 1; transform: none; }
  .js .reveal [data-stagger] > * { transform: none; }
}

/* --- responsive ---------------------------------------------------------------
   Three stops. The board's label column is the thing that has to give: below
   1024 it goes above the items rather than beside them, which is how a printed
   board sets on a narrow page anyway. */

@media (max-width: 1180px) {
  :root { --gutter: 40px; }
  .craft, .visit { gap: 56px; }
  .foot__cols { gap: 36px; }
}

@media (max-width: 1024px) {
  .hero { grid-template-columns: minmax(0, 1fr); }
  .hero__copy { padding: 64px var(--gutter); min-height: 0; }
  .hero__media { border-left: 0; border-top: 1px solid var(--line); }
  .hero__img { min-height: 0; height: 320px; }
  .menu__section { grid-template-columns: minmax(0, 1fr); row-gap: 0; }
  .menu__h, .menu__note, .menu__items { grid-column: 1; }
  .menu__h { grid-row: 1; }
  .menu__note { grid-row: 2; }
  .menu__items { grid-row: 3; padding-top: 18px; }

  .board--wide .menu__items { grid-template-columns: minmax(0, 1fr); column-gap: 0; }
  .board--wide .menu__section { grid-template-columns: minmax(0, 1fr); }
  .board--wide .menu__h { grid-row: 1; }
  .board--wide .menu__note { grid-column: 1; grid-row: 2; }
  .board--wide .menu__items { grid-row: 3; }
  .sec__head--split { grid-template-columns: minmax(0, 1fr); gap: 20px; }

  .craft, .visit { grid-template-columns: minmax(0, 1fr); }
  .landings { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .landings__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .split { grid-template-columns: minmax(0, 1fr); }
  .split__copy { padding: 56px var(--gutter); }
  .split__media { border-left: 0; border-top: 1px solid var(--line); }
  .split__media img { min-height: 0; height: 340px; }
  .gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .visit__map { grid-template-columns: minmax(0, 1fr); gap: 36px; }
  .foot__cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .nav__links { display: none; }
}

@media (max-width: 720px) {
  :root { --gutter: 20px; }
  .sec { padding: 56px 0 48px; }
  .sec--tight { padding: 48px 0; }
  .strip__in { gap: 16px; }
  .strip__n { display: none; }
  .sec__head { flex-direction: column; align-items: flex-start; gap: 16px; }
  .sec__stamp { text-align: left; }
  .quotes { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .ways { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .stats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
  .stat__n { font-size: 30px; }
  .stat__l { font-size: 9px; }
  .prints { gap: 12px; }
  .print { height: 240px; }
  .print--2 { align-self: auto; }
  .landings__list { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .gallery img { height: 190px; }
  .hero__cta .btn, .visit__cta .btn, .call__in .btn { flex-grow: 1; }
  .board__foot { flex-direction: column; align-items: flex-start; gap: 14px; }
  .call__in { gap: 24px; }
  .foot__cols { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  /* The phone lives in the persistent call bar on a phone, so the nav keeps
     only the wordmark. Both together overflowed a 390px page by 61px. */
  .nav__tel { display: none; }
  .nav__in { gap: 16px; }
  .nav__cta .btn { padding: 12px 18px; font-size: 13px; }
  /* The persistent call bar. Square, like everything else. */
  .callbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    background: var(--bg); border-top: 1px solid var(--line);
    padding: 12px var(--gutter); display: flex; gap: 10px;
  }
  .callbar .btn { flex-grow: 1; }
  .callbar .btn--icon { flex-grow: 0; width: 52px; padding: 0; }
  body { padding-bottom: 76px; }
}

.callbar { display: none; }
@media (max-width: 720px) { .callbar { display: flex; } }
