/* TEUF — one house, three rooms.
   Fluid throughout: clamp() for type and rhythm, one structural breakpoint. */

@import url('https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@62..125,400..700&family=Caveat:wght@700&family=Prata&display=swap');

/* Corner Club's real typeface, licensed as a webfont from Fontspring on
   2026-09-18. Until then the desktop-only EULA forbade @font-face, which is why
   the wordmark is artwork and the lockup lines were set in Archivo.

   Self-hosted rather than imported: it is 28KB, it is the only face on the site
   that is not from Google Fonts, and it belongs to a licence rather than a CDN.

   swap, so the lockup is legible while it loads instead of invisible. */
@font-face {
  font-family: 'Tipton';
  src: url('../fonts/tipton-demi.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  --ink: #17130E;
  --paper: #FAF8F3;
  --cream: #E8DCC6;
  --night: #0E0E0F;
  /* Teuf au Vin's ground. Rotated 60.5deg -> 50deg and lifted from C 0.076 to
     0.098 on 2026-09-18, because measurement showed it had drifted off the
     thing it is supposed to come from: the room's own hero photograph clusters
     at H 45 (54% of its chromatic pixels) and H 30 (23%), carrying C 0.082-0.085,
     while the page painted nothing outside H 60-86 and nothing above C 0.019
     except the accent. CLAUDE.md records the palette as "driven by the three
     venues' existing photographic worlds"; this executes that rather than
     overriding it. Lightness is unchanged, so contrast only improved:
     body 7.26 -> 7.38, accent 5.20 -> 5.29. */
  --oak: oklch(0.430 0.098 50);
  --light: #F4EFE4;

  --gutter: clamp(20px, 5vw, 88px);
  --section: clamp(48px, 7vw, 78px);
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* ---- vertical rhythm ----
     Measured before this existed: every major section on a venue page
     rendered at exactly 78px top and bottom — events, feature, menu, about —
     so a dated one-off announcement arrived with the same ceremony as the
     menu, and nothing told the eye which was which. Three intervals instead
     of one: subdivisions inside a movement, ordinary sections, and the break
     between movements. --section keeps its existing value so nothing that
     already reads correctly moves. */
  --space-tight: clamp(26px, 3.4vw, 44px);
  --space-major: clamp(64px, 9vw, 116px);

  --eyebrow: clamp(9px, 0.7vw, 10px);
  --body: clamp(14px, 1.05vw, 15px);
  --lede: clamp(26px, 3.2vw, 38px);

  /* ---- action and state ----
     Not a new brand colour. Every token above sits on hue 60–92, and the three
     rooms' own photographs measure at 70° and 91° — so this is the palette's
     existing hue with the chroma it never used (the strongest token, --oak,
     reaches C 0.076; the photographs carry 0.14).

     Two lightness stops because no single value clears 4.5:1 on both the cream
     page and the near-black bands. Surfaces remap the role; they never restate
     the colour. */
  --accent-lo: oklch(0.47 0.13 66);   /* 6.6:1 on --paper */
  --accent-hi: oklch(0.85 0.13 84);   /* 11.6:1 on --ink, 5.2:1 on --oak */
  --warn-lo:   oklch(0.52 0.17 30);
  --warn-hi:   oklch(0.75 0.15 38);

  --accent: var(--accent-lo);
  --accent-on: var(--paper);          /* text on an accent fill */
  --warn: var(--warn-lo);
}

/* Every ground that is dark, or dark enough — the two rooms whose pages are
   dark, plus the bands that go dark inside the cream one. */
.v-club, .v-vin,
.util, .hero, .events, .onedish, .revealfoot, .navpanel, .menu__cover, .lightbox {
  --accent: var(--accent-hi);
  --accent-on: var(--ink);
  --warn: var(--warn-hi);
}

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

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

body {
  margin: 0;
  font-family: 'Archivo', system-ui, sans-serif;
  background: var(--paper);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }

/* Text selection shipped as the browser's blue on every page — a colour that
   belongs to no design system here. It now takes the room's own action colour,
   so it is correct on cream, on ink and on au Vin's brown without a per-room
   rule. */
::selection { background: var(--accent); color: var(--accent-on); }

a { color: inherit; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* On an accent-filled button the accent ring would be invisible, so the ring
   takes the button's own text colour instead. */
.btn:focus-visible { outline-color: currentColor; }

/* Visually hidden, still read aloud and still found by search. Used where a
   page genuinely has no text heading of its own — the home page is three
   photographs and three wordmarks. */
.vh {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Five pages had no <h1> at all: the room's name existed only as an <img alt>,
   so heading navigation landed on "Öppettider" and crawlers saw no subject.
   The wordmark now IS the heading, which costs nothing visually — but the
   browser's own h1 margin and weight would move things, so they are reset. */
.hero__h {
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
  line-height: 0;
}
h1.hero__tag {
  font-weight: inherit;
  margin-bottom: 0;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--light); padding: 14px 20px;
  font-size: 12px; letter-spacing: 0.18em; text-transform: uppercase; text-decoration: none;
}
.skip:focus { left: 0; }

/* ---------- shared atoms ---------- */

.eyebrow {
  font-size: var(--eyebrow);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  opacity: 0.55;
  margin: 0 0 clamp(16px, 2vw, 26px);
}

.label {
  font-size: clamp(10px, 0.9vw, 12px);
  letter-spacing: 0.32em;
  text-transform: uppercase;
}

.body-text {
  font-size: var(--body);
  line-height: 1.75;
  opacity: 0.7;
  margin: 0 0 15px;
  max-width: 62ch;
}

.btn {
  display: inline-block;
  font-size: clamp(11px, 0.9vw, 12px);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: clamp(15px, 1.6vw, 18px) clamp(24px, 2.6vw, 34px);
  text-decoration: none;
  border: 1px solid currentColor;
  background: transparent;
  cursor: pointer;
  transition: background 220ms var(--ease), color 220ms var(--ease);
}
/* Every button on this site is Boka bord, Boka chambré or Till kassan — one
   action family, so one treatment. --solid sits on light grounds and --ghost on
   dark ones, which is exactly the split the two accent stops already make.
   Both fill: an outline over a photograph borrows its contrast from whatever
   happens to be behind it, and that measured as low as 3.5:1. */
.btn--solid,
.btn--ghost { background: var(--accent); color: var(--accent-on); border-color: var(--accent); }

/* No booking URL yet, so js/booking.js routes these to email instead. They stay
   fully live and look unchanged — booking by mail is a real channel, not a
   degraded one, and a guest should not be able to tell the difference. The
   previous rule greyed them out in production only, which meant the build we
   reviewed was never the build guests got. */
.btn--solid:hover,
.btn--ghost:hover { background: transparent; color: var(--accent); border-color: var(--accent); }

.veil { position: absolute; inset: 0; }

/* ---------- home ---------- */

.home {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}

.rooms {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.room {
  position: relative;
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  text-decoration: none;
  transition: flex-grow 520ms var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.room img.bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Percentage of the room, not the viewport — the room is a third of the
   screen on desktop and the full width when stacked. */
.room__mark { position: relative; width: min(62%, 300px); }
.room__tag { position: relative; margin-top: clamp(8px, 1.2vw, 16px); opacity: 0.85; }
.room__enter {
  position: absolute; bottom: clamp(14px, 3vw, 44px);
  font-size: clamp(8px, 0.75vw, 10px); letter-spacing: 0.3em; text-transform: uppercase;
  opacity: 0.6;
}

.room--teuf { color: var(--light); }
.room--club { color: #F2F0EA; }
.room--vin  { color: #F7EFE2; }
.room--teuf .veil { background: radial-gradient(ellipse 85% 55% at 50% 50%, rgba(18,13,8,0.58), rgba(18,13,8,0.24) 100%); }
.room--club .veil { background: radial-gradient(ellipse 85% 55% at 50% 50%, rgba(8,8,9,0.46), rgba(8,8,9,0.2) 100%); }
.room--vin  .veil { background: radial-gradient(ellipse 85% 55% at 50% 50%, rgba(26,14,6,0.5), rgba(26,14,6,0.2) 100%); }

.room--club .room__mark { width: min(78%, 372px); }
.room--vin  .room__mark { width: min(44%, 250px); }

.util {
  flex: 0 0 auto;
  background: var(--ink);
  color: #EFE7D8;
  padding: clamp(16px, 2vw, 22px) var(--gutter);
  display: flex;
  flex-wrap: wrap;
  gap: clamp(10px, 2vw, 26px);
  align-items: center;
  justify-content: space-between;
  font-size: clamp(10px, 0.85vw, 12px);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.util a { text-decoration: none; border-bottom: 1px solid rgba(239,231,216,0.4); padding-bottom: 2px; }

/* Two addresses, because there are two. The single address and single room's
   open-now state that used to live here were wrong on a page whose entire
   premise is three rooms at two doors: on a Tuesday at 15.30 it read
   "Öppet nu" while Corner Club was shut for another half hour. Hours are
   per-room and now live on the room pages, where they can be right. */
.util__where { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.util__room { opacity: 0.55; letter-spacing: 0.16em; }

@media (max-width: 599px) {
  /* Stacked, so neither address truncates the other at 10px. */
  .util { flex-direction: column; align-items: flex-start; }
  .util__where { flex-direction: column; gap: 6px; }
  .util__where > .util__room { margin-bottom: 4px; }
}
/* The one action on the home page. Same role, same colour as every Boka bord
   button on the room pages — it just has no button to sit in here. */
.util__book { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
.util nav { display: flex; gap: clamp(14px, 2vw, 26px); }

@media (min-width: 900px) {
  .rooms { flex-direction: row; }
  .room:hover { flex-grow: 1.18; }
  .room__enter { opacity: 0; transform: translateY(8px); transition: opacity 340ms var(--ease), transform 340ms var(--ease); }
  .room:hover .room__enter { opacity: 0.85; transform: translateY(0); }
}

/* ---------- venue pages ---------- */

.hero {
  position: relative;
  /* 80% of the small viewport, with guards: a floor so the mark, label and
     button still fit on a short landscape phone, and a ceiling so it does not
     become a thousand pixels of photograph on a large monitor. */
  min-height: clamp(460px, 90svh, 1000px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  padding: clamp(60px, 8vw, 90px) var(--gutter);
  text-align: center;
}
.hero img.bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Content sits above the photo and its scrim; the photo, the scrim and the
   back link stay pinned. Ordered so the specific rules win. */
.hero > * { position: relative; }
.hero > .bg,
.hero > .veil { position: absolute; inset: 0; }
.hero > .back { position: absolute; }
.hero__mark { width: clamp(220px, 48vw, 620px); }
.hero__tag { margin-top: clamp(14px, 2vw, 22px); opacity: 0.85; }
.hero .btn { margin-top: clamp(26px, 3.4vw, 44px); }

.back {
  position: absolute; top: clamp(18px, 2.4vw, 34px); left: var(--gutter);
  font-size: clamp(9px, 0.8vw, 10px); letter-spacing: 0.26em; text-transform: uppercase;
  text-decoration: none; opacity: 0.8; z-index: 2;
}
.back:hover { opacity: 1; }

.section { padding: var(--section) var(--gutter); }

.about { display: grid; gap: clamp(28px, 4vw, 88px); align-items: start; }
.about__statement { font-size: var(--lede); line-height: 1.22; margin: 0 0 clamp(20px, 2.4vw, 28px); }
.about__img {
  width: 100%; aspect-ratio: 7 / 8; border: 1px solid currentColor; opacity: 0.35;
  display: flex; align-items: center; justify-content: center;
  font-size: 9px; letter-spacing: 0.24em; text-transform: uppercase;
}

/* ---------- About: eyebrow, contained portrait, statement, lead ----------

   Not full-bleed. The section sits on the room's own ground with real margin
   around it, and the photograph is contained rather than bleeding — the quiet
   counterpart to the menu split further down.

   Three columns: a label in the left margin, the portrait, then the text. The
   statement sits at the top of its column and the lead at the bottom, level
   with the foot of the photograph, with the space between them left empty.
   There is deliberately no call to action here; the onward link belongs to the
   menu, not to the room's own description. */

.about {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(20px, 3vw, 36px);
  padding: var(--space-major) var(--gutter);
}

.about__shot { margin: 0; }
.about__shot img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 4 / 5; object-fit: cover;
}

.about__body { display: flex; flex-direction: column; }

/* The first paragraph, set a step up from the rest so the column opens with
   some weight instead of starting flat. */
.about__lead {
  margin: clamp(22px, 3vw, 34px) 0 clamp(14px, 1.6vw, 20px);
  font-size: clamp(15px, 1.2vw, 17px);
  line-height: 1.7;
  opacity: 0.85;
}

/* One column, one measure. An earlier version put the lead here and the
   remaining paragraphs in a separate full-width section below, which read as
   two disconnected blocks of text with a void between them — the text started
   in the right column and resumed at the far left. All of the copy lives in
   this column now. */
.about__body > .body-text { max-width: none; opacity: 0.72; }
.about__body > .body-text:last-child { margin-bottom: 0; }

@media (min-width: 900px) {
  .about {
    grid-template-columns: minmax(70px, 6vw) minmax(0, 0.92fr) minmax(0, 1.08fr);
    gap: clamp(26px, 4vw, 70px);
    align-items: stretch;
  }
  /* The first column used to hold an "Om" label. It stays as margin now that
     the label is gone — it is what keeps the photograph inset from the gutter
     rather than flush against it. Both items are placed explicitly, because
     auto-placement would otherwise slide the photograph into that column and
     close the indent. */
  .about__shot { grid-column: 2; }
  .about__body { grid-column: 3; }
  /* The text column holds the whole About, so it is sized to a comfortable
     measure rather than stretched to the grid. */
  .about__body { max-width: 52ch; }
}

/* ---------- the split: photograph against a colour panel ----------

   The section directly under each hero. Full-bleed, edge to edge, no gutter:
   a photograph holding one half and a panel of the room's own deep tone
   holding the other.

   The panel colour is --cover-bg, which already exists per room and is derived
   from that room's photography — so the three read as three rooms rather than
   one template in three colours. Each also keeps its own display voice further
   down (Archivo wide / Prata / Caveat), for the same reason.

   Type sits top and bottom with the space between them left empty. That gap is
   the point: it is what makes the panel read as a held composition rather than
   a text box, and it is why the intro here is ~35 words and the rest of the
   copy lives in the section below. */

.split {
  display: grid;
  grid-template-columns: 1fr;
  background: var(--cover-bg);
  color: var(--cover-on);
}

.split__shot { margin: 0; position: relative; }
.split__shot img {
  display: block; width: 100%; height: 100%;
  min-height: 46svh;
  object-fit: cover;
}

.split__panel {
  display: flex; flex-direction: column;
  gap: clamp(28px, 4vw, 56px);
  padding: clamp(32px, 5vw, 76px) clamp(24px, 4vw, 64px);
}

.split__eyebrow {
  margin: 0;
  font-size: var(--eyebrow);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  opacity: 0.62;
}

/* The statement, at display size. Per-room families are inherited from the
   .v-* rules further down, so this sets only what they share. */
.split__title {
  margin: 0;
  font-size: var(--lede);
  line-height: 1.12;
  text-wrap: balance;
}

/* Pushed to the bottom of the panel on desktop, under the empty middle. */
.split__foot { margin-top: auto; }

.split__lead {
  margin: 0 0 clamp(18px, 2vw, 26px);
  font-size: var(--body);
  line-height: 1.75;
  opacity: 0.78;
  max-width: 42ch;
}

.split__more {
  display: inline-flex; align-items: center; gap: 12px;
  font-size: var(--eyebrow);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  color: inherit;
  padding-bottom: 6px;
  border-bottom: 1px solid currentColor;
}
.split__more span {
  display: grid; place-items: center;
  width: 22px; height: 22px; border-radius: 50%;
  border: 1px solid currentColor;
  transition: transform 0.4s var(--ease);
}
.split__more:hover span { transform: translateX(4px); }
/* The menu's link opens the lightbox, so it is a <button>. Strip the UA chrome
   so it matches the anchors elsewhere. */
button.split__more { background: none; cursor: pointer; font: inherit; }

/* The secondary ways into the menu — PDF, and au Vin's full wine list — sit
   under the button, on the panel rather than on the page. */
.split__alt {
  display: flex; flex-wrap: wrap; gap: 8px clamp(14px, 2vw, 26px);
  margin: clamp(18px, 2.2vw, 26px) 0 0;
  font-size: var(--eyebrow); letter-spacing: 0.12em; text-transform: uppercase;
}
.split__alt a { color: inherit; text-decoration: none; opacity: 0.62; }
.split__alt a:hover { opacity: 1; }

@media (min-width: 900px) {
  .split { grid-template-columns: 1fr 1fr; min-height: 82svh; }
  .split__shot img { min-height: 0; position: absolute; inset: 0; }
  .split__panel { justify-content: flex-start; }
}

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

/* ---------- TEUF only: the one-dish About ---------- */

/* The house sells one dish. The section is built so the skeleton says that
   before a word is read: an opening spread, then the claim alone on the dark
   band the page already uses for its events, then the rest of the story in
   ordinary body copy. Everything here is scoped to .about--dish, so Corner
   Club and au Vin keep the plain two-column About untouched.

   No eyebrow: the old "Om" label named nothing the statement does not say. */

.about--dish { display: block; padding: 0; }

.about--dish .about__open {
  display: grid;
  gap: clamp(26px, 4vw, 64px);
  align-items: end;
  padding: var(--space-major) var(--gutter) var(--space-tight);
}

.about--dish .about__lead { min-width: 0; }
.about--dish .about__lead .body-text:last-child { margin-bottom: 0; }

.about--dish .about__shot { margin: 0; }
.about--dish .about__shot img {
  display: block; width: 100%; height: auto;
  /* Uncropped on desktop, where it sits beside the text. On a phone it is
     stacked, and at full height it pushed the claim 500px down the scroll —
     so cap it and hold the centre plate. */
  max-height: min(58svh, 440px);
  object-fit: cover;
  object-position: center 44%;
}

@media (min-width: 900px) {
  .about--dish .about__shot img { max-height: none; }
}

/* The statement runs at display scale on the width axis the wordmark lives on,
   rather than the shared --lede size, which is the smallest display step. */
.v-teuf .about--dish .about__statement {
  font-size: clamp(26px, 4.6vw, 62px);
  line-height: 1.06;
  letter-spacing: -0.02em;
  font-stretch: 118%;
  font-weight: 500;
  max-width: 16ch;
  margin: 0 0 clamp(18px, 2.2vw, 26px);
}

/* The claim, alone. Same ink ground and hairlines as the events band, so this
   is the page's own device turned up rather than a new one. Deliberately not
   given [data-reveal]: its neighbours animate in, and this one is simply
   already there — the fixed thing they arrive at. */
.onedish {
  background: var(--ink);
  color: var(--light);
  border-top: 1px solid color-mix(in srgb, var(--light) 16%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--light) 16%, transparent);
  /* The ink ground already separates this; it does not need space as well.
     Tight against its neighbours so statement, photograph and claim read as
     one movement rather than three sections. */
  padding: var(--section) var(--gutter);
}
.onedish__line {
  margin: 0;
  font-size: clamp(37px, 6.2vw, 92px);
  line-height: 1.02;
  letter-spacing: -0.03em;
  font-stretch: 125%;
  font-weight: 600;
  max-width: 15ch;
}

.about--dish .about__rest {
  padding: var(--space-tight) var(--gutter) var(--space-major);
}
.about--dish .about__rest .body-text:last-child { margin-bottom: 0; }

@media (min-width: 900px) {
  .about--dish .about__open {
    grid-template-columns: minmax(0, 1fr) clamp(280px, 33vw, 460px);
    /* The photograph runs off the right edge, the way the wordmark runs off
       the hero. The gutter is re-added inside the text column only. */
    padding-right: 0;
  }
}

/* Hours and booking are why two of the three confirmed visitor situations are
   here at all, and under a squint test this band used to disappear entirely
   while the menu cover dominated. It now gets the page's major interval and a
   readable type size. Deliberately not a fourth dark band: mass comes from
   space and content size, so it does not compete with the events and one-dish
   grounds. */
.practical {
  padding: var(--space-major) var(--gutter);
  border-top: 1px solid currentColor; border-bottom: 1px solid currentColor;
  display: flex; flex-direction: column; gap: clamp(20px, 2.6vw, 30px);
}
.practical__title {
  font-size: clamp(16px, 1.7vw, 21px);
  font-weight: 600;
  line-height: 1.2;
  margin: 0 0 clamp(14px, 1.6vw, 18px);
}
.practical .hours__row { font-size: clamp(15px, 1.25vw, 17px); opacity: 0.78; }
.practical .today {
  font-size: clamp(12px, 1.05vw, 14px);
  letter-spacing: 0.16em;
  opacity: 1;
  margin: clamp(16px, 1.9vw, 22px) 0 0;
}
.practical__hours { font-size: var(--body); line-height: 1.7; }
.practical__note { font-size: clamp(12px, 1vw, 13px); line-height: 1.6; opacity: 0.66; }

/* A band that has to read as separate on three different page grounds, so it
   takes a ground per venue plus hairlines that carry it when contrast is low. */
.events {
  padding: var(--section) var(--gutter);
  background: var(--events-bg, var(--ink));
  color: var(--events-on, var(--light));
  border-top: 1px solid color-mix(in srgb, var(--events-on, var(--light)) 16%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--events-on, var(--light)) 16%, transparent);
}
.events[hidden] { display: none; }
.events__grid { display: grid; gap: clamp(26px, 4vw, 72px); align-items: center; }
.events__date { font-size: clamp(10px, 0.85vw, 11px); letter-spacing: 0.28em; text-transform: uppercase; opacity: 0.6; }
.events__name { font-size: clamp(32px, 4.6vw, 58px); font-weight: 500; line-height: 1.06; margin: 14px 0 0; }
.events__line { font-size: clamp(14px, 1.15vw, 16px); line-height: 1.65; opacity: 0.68; margin: 16px 0 0; max-width: 46ch; }
.events__act { margin-top: clamp(20px, 2.6vw, 34px); display: flex; flex-wrap: wrap; align-items: center; gap: clamp(14px, 2vw, 26px); }

.menu { display: flex; flex-direction: column; align-items: center; }
.menu .eyebrow { align-self: flex-start; }
.menu__cover {
  width: min(384px, 100%); aspect-ratio: 8 / 11;
  border: 1px solid transparent; padding: 0; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(28px, 4vw, 46px);
  transition: transform 320ms var(--ease), box-shadow 320ms var(--ease), border-color 320ms var(--ease);
}
.menu__cover:hover { transform: translateY(-6px); }
.menu__cover img { width: 58%; }
.menu__covertext { font-size: clamp(9px, 0.8vw, 10px); letter-spacing: 0.28em; text-transform: uppercase; opacity: 0.62; }
.menu__alt { margin-top: clamp(20px, 2.4vw, 30px); display: flex; flex-wrap: wrap; justify-content: center; gap: clamp(18px, 2.6vw, 34px); }
.menu__alt a {
  font-size: clamp(11px, 0.9vw, 12px); letter-spacing: 0.16em; text-transform: uppercase;
  text-decoration: none; opacity: 0.66; border-bottom: 1px solid currentColor; padding-bottom: 2px;
}
.menu__alt a:hover { opacity: 1; }

.house { display: flex; flex-direction: column; }
.house__room {
  position: relative; overflow: hidden; text-decoration: none;
  min-height: clamp(160px, 22vw, 300px);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; flex: 1 1 0;
  transition: flex-grow 420ms var(--ease);
}
.house__room img.bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.house__label { position: relative; font-size: clamp(8px, 0.7vw, 9px); letter-spacing: 0.28em; text-transform: uppercase; opacity: 0.6; }
.house__mark { position: relative; width: clamp(110px, 20vw, 264px); }

.foot {
  background: var(--ink); color: #EFE7D8;
  padding: clamp(20px, 2.4vw, 30px) var(--gutter);
  display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: space-between;
  font-size: clamp(10px, 0.85vw, 12px); letter-spacing: 0.2em; text-transform: uppercase;
}
.foot a { text-decoration: none; border-bottom: 1px solid rgba(239,231,216,0.4); padding-bottom: 2px; }

@media (min-width: 900px) {
  .practical { flex-direction: row; align-items: center; justify-content: space-between; gap: 40px; }
  .events__grid { grid-template-columns: minmax(0, 1fr) clamp(280px, 30vw, 380px); }
  .house { flex-direction: row; }
  .house__room:hover { flex-grow: 1.15; }
}

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

.lightbox {
  /* Above .navbtn (120). At 90 the nav button sat on top of the close button:
     12 of 17 points sampled across the close button resolved to .navbtn, so the
     menu could not be closed on a phone. */
  position: fixed; inset: 0; z-index: 130;
  background: rgba(10,8,6,0.985);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(18px, 2.4vw, 34px);
  padding: clamp(56px, 8vh, 90px) clamp(14px, 3vw, 40px) clamp(20px, 4vh, 40px);
}
.lightbox[hidden] { display: none; }
.lightbox__stage { display: flex; align-items: center; gap: clamp(14px, 3vw, 48px); max-width: 100%; }
.lightbox__page {
  background: #fff; width: auto; max-width: 100%;
  max-height: calc(100svh - clamp(150px, 26vh, 260px));
  box-shadow: 0 30px 90px rgba(0,0,0,0.55);
}
.lightbox__nav { display: flex; align-items: center; gap: clamp(14px, 2.4vw, 22px); }
.lightbox__counter { font-size: clamp(10px, 0.9vw, 11px); letter-spacing: 0.26em; text-transform: uppercase; color: var(--light); opacity: 0.6; min-width: 62px; text-align: center; }

.arrow {
  width: clamp(46px, 5vw, 56px); height: clamp(46px, 5vw, 56px);
  border-radius: 50%; border: 1px solid rgba(244,239,228,0.34);
  background: transparent; color: var(--light); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; padding: 0;
  transition: background 200ms var(--ease), color 200ms var(--ease);
}
.arrow:hover:enabled { background: var(--light); color: var(--ink); }
.arrow:disabled { opacity: 0.2; cursor: default; }

.lightbox__close {
  position: absolute; top: clamp(14px, 2vw, 40px); right: clamp(14px, 3vw, 48px);
  border: 0; background: transparent; color: var(--light); cursor: pointer;
  font-family: inherit; font-size: clamp(10px, 0.9vw, 11px);
  letter-spacing: 0.24em; text-transform: uppercase; opacity: 0.8; padding: 10px;
}
.lightbox__close:hover { opacity: 1; }

/* Beside the page on wide screens, beneath it on narrow ones. */
@media (max-width: 899px) {
  .lightbox__stage { flex-direction: column; }
  .lightbox__stage .arrow { display: none; }
}
@media (min-width: 900px) {
  .lightbox__nav .arrow { display: none; }
}

body.is-locked { overflow: hidden; }

/* ---------- per-venue themes ---------- */

/* Hero scrims are weighted toward the middle, where the mark and the button
   sit, so the photograph keeps its life at the edges. The TEUF flat-lay is a
   white tablecloth in hard sun and needs the most. */
.v-teuf {
  --ground: var(--paper); --on: var(--ink); --cover-bg: var(--ink); --cover-on: var(--light);
  --hero-veil: radial-gradient(ellipse 78% 66% at 50% 50%, rgba(14,10,6,0.66), rgba(14,10,6,0.26) 100%);
  --events-bg: var(--ink); --events-on: var(--light);
}
.v-club {
  --ground: #121213; --on: #F2F0EA; --cover-bg: #0A0A0B; --cover-on: #F2F0EA;
  --hero-veil: radial-gradient(ellipse 80% 70% at 50% 50%, rgba(6,6,7,0.5), rgba(6,6,7,0.2) 100%);
  --events-bg: #050506; --events-on: #F2F0EA;
}
.v-vin {
  /* The dark bands follow the ground to the same hue, so the room reads as one
     material at two depths rather than two browns that nearly match. */
  --ground: var(--oak); --on: #F7EFE2;
  --cover-bg: oklch(0.29 0.062 50); --cover-on: #F7EFE2;
  --hero-veil: radial-gradient(ellipse 80% 82% at 50% 52%, rgba(26,12,3,0.76), rgba(26,12,3,0.3) 100%);
  --events-bg: oklch(0.29 0.062 50); --events-on: #F7EFE2;
}

.venue { background: var(--ground); color: var(--on); }
.venue .hero { color: var(--light); }
.venue .hero .veil { background: var(--hero-veil); }
.venue .practical { border-color: color-mix(in srgb, currentColor 18%, transparent); }
.venue .about__img { border-color: color-mix(in srgb, currentColor 30%, transparent); }
.venue .menu__cover { background: var(--cover-bg); color: var(--cover-on); border-color: color-mix(in srgb, var(--cover-on) 26%, transparent); }

.v-club .about__statement { font-family: 'Prata', serif; font-size: clamp(25px, 3vw, 36px); }

/* The logo lockup, now in the logo's own face. These two lines and the Est. 2013
   band are the lockup's wording; everything else on the page stays on the
   stand-in serif until that is a decision rather than a side effect. */
.v-club .hero__tag,
.v-club .hero > .label:not(.hero__tag),
.room--club .room__tag {
  font-family: 'Tipton', 'Prata', serif;
  font-weight: 600;
}
/* Tracking only. The .label value was compensating for Archivo and is too loose
   for a display serif — but the casing is left exactly as it was, because the
   lockup's own treatment of this line has not been checked against the artwork. */
.v-club .hero__tag,
.v-club .hero > .label:not(.hero__tag),
.room--club .room__tag { letter-spacing: 0.16em; }
.v-vin  .about__statement { font-family: 'Caveat', cursive; font-weight: 700; font-size: clamp(34px, 4vw, 46px); }
.v-teuf .about__statement { font-weight: 500; font-stretch: 112%; }

/* Uppercase for the two rooms whose display voice is built for it — TEUF's
   wide geometric sans and Corner Club's high-contrast serif. Teuf au Vin is
   deliberately excluded: Caveat is brush script, and setting a script face in
   caps reads as shouting rather than as display type. */
.v-teuf .about__statement,
.v-club .about__statement { text-transform: uppercase; letter-spacing: -0.01em; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}

/* ---------- shop ---------- */

.shophead {
  position: relative;
  background: var(--ink);
  color: var(--light);
  padding: clamp(74px, 9vw, 110px) var(--gutter) clamp(34px, 4vw, 54px);
  display: flex; flex-direction: column; align-items: center; text-align: center;
}
.shophead__mark { width: clamp(150px, 26vw, 260px); }
.shophead__cart {
  position: absolute; top: clamp(16px, 2.2vw, 32px); right: var(--gutter);
  border: 1px solid rgba(244,239,228,0.4); background: transparent; color: var(--light);
  font-family: inherit; font-size: clamp(10px, 0.85vw, 11px);
  letter-spacing: 0.22em; text-transform: uppercase;
  padding: 11px 16px; cursor: pointer;
  display: flex; align-items: center; gap: 9px;
  transition: background 200ms var(--ease), color 200ms var(--ease);
}
.shophead__cart:hover { background: var(--light); color: var(--ink); }
/* A class-level display rule beats the UA's [hidden] rule, so say it again. */
.pill[hidden] { display: none; }
.pill {
  min-width: 19px; height: 19px; border-radius: 10px;
  background: var(--light); color: var(--ink);
  font-size: 10px; letter-spacing: 0; display: flex; align-items: center; justify-content: center;
  padding: 0 5px;
}
.shophead__cart:hover .pill { background: var(--ink); color: var(--light); }

.note {
  font-size: var(--body); line-height: 1.6; margin: 0 0 clamp(26px, 3vw, 40px);
  padding: 14px 18px; border-left: 1px solid currentColor; opacity: 0.75; max-width: 70ch;
}
/* The warning state used to be opacity 0.9 against 0.75 — invisible. */
.note--warn { color: var(--warn); opacity: 1; font-weight: 500; }

.grid {
  display: grid; gap: clamp(26px, 3.4vw, 52px);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
}

.card { display: flex; flex-direction: column; }
.card__img {
  width: 100%; aspect-ratio: 4 / 5; overflow: hidden;
  background: color-mix(in srgb, currentColor 5%, transparent);
  margin-bottom: clamp(16px, 1.8vw, 22px);
}
.card__img img { width: 100%; height: 100%; object-fit: cover; }
.card__img--empty {
  display: flex; align-items: center; justify-content: center;
  border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
  font-size: 9px; letter-spacing: 0.24em; text-transform: uppercase; opacity: 0.45;
}
.card__title { font-size: clamp(17px, 1.5vw, 21px); font-weight: 500; margin: 0 0 7px; }
.card__desc { font-size: clamp(13px, 1vw, 14px); line-height: 1.6; opacity: 0.66; margin: 0 0 12px; }
.card__price { font-size: var(--body); margin: 0 0 16px; letter-spacing: 0.04em; }
.card__add { align-self: flex-start; margin-top: auto; }

.sizes { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 18px; }
.size {
  min-width: 44px; min-height: 44px; padding: 0 12px;
  border: 1px solid color-mix(in srgb, currentColor 28%, transparent);
  background: transparent; color: inherit; cursor: pointer;
  font-family: inherit; font-size: 12px; letter-spacing: 0.1em;
  transition: background 180ms var(--ease), color 180ms var(--ease), border-color 180ms var(--ease);
}
.size[aria-pressed="true"] { background: currentColor; border-color: currentColor; }
.size[aria-pressed="true"]::after { content: ''; }
.v-teuf .size[aria-pressed="true"] { color: var(--ink); background: var(--ink); }
.v-teuf .size[aria-pressed="true"] { color: var(--paper); }
.size:disabled { opacity: 0.45; cursor: default; text-decoration: line-through; }

/* Cart panel: a drawer on desktop, a sheet on a phone. */
/* Same tier as the menu lightbox (130). At 95 the nav button (120) and the cart
   button (115) both painted over this scrim and stayed clickable — the identical
   defect that was fixed for the lightbox and not generalised at the time. */
.cart { position: fixed; inset: 0; z-index: 130; background: rgba(10,8,6,0.6); display: flex; }
.cart[hidden] { display: none; }
.cart__panel {
  background: var(--paper); color: var(--ink);
  margin-left: auto; width: min(420px, 100%);
  display: flex; flex-direction: column;
  padding: clamp(22px, 3vw, 34px);
  box-shadow: -20px 0 60px rgba(0,0,0,0.3);
}
.cart__head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: clamp(18px, 2.4vw, 28px); }
.cart__title { font-size: clamp(18px, 1.6vw, 22px); font-weight: 500; margin: 0; }
.cart__close {
  border: 0; background: transparent; color: inherit; cursor: pointer; font-family: inherit;
  font-size: 11px; letter-spacing: 0.22em; text-transform: uppercase; opacity: 0.7; padding: 8px;
}
.cart__close:hover { opacity: 1; }
.cart__empty { font-size: var(--body); opacity: 0.6; margin: 0; }
.cart__lines { list-style: none; margin: 0; padding: 0; overflow-y: auto; flex: 1 1 auto; }
.line { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 15px 0; border-bottom: 1px solid rgba(23,19,14,0.12); }
.line__title { margin: 0; font-size: 15px; }
.line__meta { margin: 4px 0 0; font-size: 12.5px; opacity: 0.6; }
.qty { display: flex; align-items: center; gap: 4px; }
.qty__btn {
  width: 34px; height: 34px; border: 1px solid rgba(23,19,14,0.25);
  background: transparent; color: inherit; cursor: pointer; font-family: inherit; font-size: 15px;
}
.qty__btn:hover { background: var(--ink); color: var(--paper); }
.qty__n { min-width: 26px; text-align: center; font-size: 14px; }
.cart__foot { padding-top: clamp(18px, 2.4vw, 26px); }
.cart__note { font-size: 12px; line-height: 1.5; opacity: 0.6; margin: 0 0 14px; }
.cart__checkout { width: 100%; text-align: center; }

@media (max-width: 599px) {
  .cart { align-items: flex-end; }
  .cart__panel { margin: 0; width: 100%; max-height: 88svh; box-shadow: 0 -20px 60px rgba(0,0,0,0.35); }
}

/* Word-by-word scroll reveal. The .rv-on class only lands once the script has
   split the words, so unstyled text is never left dimmed. */
.rv-on .rv-word { transition: opacity 260ms linear; will-change: opacity; }
@media (prefers-reduced-motion: reduce) {
  .rv-on .rv-word { opacity: 1 !important; transition: none; }
}

/* Hero entrance — the one idea worth taking from the React hero component.
   Pure CSS: the content rises and fades in sequence on load. Two keyframes so
   each element settles at its own resting opacity instead of snapping to 1. */
@media (prefers-reduced-motion: no-preference) {
  .hero__mark,
  .hero__tag,
  .hero > .label:not(.hero__tag),
  .hero .btn {
    animation: rise 760ms var(--ease) backwards;
  }
  .hero__mark   { animation-delay: 100ms; }
  .hero__tag    { animation-delay: 260ms; animation-name: rise-soft; }
  .hero > .label:not(.hero__tag) { animation-delay: 340ms; animation-name: rise-faint; }
  .hero .btn    { animation-delay: 440ms; }
}
@keyframes rise       { from { opacity: 0;    transform: translateY(18px); } to { opacity: 1;    transform: none; } }
@keyframes rise-soft  { from { opacity: 0;    transform: translateY(18px); } to { opacity: 0.85; transform: none; } }
@keyframes rise-faint { from { opacity: 0;    transform: translateY(18px); } to { opacity: 0.55; transform: none; } }

/* Frosted button, also from that component. The blur has a job: it separates
   the button from whatever is behind it. At a 10% white tint it was not doing
   that job well enough — measured 3.5:1 over TEUF's bright flat-lay — so the
   frost is now tinted with the action colour instead of with white. Ten per
   cent of the photograph still moves behind it; the contrast no longer depends
   on which photograph that is. */
.btn--ghost {
  background: color-mix(in srgb, var(--accent) 90%, transparent);
  -webkit-backdrop-filter: blur(7px);
  backdrop-filter: blur(7px);
  border-color: var(--accent);
  color: var(--accent-on);
}
.btn--ghost:hover {
  background: transparent;
  color: var(--accent);
  border-color: var(--accent);
  -webkit-backdrop-filter: blur(7px);
  backdrop-filter: blur(7px);
}

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

/* A restaurant that serves one dish, telling you a page is not on the menu.
   The joke is only available to TEUF, which is the point.

   Ink ground because this is an interstitial rather than a room — the rooms are
   what you are trying to reach, so none of their photography appears here. The
   only ornament is the number, set the way the wordmark is set: enormous, on
   Archivo's width axis, running off the left edge. */

.lost-page { background: var(--ink); color: var(--light); }
/* The dark ground needs the light accent stop, same as every other dark
   surface on the site. */
.lost-page { --accent: var(--accent-hi); --accent-on: var(--ink); }

.lost {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(56px, 9vh, 110px) var(--gutter);
  overflow: hidden;              /* the number bleeds; nothing else should */
  position: relative;
}

.lost__code {
  /* Pulled past the gutter so it genuinely runs off the left edge, which is
     how this house sets display type. .lost clips it. */
  /* clamp() takes (min, preferred, max). These are negative, so the larger
     magnitude is the MIN: written the other way round it silently resolved to
     -12px at every width and the fluid tightening never happened. */
  margin: 0 0 clamp(-28px, -1.4vw, -12px)
          calc(var(--gutter) * -1 - clamp(4px, 1.2vw, 26px));
  font-size: clamp(120px, 27vw, 380px);
  line-height: 0.82;
  letter-spacing: -0.05em;
  font-stretch: 125%;
  font-weight: 600;
  /* Ornament, and aria-hidden. Deliberately below the contrast floor: the
     error is stated in words at 16:1 in the heading, so nothing is carried by
     this alone. Raising it enough to pass 3:1 would put it in competition with
     the line that actually says something, which is the wrong trade. */
  color: color-mix(in srgb, var(--light) 13%, transparent);
  user-select: none;
}

.lost__line {
  margin: 0;
  font-size: clamp(30px, 5.4vw, 76px);
  line-height: 1.04;
  letter-spacing: -0.03em;
  font-stretch: 118%;
  font-weight: 500;
  max-width: 17ch;
}

.lost__sub {
  font-size: clamp(14px, 1.25vw, 17px);
  line-height: 1.65;
  opacity: 0.6;
  max-width: 44ch;
  margin: clamp(16px, 2vw, 22px) 0 0;
}

/* The three rooms as the menu this page does have. Hairlines rather than cards:
   a list of rooms in a building, not three products. */
.lost__rooms {
  margin: clamp(34px, 5vw, 60px) 0 0;
  border-top: 1px solid color-mix(in srgb, var(--light) 15%, transparent);
}

/* Stacked on a phone. Beside the name, the open-now line is greedy enough to
   break "Corner Club" over two lines and its note over three — the state is
   worth its own row rather than half the width of the room's name. */
.lostroom {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 3px;
  padding: clamp(16px, 2.2vw, 24px) 0;
  border-bottom: 1px solid color-mix(in srgb, var(--light) 15%, transparent);
  text-decoration: none;
  transition: padding-left 320ms var(--ease), color 200ms var(--ease);
}
.lostroom__name {
  grid-column: 1;
  font-size: clamp(19px, 2.1vw, 27px);
  line-height: 1.2;
  font-stretch: 112%;
}
.lostroom__note {
  grid-column: 1;
  font-size: clamp(12px, 1.05vw, 14px);
  line-height: 1.5;
  opacity: 0.55;
}
.lostroom .today {
  font-size: clamp(10px, 0.9vw, 12px);
  letter-spacing: 0.2em;
  opacity: 0.8;
  margin-top: 7px;
}

@media (min-width: 620px) {
  .lostroom {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: baseline;
    gap: 4px clamp(16px, 3vw, 40px);
  }
  .lostroom__name { grid-column: 1; }
  .lostroom__note { grid-column: 1; }
  .lostroom .today {
    grid-column: 2; grid-row: 1 / span 2;
    margin-top: 0;
    letter-spacing: 0.26em;
    white-space: nowrap;
  }
}

/* The one hover idea: the room steps toward you, the way the home page panels
   grow. Nothing moves on touch, where there is no hover to reward. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .lostroom:hover { padding-left: clamp(10px, 1.4vw, 20px); color: var(--accent); }
  .lostroom:hover .lostroom__note { opacity: 0.75; }
}

.lost__actions {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: clamp(14px, 2vw, 26px);
  margin: clamp(30px, 4vw, 46px) 0 0;
}
.lost__home {
  font-size: clamp(11px, 0.95vw, 13px); letter-spacing: 0.16em; text-transform: uppercase;
  text-decoration: none;
  display: inline-flex; align-items: center; min-height: 44px;
  opacity: 0.7;
}
.lost__home span { border-bottom: 1px solid currentColor; padding-bottom: 2px; }
.lost__home:hover { opacity: 1; }

.lost__addr {
  font-size: clamp(11px, 0.95vw, 13px); letter-spacing: 0.14em; text-transform: uppercase;
  opacity: 0.5;
  margin: clamp(30px, 4.5vw, 54px) 0 0;
}

/* One authored moment, borrowing the hero's own entrance rather than inventing
   a second motion vocabulary. The number arrives first and the rooms last. */
@media (prefers-reduced-motion: no-preference) {
  .lost__code, .lost__line, .lost__sub,
  .lost__rooms, .lost__actions, .lost__addr {
    animation: rise 760ms var(--ease) backwards;
  }
  .lost__code    { animation-delay: 60ms; }
  .lost__line    { animation-delay: 180ms; }
  .lost__sub     { animation-delay: 280ms; animation-name: rise-faint; }
  .lost__rooms   { animation-delay: 380ms; }
  .lost__actions { animation-delay: 500ms; }
  .lost__addr    { animation-delay: 580ms; animation-name: rise-faint; }
}

/* au Vin's ground is mid-lightness (L 0.43), not near-white like the dining room
   or near-black like Corner Club, so the shared .body-text opacity of 0.7 leaves
   far less contrast here than on the other two. Measured: TEUF 6.69:1, Corner
   Club 8.38:1, au Vin 4.49:1 — an actual AA failure, present before this pass
   and surfaced by measuring it. The room needs its own value, not a different
   colour. */
/* Everything on this page that dims itself toward the ground needs more room
   here than on cream or near-black. Same single cause, one correction. */
.v-vin .body-text,
.v-vin .practical__note { opacity: 0.84; }
.v-vin .menu__alt a,
.v-vin .merch__price { opacity: 0.78; }

/* Same cause: .eyebrow at 0.55 measured 3.41:1 here against 4.02:1 on cream.
   The size problem (9px, below the 11px floor) is a separate, site-wide issue
   and is not fixed by this pass. */
.v-vin .eyebrow { opacity: 0.74; }

/* ---------- Corner Club: the years ---------- */

/* The third room's own shape, and the third structurally different idea.
   TEUF's fact is a reduction, so one sentence alone on an empty ground.
   au Vin's is a time of night, so the hour itself is the object, paired.
   Corner Club's is a SPAN of years — it opened twelve years before the dining
   room — so this is neither a block nor a pairing but an inscription: one wide,
   thin line running the full measure and cropped by the viewport.

   That proportion is the room's own. Its logo lockup is a 7.8:1 horizontal
   strip, which is why every other treatment on the site has to work around it;
   here it is the point. Set in Prata, the serif this room already uses, on its
   own darkest ground rather than TEUF's ink.

   Copy is not new: the claim and the line under it are the two sentences of the
   About section's final paragraph, promoted rather than rewritten. */

.since {
  background: var(--events-bg);
  color: var(--events-on);
  border-top: 1px solid color-mix(in srgb, var(--events-on) 16%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--events-on) 16%, transparent);
  padding: clamp(40px, 6vw, 84px) var(--gutter);
  overflow: hidden;              /* the inscription is meant to run off */
}

.since__year {
  /* The logo's own face, licensed as a webfont 2026-09-18. Prata was the
     stand-in and remains the fallback while the file loads. */
  font-family: 'Tipton', 'Prata', serif;
  font-weight: 600;
  font-size: clamp(46px, 14.5vw, 210px);
  line-height: 1;
  letter-spacing: 0.02em;
  white-space: nowrap;
  margin: 0 0 clamp(20px, 3vw, 40px);
  /* Optical: Prata's cap height leaves a gap the band does not want. */
  margin-top: -0.06em;
}

.since__line {
  font-family: 'Prata', serif;
  font-size: clamp(18px, 2.1vw, 28px);
  line-height: 1.35;
  margin: 0 0 clamp(10px, 1.2vw, 14px);
  max-width: 30ch;
}

.since__after {
  font-size: var(--body);
  line-height: 1.7;
  opacity: 0.66;
  margin: 0;
  max-width: 46ch;
}

/* ---------- au Vin: the late hour ---------- */

/* Teuf au Vin's equivalent of the dining room's one-dish band, and deliberately
   not the same shape. TEUF's fact is about reduction, so one sentence alone on
   an empty ground is right for it. This fact is about a TIME — a charcuterie
   counter still open after 22.00 — so the hour itself is the object, and the
   claim sits beside it rather than under it.

   Its own ground too: --events-bg is au Vin's burnt brown, not TEUF's ink, so
   the room keeps its own voice at its loudest moment.

   Placed directly after the About so it lands beside the opening hours instead
   of three sections below them. For someone deciding at 21:45 this is the most
   useful sentence on the page; it used to be a quiet lead near the bottom. */

.latehour {
  background: var(--events-bg);
  color: var(--events-on);
  border-top: 1px solid color-mix(in srgb, var(--events-on) 16%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--events-on) 16%, transparent);
  padding: var(--section) var(--gutter);
  display: grid;
  gap: clamp(6px, 1.4vw, 28px) clamp(28px, 4.5vw, 72px);
  align-items: start;
}

.latehour__time {
  margin: 0;
  font-size: clamp(64px, 13vw, 190px);
  line-height: 0.86;
  letter-spacing: -0.045em;
  font-stretch: 125%;
  font-weight: 600;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  /* Optical: the tabular 2 leaves more room on the left than the cap line wants. */
  margin-left: -0.04em;
}

.latehour__body { min-width: 0; }

.latehour__claim {
  margin: 0 0 clamp(16px, 2vw, 24px);
  font-size: clamp(21px, 2.5vw, 34px);
  line-height: 1.18;
  letter-spacing: -0.01em;
  font-weight: 500;
  max-width: 26ch;
}

.latehour .body-text { opacity: 0.74; max-width: 54ch; }
.latehour .body-text:last-child { margin-bottom: 0; }

@media (min-width: 900px) {
  /* The hour takes its own column and the copy runs beside it — an asymmetric
     pairing rather than the single stacked column the dining room uses. */
  .latehour { grid-template-columns: auto minmax(0, 1fr); align-items: center; }
}

/* ---------- the answer, directly under the hero ---------- */

/* Two of the three confirmed visitor situations arrive wanting the same two
   facts: are you open, and which door. Before this band they were 3.6 and 5.9
   screens down on a phone, or behind an unlabelled hamburger. This is one line
   and it sits in the first screen after the hero.

   Deliberately quiet: a hairline and small caps, not a third ceremonial band.
   It answers a question; it is not trying to be looked at. */
.quickbar {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 4px clamp(14px, 2.4vw, 28px);
  padding: 0 var(--gutter);
  border-bottom: 1px solid color-mix(in srgb, currentColor 14%, transparent);
  font-size: clamp(11px, 0.95vw, 13px);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
/* The row is short; the tap areas are not. Padding carries both items past
   44px without changing how the line looks. */
.quickbar > * {
  display: inline-flex; align-items: center;
  min-height: 46px;
}
.quickbar .today { opacity: 0.9; }
.quickbar .maplink { text-decoration: none; opacity: 0.72; }
.quickbar .maplink:hover { opacity: 1; }

@media (max-width: 519px) {
  /* Genuinely stacked. flex-wrap alone was not enough — at 375px the two items
     just fit side by side, so with gap:0 they ran together as
     "STÄNGER 23.00MÄLARTORGET 15". Full-width basis forces the break. */
  .quickbar { gap: 0; }
  .quickbar > * { flex: 0 0 100%; min-height: 44px; }
  .quickbar .today { border-bottom: 1px solid color-mix(in srgb, currentColor 10%, transparent); }
}

/* ---------- press ---------- */

/* Read mode: a journalist is here to find a fact, a file and an address, in
   that order. Structure for scanning, not for atmosphere — no photography
   behind the header, because the photographs are the deliverable here rather
   than the decoration. */

/* The press page had no identity at all — no mark, no ground — on the one page
   where the house's own logotypes are the subject matter. It now wears the ink
   ground the shop header uses, but carries all three marks rather than one:
   that identifies the page and previews its deliverable in the same move. */
.presshead {
  position: relative;
  background: var(--ink);
  color: var(--light);
  --accent: var(--accent-hi);
  --accent-on: var(--ink);
  padding: clamp(96px, 13vh, 150px) var(--gutter) clamp(44px, 6vw, 72px);
  border-bottom: 0;
}

.presshead__marks {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: clamp(22px, 4vw, 54px);
  margin: 0 0 clamp(30px, 4.5vw, 54px);
  opacity: 0.85;
}
/* Sized by width per mark, not by height: the three assets carry very
   different transparent padding and cap heights. */
.presshead__mark { display: block; height: auto; }
/* Same 1 : 1.31 : 0.70 proportion the nav panel already uses, which was tuned
   against these three files. Sized to it directly, because Corner Club is a
   7.8:1 horizontal lockup and matching heights would make it enormous. */
.pm-teuf { width: clamp(84px, 12vw, 140px); }
.pm-club { width: clamp(110px, 15.7vw, 183px); }
.pm-vin  { width: clamp(58px, 8.4vw, 98px); }
.presshead__title {
  font-size: clamp(38px, 7vw, 96px);
  line-height: 1.02; letter-spacing: -0.03em;
  font-stretch: 118%; font-weight: 600;
  margin: 0;
}
.presshead__line {
  font-size: clamp(15px, 1.35vw, 19px); line-height: 1.6;
  opacity: 0.72; max-width: 46ch;
  margin: clamp(16px, 2vw, 24px) 0 clamp(24px, 3vw, 34px);
}
.presshead .back { position: absolute; }

.presssec {
  padding: var(--space-major) var(--gutter);
  border-bottom: 1px solid color-mix(in srgb, currentColor 12%, transparent);
}
.presssec:last-of-type { border-bottom: 0; }
.presssec[hidden] { display: none; }
.presssec__title {
  font-size: clamp(16px, 1.7vw, 21px); font-weight: 600; line-height: 1.2;
  margin: 0 0 clamp(24px, 3vw, 34px);
}
.presssec__sub {
  font-size: clamp(12px, 1vw, 13px); font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase;
  opacity: 0.6;
  margin: clamp(28px, 3.4vw, 40px) 0 clamp(14px, 1.8vw, 20px);
}
.presssec__sub:first-of-type { margin-top: 0; }
.presssec__note {
  font-size: clamp(12px, 1vw, 13px); line-height: 1.6; opacity: 0.66;
  max-width: 58ch; margin: clamp(26px, 3vw, 36px) 0 0;
}

/* Coverage and listings share a row: source and date on one line, then the
   headline as the link. The outlet leads because that is what a reader scans
   for. */
.presslist { list-style: none; margin: 0; padding: 0; display: grid; gap: clamp(22px, 2.8vw, 34px); }
.presslist__item { max-width: 62ch; }
.presslist__head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px clamp(12px, 1.6vw, 20px);
  margin-bottom: 6px;
}
.presslist__outlet {
  font-size: clamp(11px, 0.95vw, 13px); letter-spacing: 0.16em; text-transform: uppercase;
  font-weight: 600;
}
.presslist__date { font-size: clamp(11px, 0.95vw, 13px); opacity: 0.6; }
.presslist__headline {
  display: inline-block;
  font-size: clamp(17px, 1.7vw, 23px); line-height: 1.32;
  margin: 0; text-decoration: none;
}
a.presslist__headline { border-bottom: 1px solid color-mix(in srgb, currentColor 30%, transparent); padding-bottom: 2px; }
a.presslist__headline:hover { border-bottom-color: currentColor; }
.presslist__quote {
  font-size: var(--body); line-height: 1.7; opacity: 0.72;
  margin: 10px 0 0; padding: 0; max-width: 56ch;
}

/* Facts read as a reference table, so the label column is fixed and the values
   align — a journalist copies from this. */
.facts { margin: 0; display: grid; gap: clamp(14px, 1.8vw, 20px) clamp(20px, 3vw, 40px); }
.facts__label {
  font-size: clamp(11px, 0.95vw, 13px); letter-spacing: 0.16em; text-transform: uppercase;
  font-weight: 600; opacity: 0.6; margin: 0;
}
.facts__value { font-size: var(--body); line-height: 1.7; margin: 0; max-width: 62ch; }

@media (min-width: 720px) {
  .facts { grid-template-columns: clamp(130px, 15vw, 180px) minmax(0, 1fr); align-items: baseline; }
  .facts__label { grid-column: 1; }
  .facts__value { grid-column: 2; }
}

/* Download tiles. The preview is the file itself, so what you see is what you
   get — no generic file icon standing in for the asset. */
.kit {
  display: grid; gap: clamp(16px, 2.2vw, 28px);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr));
}
.kit__item { display: block; text-decoration: none; }
.kit__shot {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 3 / 2; overflow: hidden; padding: 12%;
  margin: 0 0 clamp(10px, 1.2vw, 14px);
  background: color-mix(in srgb, currentColor 7%, transparent);
}
.kit__shot img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; }
.kit__label { display: block; font-size: var(--body); line-height: 1.4; }
.kit__note { display: block; font-size: clamp(11px, 0.95vw, 12px); opacity: 0.6; margin-top: 3px; }
.kit__item:hover .kit__label { text-decoration: underline; text-underline-offset: 3px; }

/* Photographs are dark-ish and want no padding; logos are marks and want it. */
.kit--photos .kit__shot { padding: 0; }
.kit--photos .kit__shot img { width: 100%; height: 100%; object-fit: cover; }

/* ---------- the Butik block on a venue page ---------- */

/* Tertiary by intent: it sits after the menu on the tight interval so merch
   never competes with the menu or with booking. No card chrome — the product
   photograph is the object, and a box around it would only add weight this
   block has not earned. */

.merch { padding: var(--space-tight) var(--gutter); }
.merch[hidden] { display: none; }

.merch__head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 10px clamp(16px, 2.4vw, 28px);
  margin: 0 0 clamp(20px, 2.6vw, 30px);
}
.merch__title { font-size: clamp(16px, 1.7vw, 21px); font-weight: 600; line-height: 1.2; margin: 0; }
/* The visible mark is a short underlined line; the tap area is not. Padding
   carries it to 44px without changing how it looks, and the negative margin
   keeps it optically aligned with the heading beside it. */
.merch__all {
  font-size: clamp(11px, 0.95vw, 13px); letter-spacing: 0.16em; text-transform: uppercase;
  text-decoration: none;
  display: inline-flex; align-items: center; min-height: 44px;
  margin: -13px 0;
}
.merch__all span { border-bottom: 1px solid currentColor; padding-bottom: 2px; }

.merch__grid {
  display: grid; gap: clamp(16px, 2.4vw, 30px);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
}

.merch__item { display: block; text-decoration: none; }
.merch__shot {
  display: block; aspect-ratio: 1 / 1; overflow: hidden;
  margin: 0 0 clamp(10px, 1.2vw, 14px);
  background: color-mix(in srgb, currentColor 7%, transparent);
}
.merch__shot img { width: 100%; height: 100%; object-fit: cover; }
.merch__shot--empty { border: 1px solid color-mix(in srgb, currentColor 22%, transparent); }

.merch__name { display: block; font-size: var(--body); line-height: 1.4; }
.merch__price { display: block; font-size: clamp(12px, 1vw, 13px); opacity: 0.66; margin-top: 3px; }

.merch__item:hover .merch__name { text-decoration: underline; text-underline-offset: 3px; }

/* Belt and braces with the z-index: while a modal is open the page chrome is not
   just behind it, it is gone.

   .is-locked is set by both the lightbox and the cart, and neither owns the nav
   button, so suppressing it there is right for both. The nav panel does NOT set
   .is-locked — it uses .nav-open — so the nav keeps its own close button. */
body.is-locked .navbtn,
body.is-locked .shophead__cart { opacity: 0; pointer-events: none; }

/* ---------- opening hours ---------- */

.hours { display: flex; flex-direction: column; gap: 5px; }
.hours__row { display: flex; gap: clamp(14px, 2vw, 26px); font-size: var(--body); line-height: 1.6; opacity: 0.66; }
.hours__row--today { opacity: 1; font-weight: 600; }
.hours__day { min-width: 7ch; letter-spacing: 0.02em; }
.hours__time { font-variant-numeric: tabular-nums; }

.today { display: inline-flex; align-items: center; gap: 8px; }
/* Open and closed were separated by the opacity of an otherwise identical dot,
   which is to say the dot said nothing. Open is now lit; closed stays a faint
   neutral. The text beside it already names the state, so colour is never the
   only code. */
.today::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto;
  background: currentColor; opacity: 0.3;
}
.today.is-open::before { background: var(--accent); opacity: 1; }

/* A block for something that deserves more than a line inside About —
   au Vin's cheese and charcuterie counter, which is its own reason to visit. */
.feature {
  padding: var(--space-tight) var(--gutter);
  border-top: 1px solid color-mix(in srgb, currentColor 16%, transparent);
}
.feature__lead {
  font-size: clamp(22px, 2.6vw, 32px);
  line-height: 1.24;
  margin: 0 0 clamp(20px, 2.4vw, 28px);
  max-width: 24ch;
}
.v-vin .feature__lead { font-family: 'Caveat', cursive; font-weight: 700; font-size: clamp(28px, 3.4vw, 42px); }
.v-club .feature__lead { font-family: 'Prata', serif; }

/* ---------- full-screen navigation ---------- */

.navbtn {
  position: fixed; top: clamp(14px, 2vw, 28px); right: clamp(14px, 3vw, 44px);
  z-index: 120;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 5px; width: 52px; height: 52px; padding: 0;
  border: 1px solid rgba(244,239,228,0.3); border-radius: 50%;
  background: rgba(20,15,10,0.34);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  cursor: pointer;
}
.navbtn__bar {
  display: block; width: 18px; height: 1.5px; background: var(--light);
  transition: transform 420ms var(--ease), opacity 220ms var(--ease);
}
body.nav-open .navbtn { background: transparent; border-color: rgba(244,239,228,0.4); }
body.nav-open .navbtn__bar:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
body.nav-open .navbtn__bar:nth-child(2) { opacity: 0; transform: scaleX(0); }
body.nav-open .navbtn__bar:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

.navpanel {
  position: fixed; inset: 0; z-index: 110;
  background: var(--ink); color: var(--light);
  display: flex; flex-direction: column; justify-content: space-between;
  gap: clamp(28px, 5vh, 60px);
  padding: clamp(84px, 11vh, 130px) var(--gutter) clamp(28px, 5vh, 56px);
  overflow-y: auto;
  /* The wipe: closed is a zero-height sliver at the top. */
  clip-path: inset(0 0 100% 0);
  transition: clip-path 760ms var(--ease);
}
.navpanel[hidden] { display: none; }
body.nav-open .navpanel { clip-path: inset(0 0 0 0); }

.navpanel__rooms { display: flex; flex-direction: column; }
.navpanel__room {
  text-decoration: none; line-height: 1.08;
  align-items: center;
  padding: clamp(4px, 0.8vh, 10px) 0;
  display: flex; align-items: baseline; gap: clamp(10px, 1.6vw, 22px); flex-wrap: wrap;
  opacity: 0; transform: translateY(18px);
  transition: opacity 620ms var(--ease), transform 620ms var(--ease), color 220ms var(--ease);
}
body.nav-open .navpanel__room { opacity: 1; transform: none; }
/* The delays used to be declared for rows 1-4 while five rows existed, so Press
   got 0ms and the stagger ran backwards — the last item arrived before the
   first. The base delay below means a row added later inherits a sane value
   instead of jumping the queue. */
body.nav-open .navpanel__room            { transition-delay: 300ms; }
body.nav-open .navpanel__room:nth-child(2) { transition-delay: 370ms; }
body.nav-open .navpanel__room:nth-child(3) { transition-delay: 440ms; }
body.nav-open .navpanel__room:nth-child(4) { transition-delay: 510ms; }
body.nav-open .navpanel__room:nth-child(5) { transition-delay: 580ms; }
body.nav-open .navpanel__room:nth-child(n+6) { transition-delay: 650ms; }
.navpanel__room:hover { color: #fff; }
body.nav-open .navpanel__room[aria-current="page"] { opacity: 0.4; }
.navpanel__room[aria-current="page"] { cursor: default; }

/* The rooms use their real wordmarks, not typeset substitutes. Two of the
   three cannot be set as type at all: the au Vin mark is drawn lettering, and
   Corner Club's Tipton Demi carries a desktop-only licence that explicitly
   forbids @font-face. The artwork is the only correct letterform.
   Sized by height, since the three have very different proportions. */
.navpanel__mark { display: block; height: auto; }
/* Sized by width, not height: the PNGs carry transparent padding, so their
   box height is not their letterform height. Tuned by eye so the four rows
   carry similar visual weight. */
.nv-teuf .navpanel__mark { width: clamp(120px, 21vw, 260px); margin: -3% 0; }
.nv-club .navpanel__mark { width: clamp(150px, 27vw, 340px); }
.nv-vin  .navpanel__mark { width: clamp(86px, 15vw, 182px); margin: -2% 0; }
.navpanel__name { font-size: clamp(26px, 4.8vw, 58px); }
.nv-shop .navpanel__name,
.nv-press .navpanel__name { font-weight: 500; font-stretch: 112%; }
.navpanel__role {
  font-size: clamp(9px, 0.85vw, 11px); letter-spacing: 0.3em; text-transform: uppercase;
  opacity: 0.5;
}

.navpanel__foot {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: clamp(16px, 3vw, 40px);
  opacity: 0; transform: translateY(12px);
  transition: opacity 500ms var(--ease) 620ms, transform 500ms var(--ease) 620ms;
}
body.nav-open .navpanel__foot { opacity: 1; transform: none; }
.navpanel__meta { display: flex; flex-direction: column; gap: 7px; font-size: clamp(11px, 1vw, 13px); opacity: 0.66; }

body.nav-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .navpanel { transition: none; }
  .navpanel__room, .navpanel__foot { transition: none; opacity: 1; transform: none; }
}

.navpanel__actions { display: flex; align-items: center; gap: clamp(16px, 2.4vw, 28px); }
.social {
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;           /* full tap target, icon stays 22px */
  color: var(--light); opacity: 0.66;
  transition: opacity 200ms var(--ease);
}
.social:hover { opacity: 1; }
.social svg { width: 22px; height: 22px; display: block; }

/* The address is a link everywhere it appears — on a phone it opens the maps
   app, which is what people actually want from it. */
.maplink {
  color: inherit; text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
  opacity: 0.85;
  transition: opacity 180ms var(--ease);
}
.maplink:hover { opacity: 1; }
.util .maplink, .foot .maplink { border-bottom-color: rgba(239,231,216,0.4); }

/* ---------- revealed footer ---------- */
/* The page clips a fixed panel, so the footer reads as sitting behind the page
   and being uncovered as you reach the bottom. Ported from a React component;
   the mechanism is entirely CSS. clip-path clips fixed descendants without
   making them scroll, which is the whole trick. */

.revealfoot {
  /* Tall enough for the content it holds — measured, not guessed. The phone
     layout stacks three columns and needs more height than the desktop one. */
  /* svh, not vh: the hero already uses svh, and sizing the footer to the LARGE
     viewport meant its bottom row could sit under iOS browser chrome. */
  --foot-h: clamp(560px, 70svh, 620px);
  position: relative;
  height: var(--foot-h);
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
.revealfoot__panel {
  position: fixed; bottom: 0; left: 0;
  width: 100%; height: var(--foot-h);
  background: var(--ink); color: #EFE7D8;
  display: flex; flex-direction: column;
  padding: clamp(30px, 5vh, 56px) var(--gutter) clamp(20px, 3vh, 30px);
  box-sizing: border-box;
  overflow-y: auto;
}
.revealfoot__cols {
  flex: 1 1 auto;
  display: grid; gap: clamp(24px, 4vw, 64px);
  grid-template-columns: 1fr;
}
.revealfoot .eyebrow { opacity: 0.45; margin-bottom: clamp(10px, 1.4vw, 16px); }
.revealfoot__addr { font-size: var(--body); line-height: 1.7; margin: 0 0 10px; }
.revealfoot .hours__row { opacity: 0.6; }
.revealfoot .hours__row--today { opacity: 1; }
.revealfoot__act { display: flex; flex-wrap: wrap; align-items: center; gap: clamp(14px, 2vw, 22px); }
/* Instagram and booking sit at the lower corners of the footer, above the rule.
   The fine print goes below it. */
.revealfoot__actions {
  display: flex; align-items: center; justify-content: space-between;
  gap: clamp(12px, 2vw, 24px);
  padding-bottom: clamp(18px, 2.6vh, 28px);
}
.revealfoot__actions .social { margin-left: -12px; }   /* optical align to the gutter */

.revealfoot__base {
  display: flex; flex-wrap: wrap; justify-content: space-between;
  gap: 6px clamp(16px, 3vw, 32px);
  padding-top: clamp(14px, 2vh, 20px);
  border-top: 1px solid rgba(239,231,216,0.16);
}
.revealfoot__fine {
  font-size: clamp(10px, 0.85vw, 12px); letter-spacing: 0.14em; text-transform: uppercase;
  opacity: 0.5; line-height: 1.7;
}
.revealfoot__fine a { color: inherit; text-decoration: none; border-bottom: 1px solid rgba(239,231,216,0.3); padding-bottom: 1px; }
.revealfoot__fine a:hover { border-bottom-color: currentColor; }


.revealfoot .social { color: #EFE7D8; }

@media (min-width: 760px) {
  .revealfoot__cols { grid-template-columns: 1.2fr 1fr 1fr; align-items: start; }
}

/* If the reveal ever misbehaves — iOS Safari has historically been awkward
   with fixed inside a clipped ancestor — this turns it into an ordinary
   footer and loses nothing but the effect:
     .revealfoot { height: auto; clip-path: none; }
     .revealfoot__panel { position: static; height: auto; }
   Needs checking on real hardware before deciding. */

.contact { list-style: none; margin: 0 0 clamp(16px, 2.4vh, 24px); padding: 0; display: flex; flex-direction: column; gap: 7px; }
.contact a {
  font-size: var(--body); color: inherit; text-decoration: none;
  border-bottom: 1px solid rgba(239,231,216,0.3); padding-bottom: 1px;
  transition: border-color 180ms var(--ease);
}
.contact a:hover { border-bottom-color: currentColor; }
.contact__tag {
  font-size: clamp(9px, 0.75vw, 10px); letter-spacing: 0.22em;
  text-transform: uppercase; opacity: 0.45; margin-left: 8px;
}

/* Butik already has a cart button top-right, so the menu toggle would land on
   top of it. Make the cart fixed too, sit it to the left of the toggle, and
   take it out of the way while the menu is open. */
/* Fixed, so it is over the dark header at the top of the page and over the cream
   product grid everywhere else. It used to inherit the header's light colour and
   measured 1.08:1 against the page the moment you scrolled — the only persistent
   route to the cart, invisible for the whole time you are shopping. It now
   carries its own ground so it reads on both. */
.shop-page .shophead__cart {
  position: fixed;
  top: clamp(14px, 2vw, 28px);
  right: calc(clamp(14px, 3vw, 44px) + 64px);
  z-index: 115;
  background: var(--ink);
  color: var(--light);
  border-color: var(--ink);
  transition: opacity 260ms var(--ease), background 200ms var(--ease), color 200ms var(--ease);
}
.shop-page .shophead__cart:hover { background: var(--accent-hi); color: var(--ink); border-color: var(--accent-hi); }
.shop-page .shophead__cart:hover .pill { background: var(--ink); color: var(--accent-hi); }
body.nav-open .shophead__cart { opacity: 0; pointer-events: none; }

/* The shop has no opening hours of its own, so its footer runs two columns. */
@media (min-width: 760px) {
  .revealfoot--shop .revealfoot__cols { grid-template-columns: 1.2fr 1fr; }
}
