/* ─────────────────────────────────────────────────────────
   BLVCK ROSE COLLECTIVE — MAIN STYLESHEET
   Mobile-first throughout. Desktop is the adaptation.
   Created: 2026-07-19
───────────────────────────────────────────────────────── */

/* ── A NOTE ON THE BREAKPOINTS, before someone tidies them ──
   There are eleven min-widths in this file — 420, 560, 620, 700, 720, 780,
   800, 820, 900, 1000, 1100 — and they are not drift. Each one is the width at
   which that particular component's content stops fitting, measured rather
   than chosen:

     700  .roster        artist cards reach their minimum readable column
     720  .reviews-grid  two review quotes fit without either going narrow
     780  .feed-head     title and body sit side by side with room between
     800  .info-grid     footer hours and address hold two columns
     820  nav            the full nav fits, so the menu button retires
     1100 .reviews-grid  a third quote column

   An audit flagged the count as maintenance cost, which is fair, and the fix
   looked like collapsing them onto a shared scale. Checked component by
   component, that would be worse: forcing .feed-head to wait until 820 leaves
   it stacked for 40px of viewport where it plainly fits, and every other
   component has the same problem in a different direction. Content-driven
   breakpoints beat a device scale. Leave them, and set new ones the same way —
   resize until it breaks, then use that number. */

/* ── Reset ── */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
img, svg, video { display: block; max-width: 100%; height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
ul[role="list"] { list-style: none; }
a { color: inherit; text-decoration: none; }

body {
  background: var(--ink);
  color: var(--bone);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;                 /* never scroll sideways */
}

/* Film grain over everything. Sells "gallery print" rather than "web page".
   Pointer-events off so it never eats a tap. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ── Type ── */
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;              /* Archivo Black ships at one weight */
  line-height: 1.02;
  letter-spacing: -0.02em;       /* a black grotesque needs pulling in */
  text-wrap: balance;
}
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--bone-faint);
}
.muted { color: var(--bone-muted); }

/* ── Layout ── */
.wrap { width: 100%; max-width: var(--w-normal); margin-inline: auto; padding-inline: var(--sp-5); }
.section { padding-block: var(--sp-10); }
@media (min-width: 900px) { .section { padding-block: var(--sp-12); } }

.rule { height: 1px; background: var(--hairline); border: 0; }

/* ═══════════════════════════════════════════════════════
   SPLITTER — the landing choice
   Mobile: two stacked panels, tap to enter.
   Desktop: two halves; hovering one lets it take more room.
   Two states only. No third in-between layout.
═══════════════════════════════════════════════════════ */
/* Minus the header: it is sticky, so it occupies flow above the splitter.
   At a flat 100svh the panel below the fold was always the header's height
   off-screen — harmless while nothing sat under the panels, but it pushed
   the address and scroll cue out of view once they were added. */
.splitter {
  min-height: calc(100svh - var(--header-h));
  display: flex; flex-direction: column;
}

.splitter-head {
  text-align: center;
  /* Tightened when the address and scroll cue moved in below the panels.
     Both doors have to stay visible without scrolling — that choice is the
     whole page — so the chrome around them gives up the room. */
  padding: var(--sp-6) var(--sp-5) var(--sp-4);
}
.splitter-head h1 {
  font-size: var(--text-3xl);
  max-width: 18ch;
  margin-inline: auto;
  margin-block: var(--sp-3) var(--sp-2);
}
.splitter-head .sub { color: var(--bone-muted); font-size: var(--text-sm); }

.panels { flex: 1; display: flex; flex-direction: column; gap: 2px; background: var(--hairline); }

.panel {
  position: relative;
  flex: 1 1 0;
  /* A floor, not a target: the panels flex to fill whatever the splitter
     has left after the heading, address and cue. Set high enough and the
     two of them alone overflow a phone screen. */
  min-height: 24svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--ink-raised);
  isolation: isolate;
  transition: flex-grow var(--dur-slow) var(--ease-out);
}
.panel-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  /* Monochrome by default; the brand is black and white. */
  filter: grayscale(1) contrast(1.08) brightness(0.62);
  transform: scale(1.04);
  transition: transform var(--dur-slow) var(--ease-out),
              filter   var(--dur-slow) var(--ease-out);
  z-index: -2;
}
/* Legibility scrim. The first version faded out too early and the kicker
   sat over bright wall — unreadable. The dark band now extends well past
   the text block so every panel reads regardless of what the photo does. */
.panel::before {
  content: '';
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top,
    rgba(0,0,0,0.94) 0%,
    rgba(0,0,0,0.88) 26%,
    rgba(0,0,0,0.60) 48%,
    rgba(0,0,0,0.30) 70%,
    rgba(0,0,0,0.55) 100%);
}
.panel-body { padding: var(--sp-6) var(--sp-5) var(--sp-8); width: 100%; }
.panel-kicker {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  /* Not --bone-faint here: over a photo that tone disappears. Panels get
     the brighter muted tone plus a shadow to hold an edge on any frame. */
  color: var(--bone-muted);
  text-shadow: 0 1px 10px rgba(0,0,0,0.85);
  margin-bottom: var(--sp-2);
}
.panel-title, .panel-line { text-shadow: 0 1px 14px rgba(0,0,0,0.8); }
.panel-title { font-size: var(--text-2xl); margin-bottom: var(--sp-2); }
.panel-line  { color: var(--bone-muted); font-size: var(--text-sm); max-width: 34ch; }
.panel-cta {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-5);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--hairline-bright);
  transition: border-color var(--dur-fast) var(--ease-out),
              gap var(--dur-fast) var(--ease-out);
}

/* Side identity — a hairline of colour, nothing more. */
.panel[data-side="barber"] .panel-cta { border-bottom-color: var(--barber-tint); }
.panel[data-side="tattoo"] .panel-cta { border-bottom-color: var(--tattoo-tint); }

.panel:hover  .panel-img,
.panel:focus-within .panel-img { filter: grayscale(0.15) contrast(1.02) brightness(0.72); transform: scale(1); }
.panel:hover  .panel-cta { gap: var(--sp-4); }

.splitter-foot {
  text-align: center;
  padding: var(--sp-5) var(--sp-5) var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  color: var(--bone-faint);
}
/* Monospace at full tracking wraps this address onto two lines on a phone
   and strands "NH" on its own. Tighten it rather than shorten the address. */
@media (max-width: 430px) {
  .splitter-foot { letter-spacing: 0.01em; font-size: var(--text-xs); }
}
/* The address links to directions. Underlined on hover only — a permanent
   underline on a monospace line this small turns into visual noise. */
.splitter-foot a { color: inherit; text-decoration: none; display: inline-flex; align-items: center;
  /* min-height rather than padding arithmetic: 12px of padding plus this
     line-height landed at 43.8px, which is under the 44px floor by a
     fifth of a pixel and still counts as under. */
  min-height: 44px; padding: var(--sp-2); }
.splitter-foot a:hover,
.splitter-foot a:focus-visible { color: var(--rose); text-decoration: underline; }

/* Scroll cue. The door choice fills the first screen on purpose, so the
   shared block below it needs to announce itself or nobody scrolls. */
.splitter-cue {
  text-align: center;
  padding: 0 var(--sp-5) var(--sp-4);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--bone-faint);
  opacity: 0.65;
}
.splitter-cue::after {
  content: '';
  display: block;
  width: 1px; height: 16px;
  margin: var(--sp-2) auto 0;
  background: linear-gradient(180deg, var(--rose-hair), transparent);
}

@media (min-width: 900px) {
  .panels { flex-direction: row; }
  /* Side by side here, so this is the height of a single row rather than a
     stack of two. Still a floor, not a target — at 62svh the address and
     cue below the panels fell off a 1280x800 screen. */
  .panel { min-height: 50svh; }
  .panel:hover { flex-grow: 1.35; }     /* the chosen side leans forward */
  .panel-body { padding: var(--sp-8); }
  .panel-title { font-size: var(--text-3xl); }
}

/* ═══════════════════════════════════════════════════════
   SITE HEADER (side pages)
═══════════════════════════════════════════════════════ */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: rgba(0,0,0,0.78);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--hairline);
}
.header-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4);
  height: var(--header-h);
}
.wordmark {
  font-family: var(--font-display);
  font-size: 0.95rem;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  line-height: 1.1;
  min-width: 0;                 /* allow it to shrink instead of pushing */
}
@media (min-width: 560px) { .wordmark { font-size: var(--text-lg); } }
.wordmark small {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--bone-faint);
}
.switch {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--hairline-bright);
  border-radius: 999px;
  white-space: nowrap;
  flex: 0 0 auto;               /* never let the wordmark squash it */
  min-height: 40px;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  transition: border-color var(--dur-fast), background var(--dur-fast);
}
/* Short label on phones, full label once there is room. */
.sw-full  { display: none; }
.sw-short { display: inline; }
@media (min-width: 560px) {
  .sw-full  { display: inline; }
  .sw-short { display: none; }
}
.switch:hover { border-color: var(--bone-muted); background: var(--ink-raised); }

/* ═══════════════════════════════════════════════════════
   SIDE HERO
═══════════════════════════════════════════════════════ */
.hero { position: relative; overflow: hidden; isolation: isolate; }
.hero-img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.04) brightness(0.72);
  z-index: -2;
}
.hero::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top, var(--ink) 4%, rgba(0,0,0,0.55) 60%, rgba(0,0,0,0.7) 100%);
}
.hero-inner { padding-block: var(--sp-10) var(--sp-8); }
@media (min-width: 900px) { .hero-inner { padding-block: var(--sp-12) var(--sp-10); } }
.hero h1 { font-size: var(--text-4xl); margin-block: var(--sp-3) var(--sp-5); max-width: 15ch; }
/* A `.lede` inside a hero was constrained; a `.lede` anywhere else was not,
   so the shop's own description on the home page and the contact page ran the
   full 1132px column — 139 and 150 characters per line, measured. The eye
   loses the return sweep well before that. `ch` is the width of "0", which is
   wider than the average letter, so 60ch renders around 70 real characters. */
.lede { max-width: 60ch; }
.hero .lede { color: var(--bone-muted); max-width: 46ch; }

/* ═══════════════════════════════════════════════════════
   ROSTER — horizontal snap carousel on mobile, grid on desktop
═══════════════════════════════════════════════════════ */
.roster-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-4); margin-bottom: var(--sp-5);
}
.roster-head h2 { font-size: var(--text-2xl); }
.roster-count { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--bone-faint); }

/* Stacked on phones, not a side-scrolling carousel — Brian's call,
   2026-07-19.
   The carousel showed one and a bit cards at a time and hid the rest behind
   a swipe most visitors never make. On a page where the artists ARE the
   product, and where nearly all the traffic arrives from an Instagram bio
   link, every artist should be seen without being asked to look. It costs
   page length and buys visibility for everyone below position two. */
.roster {
  display: grid;
  grid-auto-flow: row;
  grid-template-columns: 1fr;
  gap: var(--sp-5);
}

@media (min-width: 700px) {
  .roster {
    grid-auto-flow: row;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    grid-auto-columns: auto;
    overflow: visible;
    padding-inline: 0;
    margin-inline: 0;
  }
}

/* ── Artist card ── */
.card {
  position: relative;
  display: block;
  background: var(--ink-raised);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  overflow: hidden;
  transition: border-color var(--dur-mid) var(--ease-out),
              transform var(--dur-mid) var(--ease-out),
              background var(--dur-mid) var(--ease-out);
}
.card:hover { border-color: var(--hairline-bright); background: var(--ink-elevated); transform: translateY(-3px); }

.card-media { position: relative; aspect-ratio: 4 / 5; overflow: hidden; background: #0E0E10; }
.card-media img {
  width: 100%; height: 100%; object-fit: cover;
  /* The unifying move: every supplied photo arrives with different
     lighting and colour temperature. Monochrome makes them one set;
     colour returns on hover as a reward, not as noise. */
  filter: grayscale(1) contrast(1.1) brightness(0.86);
  transform: scale(1.02);
  transition: filter var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}
.card:hover .card-media img { filter: grayscale(0) contrast(1) brightness(1); transform: scale(1.06); }

/* Action shots are framed higher — the subject is working, not posing. */
.card-media img[data-style="action"] { object-position: 50% 32%; }

/* Missing photo: a typographic monogram instead of a broken image. */
.card-monogram {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--font-black);   /* blackletter, echoing the BR mark */
  font-size: 4rem;
  /* --bone-faint vanished against the card ground. The monogram is the
     stand-in for a face, so it has to actually register. */
  color: #4A4741;
  background:
    radial-gradient(120% 90% at 50% 0%, #17171A 0%, #0B0B0D 70%);
  letter-spacing: 0.04em;
}

.card-body { padding: var(--sp-4); }
.card-name { font-size: var(--text-lg); line-height: 1.2; }
.card-role {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--bone-faint);
  margin-top: 6px;
}
.card-meta {
  display: flex; align-items: center; gap: var(--sp-3);
  margin-top: var(--sp-3);
  font-family: var(--font-mono); font-size: var(--text-xs);
  color: var(--bone-muted);
}
.stars { color: var(--barber-tint); letter-spacing: 0.1em; }

.badge {
  position: absolute; top: var(--sp-3); left: var(--sp-3);
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  padding: 4px var(--sp-2);
  background: rgba(0,0,0,0.7);
  border: 1px solid var(--hairline-bright);
  border-radius: 999px;
  backdrop-filter: blur(6px);
}

/* ═══════════════════════════════════════════════════════
   BUTTONS
═══════════════════════════════════════════════════════ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  padding: var(--sp-3) var(--sp-5);
  border: 1px solid var(--bone);
  border-radius: 999px;
  background: var(--bone);
  color: var(--ink);
  min-height: 44px;                 /* thumb-sized */
  transition: opacity var(--dur-fast), transform var(--dur-fast);
}
.btn:hover { opacity: 0.86; }
.btn:active { transform: translateY(1px); }
.btn--ghost { background: transparent; color: var(--bone); border-color: var(--hairline-bright); }
.btn--ghost:hover { border-color: var(--bone-muted); opacity: 1; }
.btn--block { width: 100%; }

/* ═══════════════════════════════════════════════════════
   INFO BLOCKS
═══════════════════════════════════════════════════════ */
.info-grid { display: grid; gap: var(--sp-6); }
@media (min-width: 800px) { .info-grid { grid-template-columns: 1fr 1fr; gap: var(--sp-10); } }

.info h3 {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider); text-transform: uppercase;
  color: var(--bone-faint); margin-bottom: var(--sp-4);
}
.hours { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.hours td { padding: var(--sp-2) 0; border-bottom: 1px solid var(--hairline); }
.hours td:last-child { text-align: right; color: var(--bone-muted); font-variant-numeric: tabular-nums; }
.hours tr:last-child td { border-bottom: 0; }
.hours-note { margin-top: var(--sp-3); font-size: var(--text-xs); color: var(--bone-faint); line-height: 1.6; max-width: 52ch; }

.contact-list { display: flex; flex-direction: column; gap: var(--sp-3); font-size: var(--text-sm); }
/* 44px tap targets without moving the layout: the padding grows the hit
   area, the reduced gap gives back the space it took. */
.contact-list { gap: var(--sp-1); }
.contact-list a { display: block; padding: var(--sp-2) 0; min-height: 44px; box-sizing: border-box; }
.contact-list a:hover { color: var(--bone); text-decoration: underline; text-underline-offset: 3px; }

/* ═══════════════════════════════════════════════════════
   ARTIST DETAIL
═══════════════════════════════════════════════════════ */
.artist-grid { display: grid; gap: var(--sp-6); }

/* The artist + room strip. Two up on a phone so it reads as a set rather than
   three more full-width images to scroll past. */
.artist-aside {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3);
}
.artist-aside figure { margin: 0; }
.artist-aside img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  background: #0E0E10;
  /* ⛔ NO grayscale here. Brian's rule, 2026-08-17: black-and-grey-turns-colour is
     the effect for BROWSING artists — the roster cards on the barber and tattoo
     pages, and the shop feed. Once you are on someone's own page, a colour photo
     stays colour; you should not have to hover to see the room properly.
     This matches .work-tile img below: a touch down, lifting on hover, colour
     intact throughout. It was grayscale(1) for about an hour and he caught it. */
  filter: brightness(0.92) contrast(1.04);
  transform: scale(1.005);
  transition: filter var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}
.artist-aside img:hover,
.artist-aside img:focus-visible { filter: none; transform: scale(1.02); }
@media (prefers-reduced-motion: reduce) {
  .artist-aside img { transition: none; transform: none; }
  .artist-aside img:hover, .artist-aside img:focus-visible { transform: none; }
}

@media (min-width: 820px) {
  .artist-grid { grid-template-columns: 0.85fr 1fr; gap: var(--sp-10); align-items: start; }
  /* Explicit placement, because the aside comes AFTER the bio in the markup:
     phones get portrait -> name and bio -> the strip, which keeps the name high.
     Wide screens pull the strip back under the portrait, on the left. */
  .artist-photo { grid-column: 1; grid-row: 1; }
  .artist-aside { grid-column: 1; grid-row: 2; margin-top: calc(var(--sp-3) - var(--sp-6)); }
  /* ⭐ Exactly THREE aside tiles orphan the third in a 2-column grid, leaving a dead
     gap beside it on a wide screen. Added 2026-08-21 when Dale gained a third tile
     (profile, at work, her room) — Brian: "we only need one office picture, but you
     need to include all the pictures".
     ⚠️ This is NOT Dale-only, and I checked rather than assumed: DEREK NORDGREN and
     MONIQUE DESROCHES already had three tiles and the same orphan gap, so this fixes
     their pages too. Counted from the config, all ten artists: 3 tiles = derek,
     monique, dale · 2 = juan, matthew-brown, anna · 1 = miquela, karissa, matthew-baker
     · 4 = skybrow (4 fills two rows cleanly, so it is unaffected).
     ⛔ DESKTOP ONLY on purpose. Three across a 375px phone gives 96px tiles, which is
     too small for a photo of a person; the phone keeps 2-up at 151px and wraps. */
  .artist-aside:has(figure:first-child:nth-last-child(3)) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .artist-intro { grid-column: 2; grid-row: 1 / span 2; }
}

.artist-photo {
  position: relative;
  aspect-ratio: 4 / 5;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  overflow: hidden;
  background: #0E0E10;
}
.artist-photo img { width: 100%; height: 100%; object-fit: cover; }
.artist-name { font-size: var(--text-3xl); }
.artist-role {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--bone-faint); margin-top: var(--sp-2);
}
.artist-actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-6); }

.linkrow { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: var(--sp-6); }
.linkrow a {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--hairline);
  font-size: var(--text-sm);
}
.linkrow a:hover { color: var(--bone); }
.linkrow .lbl { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--bone-faint); }

/* ═══════════════════════════════════════════════════════
   FOOTER
═══════════════════════════════════════════════════════ */
.site-footer {
  border-top: 1px solid var(--hairline);
  padding-block: var(--sp-8);
  margin-top: var(--sp-10);
  font-size: var(--text-sm);
  color: var(--bone-muted);
}
.footer-note { font-size: var(--text-xs); color: var(--bone-faint); margin-top: var(--sp-4); line-height: 1.7; max-width: 52ch; }

/* ═══════════════════════════════════════════════════════
   MOTION / ACCESSIBILITY
═══════════════════════════════════════════════════════ */
/* Hidden ONLY when JS is present and has taken responsibility for
   revealing. Without .js-reveal the content simply shows. */
/* One rule, no competition: hide ONLY while un-revealed and only when JS
   has taken responsibility (.js-reveal on <html>). Two rules fighting over
   the same properties produced an element that stayed invisible even with
   .in applied, so the revealed state now has nothing to out-rank. */
.reveal {
  transition: opacity var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}
.js-reveal .reveal:not(.in) { opacity: 0; transform: translateY(14px); }

/* ── Clearance for the chat launchers ──
   js/chat-widgets.js puts .has-chat-widgets on <html> when it renders. The
   launchers are fixed in the bottom corners, so anything that sits at the foot
   of the viewport has to move up out from under them or it is simply hidden.
   Reserved height = orb + label + bottom offset, which is ~100px on a phone
   and ~130px on desktop where the orb is 92px rather than 62px. */
.has-chat-widgets .site-footer { padding-bottom: 104px; }
@media (min-width: 561px) {
  .has-chat-widgets .site-footer { padding-bottom: 136px; }
}

/* Photographs ship as WebP with a JPEG fallback, which needs a picture element
   wrapping the image. `display: contents` makes that wrapper generate no box
   at all, so every layout rule written against the image — object-fit,
   absolute positioning, the panel and hero sizing — behaves exactly as it did
   when the image was a direct child. Without this line the wrapper would be an
   inline element and several of those layouts would quietly collapse. */
picture { display: contents; }

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

/* Skip link. Off-screen until focused, then it lands as a solid chip over the
   header — not a 1px clipped box, so it is actually readable when it appears. */
.skip-link {
  position: absolute;
  left: var(--sp-4);
  top: -100%;
  z-index: 200;
  padding: var(--sp-3) var(--sp-5);
  background: var(--ink-raised);
  border: 1px solid var(--rose);
  border-radius: var(--r-md);
  color: var(--bone);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  text-decoration: none;
  transition: top var(--dur-fast) var(--ease-out);
}
.skip-link:focus { top: var(--sp-3); }

/* Reduced motion. The blanket `0.001ms !important` this replaces killed
   transitions as well as animation — including the ones that are not
   decoration but feedback: the menu opening, a focus ring arriving, a button
   answering a press. "Reduce" does not mean "remove"; it means stop the
   large, looping, unrequested movement. So:
     · looping and drifting animation is cancelled outright
     · reveal-on-scroll resolves to its finished state immediately
     · state transitions survive, clamped short enough not to read as motion
   The hero, sheen and gallery images have their own targeted blocks further
   down, which stay. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-iteration-count: 1 !important;
    animation-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  /* Feedback keeps a short transition; nothing here reads as movement. */
  *, *::before, *::after { transition-duration: 90ms !important; }
  /* Anything that moves position or scale is the part to stop. */
  *, *::before, *::after {
    transition-property: color, background-color, border-color, outline-color,
                         opacity, fill, stroke !important;
  }
  .reveal { opacity: 1; transform: none; }
}

/* ═══════════════════════════════════════════════════════
   VISIT — address, hours, directions above the footer
═══════════════════════════════════════════════════════ */
.visit { border-top: 1px solid var(--hairline); }
.visit-grid { display: grid; gap: var(--sp-8); }
@media (min-width: 820px) {
  .visit-grid { grid-template-columns: 1fr 1fr; gap: var(--sp-10); align-items: start; }
}
.visit-title { font-size: var(--text-2xl); margin-top: var(--sp-3); max-width: 18ch; }

/* Front desk — the shop manager, after Visit. Support role, so it reads
   as a card, not a hero: small portrait, two short paragraphs, two links. */
.about-grid { display: grid; gap: var(--sp-6); }
.about-photo img { display: block; width: 100%; height: auto; border-radius: var(--r-sm); border: 1px solid var(--hairline); }
@media (min-width: 820px) { .about-grid { grid-template-columns: 1fr 1fr; gap: var(--sp-10); align-items: center; } }
.trust-grid { display: grid; gap: var(--sp-4); margin-top: var(--sp-6); }
@media (min-width: 820px) { .trust-grid { grid-template-columns: 1fr 1fr; gap: var(--sp-6); } }
.manager-grid { display: grid; gap: var(--sp-6); }
.manager-photo { max-width: 220px; }
.manager-photo img { display: block; width: 100%; height: auto; border-radius: var(--r-sm); border: 1px solid var(--hairline); }
.manager-bio p + p { margin-top: var(--sp-3); }
@media (min-width: 820px) {
  .manager-grid { grid-template-columns: 220px 1fr; gap: var(--sp-10); align-items: start; }
}

/* The footer repeats hours and contact. Where the Visit section already
   carries them, the footer copy is redundant — collapse it there.
   Sibling selectors don't reach: .visit sits inside <main> while the
   footer is main's sibling, so this keys off the document instead. */
body:has(.visit) .site-footer .info-grid { display: none; }
body:has(.visit) .site-footer { margin-top: 0; padding-block: var(--sp-6); }

/* ═══════════════════════════════════════════════════════
   SHARED HEADER — banner on every page + mobile drawer
═══════════════════════════════════════════════════════ */
.site-header {
  position: sticky; top: 0; z-index: 60;
  background: rgba(0,0,0,0.82);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--hairline);
}
/* Rose-gold hairline under the header — the metal edge, full width. */
.site-header::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: var(--rose-sheen); opacity: 0.85;
}

.brandmark { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
/* Matt's actual badge, used unmodified.

   The badge's own circle is pure black — the same value as the page — so
   on this site its edge simply does not exist and it reads as white text
   floating in space. Rather than alter his artwork, the SITE supplies the
   contrast: a slightly raised plate behind it and a rose-gold hairline
   ring to define the edge. The logo itself is untouched. */
.brandmark-logo-wrap {
  flex: 0 0 auto;
  position: relative;
  width: 52px; height: 52px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: radial-gradient(circle at 50% 38%, #191A1D 0%, #0C0C0E 72%);
  box-shadow:
    0 0 0 1px var(--rose-hair),
    0 0 18px rgba(var(--rose-rgb), 0.16),
    inset 0 1px 0 rgba(255,255,255,0.05);
}
@media (min-width: 560px) { .brandmark-logo-wrap { width: 60px; height: 60px; } }

.brandmark-logo {
  width: 88%; height: 88%;
  object-fit: contain;
  display: block;
}

.brandmark-text { display: flex; flex-direction: column; min-width: 0; }
.brandmark-name {
  font-family: var(--font-display);
  font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.01em;
  line-height: 1.1; white-space: nowrap;
}
.brandmark-sub {
  font-family: var(--font-mono);
  font-size: var(--text-xs); letter-spacing: var(--tracking-wider);
  text-transform: uppercase; color: var(--rose); opacity: 0.85;
}
@media (min-width: 560px) { .brandmark-name { font-size: 1.05rem; } }

/* Desktop nav */
.nav-desktop { display: none; }
.nav-desktop ul { display: flex; gap: var(--sp-6); list-style: none; }
.nav-desktop a {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--bone-muted); padding-block: var(--sp-2);
  border-bottom: 1px solid transparent;
  transition: color var(--dur-fast), border-color var(--dur-fast);
}
/* The underline indicator has to stay tight to the text, so the hit area is
   extended with a transparent overlay instead of padding. 44px tall, nothing
   moves, and tablets at this breakpoint are still touch devices. */
.nav-desktop a { position: relative; }
.nav-desktop a::after {
  content: ''; position: absolute; left: 0; right: 0;
  top: 50%; transform: translateY(-50%); height: 44px;
}
.nav-desktop a:hover { color: var(--bone); border-bottom-color: var(--rose); }
.nav-desktop a[aria-current="page"] { color: var(--bone); border-bottom-color: var(--rose); }
@media (min-width: 820px) { .nav-desktop { display: block; } }

/* Mobile toggle */
.nav-toggle {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  background: transparent; border: 1px solid var(--rose-hair);
  border-radius: 999px; color: var(--bone);
  padding: var(--sp-2) var(--sp-4); min-height: 44px; min-width: 44px; justify-content: center;
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  cursor: pointer; flex: 0 0 auto;
  transition: border-color var(--dur-fast), background var(--dur-fast);
}
.nav-toggle:hover { border-color: var(--rose); background: var(--rose-soft); }
.nav-toggle-bars { display: grid; gap: 4px; }
.nav-toggle-bars i { display: block; width: 16px; height: 1.5px; background: var(--rose-bright); }
@media (min-width: 820px) { .nav-toggle { display: none; } }

/* Drawer */
.nav-drawer { border-top: 1px solid var(--hairline); background: rgba(0,0,0,0.96); }
.nav-drawer[hidden] { display: none; }
.nav-drawer nav ul { list-style: none; }
.nav-drawer a {
  display: block; padding: var(--sp-4) var(--sp-5);
  font-family: var(--font-display); font-size: var(--text-xl);
  text-transform: uppercase; letter-spacing: -0.01em;
  border-bottom: 1px solid var(--hairline);
}
.nav-drawer a:active { background: var(--rose-soft); }
.nav-drawer-foot {
  display: flex; flex-wrap: wrap; gap: var(--sp-4);
  padding: var(--sp-5);
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); color: var(--rose);
}
body.nav-open { overflow: hidden; }

/* ═══════════════════════════════════════════════════════
   ROSE GOLD THROUGHOUT
═══════════════════════════════════════════════════════ */
/* Eyebrows pick up the metal */
.eyebrow, .card-role, .roster-count { color: var(--rose); opacity: 0.9; }

/* Card edge lights up on hover — the metal frame */
.card { border-color: var(--hairline); }
.card:hover { border-color: var(--rose-hair); box-shadow: 0 0 0 1px var(--rose-soft), 0 18px 40px rgba(0,0,0,0.55); }
/* Thin rose rule between the photo and the name */
.card-media::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--rose-sheen); opacity: 0.7;
}
.stars { color: var(--rose-bright); }

/* Section headings get a short rose rule above them */
.roster-head, .visit .eyebrow { position: relative; }
.roster-head::before {
  content: ''; position: absolute; top: -14px; left: 0;
  width: 54px; height: 1px; background: var(--rose-sheen);
}

/* Buttons: ghost buttons use the metal edge */
.btn--ghost { border-color: var(--rose-hair); color: var(--bone); }
.btn--ghost:hover { border-color: var(--rose); background: var(--rose-soft); }
.btn:not(.btn--ghost) { box-shadow: 0 0 0 1px rgba(var(--rose-rgb), 0.0); }

/* Link rows on artist pages */
.linkrow a { border-bottom-color: var(--hairline); }
.linkrow a:hover { border-bottom-color: var(--rose-hair); }
.linkrow .lbl { color: var(--rose); opacity: 0.8; }

/* Hours divider + footer edge */
.hours td { border-bottom-color: var(--hairline); }
.site-footer { border-top-color: transparent; position: relative; }
.site-footer::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: var(--rose-sheen); opacity: 0.6;
}
.contact-list a:hover { color: var(--rose-bright); }
:focus-visible { outline-color: var(--rose-bright); }

/* Splitter: the CTA underline is already side-tinted; give the barber
   side the metal and the tattoo side bone, so they read as siblings. */
.panel[data-side="barber"] .panel-cta { border-bottom-color: var(--rose); }
.splitter-foot { color: var(--rose); opacity: 0.75; }

/* ═══════════════════════════════════════════════════════
   HERO MOTION
   Slow, weighted movement only — this is a gallery, not a carousel.
   All of it is decorative and sits behind prefers-reduced-motion.
═══════════════════════════════════════════════════════ */

/* 1. The room breathes: a very slow push-in on the hero photograph. */
@keyframes heroDrift {
  from { transform: scale(1.06) translate3d(0, 0, 0); }
  to   { transform: scale(1.14) translate3d(0, -1.2%, 0); }
}
.hero-img {
  will-change: transform;
  animation: heroDrift 26s var(--ease-in-out) infinite alternate;
}

/* 2. A rose-gold sheen crosses the hero, like light moving across the gloss
      floor they actually have.

      Reworked 2026-07-19. It used to sit at 16% opacity in a narrow 16%-wide
      band, on an 11s cycle that was fully transparent for the first 62% of
      it — so the sweep was invisible for about seven seconds out of every
      eleven, and faint for the rest. On a phone in daylight that read as
      nothing at all.

      Now: wider band, a brighter core so it catches the eye mid-sweep,
      7.5s, and visible across nearly the whole cycle so it reads as a
      constant shimmer rather than one event you happen to catch. */
.hero::after {
  content: '';
  position: absolute; inset: -20% -60%;
  z-index: -1;
  pointer-events: none;
  /* Strengths dialled back a step on 2026-07-19: at 0.34 with a 0.20 core
     it read as a wash over the photograph rather than a glint across it.
     Pace unchanged — that part was right. */
  background: linear-gradient(115deg,
    rgba(var(--rose-rgb), 0)    30%,
    rgba(var(--rose-rgb), 0.13) 43%,
    rgba(var(--rose-bright-rgb), 0.22) 48%,
    rgba(255,231,214,0.13) 50%,   /* bright core — the glint */
    rgba(var(--rose-bright-rgb), 0.22) 52%,
    rgba(var(--rose-rgb), 0.13) 57%,
    rgba(var(--rose-rgb), 0)    70%);
  transform: translateX(-55%);
  animation: heroSheen 7.5s linear infinite;
}
@keyframes heroSheen {
  0%   { transform: translateX(-55%); opacity: 0; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { transform: translateX(55%); opacity: 0; }
}
/* Phone screens are smaller and usually brighter, and the sweep crosses a
   narrower area — so it gets a touch more strength, not less. */
@media (max-width: 700px) {
  .hero::after { animation-duration: 6.5s; filter: brightness(1.25); }
}

/* 3. Splitter panels drift too, each at its own pace so the two halves
      never feel mechanically synced. */
.panel[data-side="tattoo"] .panel-img { animation: heroDrift 30s var(--ease-in-out) infinite alternate; }
.panel[data-side="barber"] .panel-img { animation: heroDrift 34s var(--ease-in-out) infinite alternate reverse; }

/* 3b. The same sheen crosses the splitter panels. The home page had no
       shimmer at all — only the hairline on the seam — and on a phone the
       splitter IS the first screen, which is exactly where Brian could not
       see the effect. Sits at z-index -1 like the scrim; because ::after
       comes after ::before it paints over the scrim but still under the
       panel text.
       The two panels run at different speeds and offsets so the sweeps
       cross independently rather than moving as one bar. */
.panel::after {
  content: '';
  position: absolute; inset: -20% -60%;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(115deg,
    rgba(var(--rose-rgb), 0)    30%,
    rgba(var(--rose-rgb), 0.12) 43%,
    rgba(var(--rose-bright-rgb), 0.20) 48%,
    rgba(255,231,214,0.12) 50%,
    rgba(var(--rose-bright-rgb), 0.20) 52%,
    rgba(var(--rose-rgb), 0.12) 57%,
    rgba(var(--rose-rgb), 0)    70%);
  transform: translateX(-55%);
  animation: heroSheen 8s linear infinite;
}
.panel[data-side="barber"]::after { animation-duration: 9.5s; animation-delay: -3.5s; }
@media (max-width: 700px) {
  .panel::after { filter: brightness(1.25); }
}

/* 4. A hairline of metal travels the splitter seam. */
.panels { position: relative; }
.panels::after {
  content: ''; position: absolute; z-index: 3; pointer-events: none;
  left: 0; right: 0; top: 50%; height: 1px; transform: translateY(-50%);
  background: var(--rose-sheen); opacity: 0.5;
  animation: seamPulse 7s ease-in-out infinite;
}
@keyframes seamPulse { 0%,100% { opacity: 0.22; } 50% { opacity: 0.7; } }
@media (min-width: 900px) {
  .panels::after { top: 0; bottom: 0; left: 50%; right: auto; width: 1px; height: auto;
    transform: translateX(-50%); background: linear-gradient(180deg,
      rgba(var(--rose-rgb), 0) 0%, rgba(var(--rose-bright-rgb), 0.85) 45%, rgba(var(--rose-deep-rgb), 0.85) 62%, rgba(var(--rose-rgb), 0) 100%);
    transition: left var(--dur-slow) var(--ease-out); }
  /* The seam rides the real join. On hover one panel grows to 1.35 of the
     other (see .panel:hover above), so the join sits at 1.35/2.35 or 1/2.35
     of the width — not the middle. Same easing as the panels themselves. */
  .panels:has(.panel:first-child:hover)::after { left: calc(100% * 1.35 / 2.35); }
  .panels:has(.panel:last-child:hover)::after  { left: calc(100% * 1 / 2.35); }
}

@media (prefers-reduced-motion: reduce) {
  .hero-img, .panel-img, .hero::after, .panel::after, .panels::after { animation: none !important; }
  /* The sheen is parked off-screen when it is not animating, otherwise it
     freezes as a static rose band across the middle of the photograph. */
  .hero::after, .panel::after { opacity: 0 !important; }
  .hero-img, .panel-img { transform: scale(1.02); }
}

/* ── Header layout corrections ──
   "BLVCK ROSE COLLECTIVE" set in a black grotesque is wide; at 375px it
   ran straight under the Menu button. The brand block now shrinks and
   truncates instead of pushing, and the toggle never yields space. */
.header-inner { gap: var(--sp-3); }
.brandmark { flex: 1 1 auto; min-width: 0; overflow: hidden; }
.brandmark-text { min-width: 0; }
.brandmark-name {
  font-size: 0.78rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: block; max-width: 100%;
}
@media (min-width: 420px) { .brandmark-name { font-size: 0.9rem; } }
@media (min-width: 560px) { .brandmark-name { font-size: 1.05rem; } }
.nav-toggle { flex: 0 0 auto; }
/* On the narrowest screens the word "Menu" is redundant next to the bars. */
@media (max-width: 380px) {
  .nav-toggle-label { display: none; }
  .nav-toggle { padding-inline: var(--sp-3); }
}

/* Drawer footer links are metadata, not navigation — they were
   inheriting the big display treatment from the menu items. */
.nav-drawer-foot a {
  display: inline-block;
  padding: 0;
  border-bottom: 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: none;
  color: var(--rose);
}
.nav-drawer-foot a:hover { color: var(--rose-bright); }

/* ═══════════════════════════════════════════════════════
   FEED — latest work from the collective
═══════════════════════════════════════════════════════ */
.feed { border-top: 1px solid var(--hairline); }
.feed-head {
  display: flex; flex-direction: column; gap: var(--sp-5);
  margin-bottom: var(--sp-6);
}
@media (min-width: 780px) {
  .feed-head { flex-direction: row; align-items: flex-end; justify-content: space-between; }
}
.feed-title { font-size: var(--text-2xl); margin-top: var(--sp-3); max-width: 16ch; }
.feed-body  { font-size: var(--text-sm); max-width: 46ch; margin-top: var(--sp-3); }

/* Square tiles, mirroring an Instagram grid without looking like one. */
.feed-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-2);
}
@media (min-width: 620px) { .feed-grid { grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); } }
/* Three across, not four. With six tiles, four columns left an orphan row
   of two; three gives two full rows and bigger photographs — which is the
   point of a section called "Come see the room". */
@media (min-width: 1000px) { .feed-grid { grid-template-columns: repeat(3, 1fr); } }

.feed-tile {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--ink-raised);
  border-radius: var(--r-sm);
  isolation: isolate;
}
.feed-tile img {
  width: 100%; height: 100%; object-fit: cover;
  /* Same grade as the artist cards, so the whole site reads as one set.
     Colour returns on hover — the work is the reward. */
  filter: grayscale(1) contrast(1.06) brightness(0.88);
  transform: scale(1.02);
  transition: filter var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}
.feed-tile:hover img { filter: grayscale(0) contrast(1) brightness(1); transform: scale(1.07); }

/* Rose-gold edge that draws on hover — the metal frame again. */
.feed-tile-edge {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  transition: border-color var(--dur-mid) var(--ease-out),
              box-shadow var(--dur-mid) var(--ease-out);
}
.feed-tile:hover .feed-tile-edge {
  border-color: var(--rose-hair);
  box-shadow: inset 0 0 22px rgba(var(--rose-rgb), 0.16);
}

/* ═══════════════════════════════════════════════════════
   REELS — video portfolio grid + lightbox
═══════════════════════════════════════════════════════ */
.reels { border-top: 1px solid var(--hairline); }
.reels-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-2);
}
@media (min-width: 620px)  { .reels-grid { grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); } }
@media (min-width: 1000px) { .reels-grid { grid-template-columns: repeat(4, 1fr); } }

.reel {
  position: relative;
  display: block; padding: 0;
  aspect-ratio: 9 / 16;           /* reels are vertical */
  border: 0; border-radius: var(--r-sm);
  overflow: hidden; cursor: pointer;
  background: var(--ink-raised);
  isolation: isolate;
}
.reel-video {
  width: 100%; height: 100%; object-fit: cover; display: block;
  filter: grayscale(1) contrast(1.06) brightness(0.88);
  transform: scale(1.02);
  transition: filter var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}
.reel:hover .reel-video,
.reel:focus-visible .reel-video { filter: none; transform: scale(1.06); }

.reel-edge {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  border: 1px solid transparent; border-radius: var(--r-sm);
  transition: border-color var(--dur-mid), box-shadow var(--dur-mid);
}
.reel:hover .reel-edge,
.reel:focus-visible .reel-edge {
  border-color: var(--rose-hair);
  box-shadow: inset 0 0 22px rgba(var(--rose-rgb), 0.18);
}

/* Play affordance — needed on touch, where there is no hover to hint with. */
.reel-play {
  position: absolute; z-index: 3; right: var(--sp-3); bottom: var(--sp-3);
  width: 26px; height: 26px; border-radius: 50%;
  background: rgba(0,0,0,0.55);
  border: 1px solid var(--rose-hair);
  backdrop-filter: blur(4px);
  transition: opacity var(--dur-fast);
}
.reel-play::after {
  content: ''; position: absolute; left: 9px; top: 7px;
  border-left: 8px solid var(--rose-bright);
  border-top: 6px solid transparent; border-bottom: 6px solid transparent;
}
.reel:hover .reel-play { opacity: 0; }

/* ── Lightbox ── */
.lightbox { position: fixed; inset: 0; z-index: 200; display: grid; place-items: center; }
.lightbox[hidden] { display: none; }
.lightbox-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,0.92); backdrop-filter: blur(6px); }
.lightbox-inner {
  position: relative; z-index: 1;
  width: min(94vw, 460px);
  display: grid; justify-items: center; gap: var(--sp-3);
}
.lightbox-video {
  width: 100%; max-height: 78svh;
  aspect-ratio: 9 / 16; object-fit: contain;
  background: #000;
  border: 1px solid var(--rose-hair);
  border-radius: var(--r-md);
  box-shadow: 0 30px 90px rgba(0,0,0,0.7), 0 0 0 1px var(--rose-soft);
}
.lightbox-cap {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); color: var(--bone-muted);
  text-align: center; max-width: 40ch;
}
.lightbox-close {
  position: absolute; top: -46px; right: 0; z-index: 2;
  width: 40px; height: 40px; line-height: 1;
  font-size: 1.6rem; color: var(--bone);
  background: transparent; border: 1px solid var(--rose-hair);
  border-radius: 999px; cursor: pointer;
}
.lightbox-close:hover { background: var(--rose-soft); border-color: var(--rose); }
.lightbox-nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 44px; height: 44px; font-size: 1.7rem; line-height: 1;
  color: var(--bone); background: rgba(0,0,0,0.5);
  border: 1px solid var(--rose-hair); border-radius: 999px; cursor: pointer;
}
.lightbox-nav:hover { background: var(--rose-soft); border-color: var(--rose); }
.lightbox-prev { left: -22px; }
.lightbox-next { right: -22px; }
@media (max-width: 560px) {
  .lightbox-prev { left: 2px; } .lightbox-next { right: 2px; }
  .lightbox-close { top: -44px; }
}

/* ═══════════════════════════════════════════════════════
   PORTFOLIO — an artist's selected work
═══════════════════════════════════════════════════════ */
.work { border-top: 1px solid var(--hairline); }
.work-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-2);
}
@media (min-width: 620px)  { .work-grid { grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); } }

.work-tile {
  position: relative; display: block; padding: 0;
  aspect-ratio: 1 / 1;
  border: 0; border-radius: var(--r-sm);
  overflow: hidden; cursor: zoom-in;
  background: var(--ink-raised);
  isolation: isolate;
}
.work-tile img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* Matt's work is already black and grey, so it needs almost no grading —
     just a touch down so the rose gold edge reads on hover. */
  filter: brightness(0.92) contrast(1.04);
  transform: scale(1.02);
  transition: filter var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}
.work-tile:hover img,
.work-tile:focus-visible img { filter: none; transform: scale(1.07); }

.work-edge {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border: 1px solid transparent; border-radius: var(--r-sm);
  transition: border-color var(--dur-mid), box-shadow var(--dur-mid);
}
.work-tile:hover .work-edge,
.work-tile:focus-visible .work-edge {
  border-color: var(--rose-hair);
  box-shadow: inset 0 0 22px rgba(var(--rose-rgb), 0.18);
}

/* Wider lightbox for stills — tattoo work is not 9:16. */
.lightbox-inner--wide { width: min(94vw, 900px); }
.lightbox-img {
  width: 100%; max-height: 78svh; object-fit: contain;
  background: #000;
  border: 1px solid var(--rose-hair);
  border-radius: var(--r-md);
  box-shadow: 0 30px 90px rgba(0,0,0,0.7), 0 0 0 1px var(--rose-soft);
}

/* ═══════════════════════════════════════════════════════
   INTRO — the mark BUILDS, peaks, then clears

   The first version faded out while shrinking, so the logo was at its
   weakest at the end. It should be the opposite: the glyph resolves out
   of blur, the rose draws in from the top, everything sharpens and
   brightens to a peak, holds a beat, and only then clears away.
═══════════════════════════════════════════════════════ */
body.intro-running { overflow: hidden; }

.intro {
  position: fixed; inset: 0; z-index: 300;
  display: grid; place-items: center;
  background: #000;
  animation: introClear var(--intro-dur) var(--ease-out) forwards;
}
:root { --intro-dur: 2400ms; }

/* The stage holds black until the peak has landed, then lifts. */
@keyframes introClear {
  0%, 78%  { opacity: 1; }
  100%     { opacity: 0; }
}

.intro-stage { display: grid; justify-items: center; gap: var(--sp-5); }

.intro-mark {
  position: relative;
  width: min(46vw, 200px);
  aspect-ratio: 575 / 900;
}
.intro-mark img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;
}

/* Letterform: resolves out of blur, dim to bright. Peaks at 72%. */
.intro-glyph {
  animation: introGlyph var(--intro-dur) var(--ease-out) forwards;
}
@keyframes introGlyph {
  0%   { opacity: 0;    filter: blur(10px) brightness(0.35); transform: scale(1.05); }
  30%  { opacity: 0.85; filter: blur(4px)  brightness(0.6);  transform: scale(1.02); }
  60%  { opacity: 1;    filter: blur(0)    brightness(0.95); transform: scale(1); }
  72%  { opacity: 1;    filter: blur(0)    brightness(1.25); }  /* the pop */
  86%  { opacity: 1;    filter: blur(0)    brightness(1.1); }
  100% { opacity: 0;    filter: blur(0)    brightness(1.1); }
}

/* Rose: wiped in from the top so the stem appears to draw downward,
   then a brief bloom at the same moment the glyph pops. */
.intro-rose {
  clip-path: inset(0 0 100% 0);
  animation: introRose var(--intro-dur) var(--ease-out) forwards;
}
@keyframes introRose {
  0%   { clip-path: inset(0 0 100% 0); opacity: 0; }
  22%  { clip-path: inset(0 0 100% 0); opacity: 1; }
  62%  { clip-path: inset(0 0 0 0);    opacity: 1; }
  72%  { clip-path: inset(0 0 0 0);    opacity: 1; }
  100% { clip-path: inset(0 0 0 0);    opacity: 0; }
}

/* A rose-gold bloom behind the mark, brightest at the pop. */
.intro-mark::after {
  content: ''; position: absolute; inset: -30%; z-index: -1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--rose-rgb), 0.30) 0%, rgba(var(--rose-rgb), 0) 68%);
  opacity: 0;
  animation: introBloom var(--intro-dur) var(--ease-out) forwards;
}
@keyframes introBloom {
  0%,40% { opacity: 0; transform: scale(0.85); }
  72%    { opacity: 1; transform: scale(1.05); }
  100%   { opacity: 0; transform: scale(1.12); }
}

/* Their actual wordmark artwork, knocked out to bone. Replaces the typed
   approximation — the lockup, spacing and rule are theirs, not mine. */
.intro-word {
  width: min(62vw, 260px);
  height: auto;
  opacity: 0;
  animation: introWord var(--intro-dur) var(--ease-out) forwards;
}
@keyframes introWord {
  0%,52% { opacity: 0; transform: translateY(8px); }
  72%    { opacity: 1; transform: none; }
  86%    { opacity: 1; }
  100%   { opacity: 0; }
}

.intro-skip {
  position: absolute; bottom: var(--sp-6); right: var(--sp-6);
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--bone-muted);
  background: transparent; border: 1px solid var(--hairline-bright);
  border-radius: 999px; padding: var(--sp-2) var(--sp-4);
  min-height: 40px; cursor: pointer;
}
.intro-skip:hover { color: var(--bone); border-color: var(--rose); }

.intro.intro-out { animation: none; opacity: 0; pointer-events: none;
  transition: opacity 320ms var(--ease-out); }
.intro.intro-out * { animation-play-state: paused; }

@media (prefers-reduced-motion: reduce) { .intro { display: none; } }

/* ═══════════════════════════════════════════════════════
   REVIEWS
═══════════════════════════════════════════════════════ */
.reviews { border-top: 1px solid var(--hairline); }
.reviews-grid {
  display: grid; gap: var(--sp-4);
  grid-template-columns: 1fr;
}
@media (min-width: 720px)  { .reviews-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .reviews-grid { grid-template-columns: repeat(3, 1fr); } }

.review {
  margin: 0;
  padding: var(--sp-5);
  background: var(--ink-raised);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  display: flex; flex-direction: column; gap: var(--sp-3);
  transition: border-color var(--dur-mid);
}
.review:hover { border-color: var(--rose-hair); }
.review-stars { color: var(--rose-bright); letter-spacing: 0.14em; font-size: var(--text-sm); }
.review-quote {
  margin: 0;
  font-size: var(--text-sm);
  line-height: 1.7;
  color: var(--bone);
}
.review-quote::before { content: '\201C'; }
.review-quote::after  { content: '\201D'; }
.review-by {
  display: flex; align-items: baseline; gap: var(--sp-2) var(--sp-3);
  /* Wraps because Google bylines carry three parts, not two, and a client
     name plus an artist credit runs past a phone's width on one line. */
  flex-wrap: wrap;
  margin-top: auto;
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
}
.review-staff { color: var(--rose); text-transform: uppercase; }
.review-date  { color: var(--bone-faint); }
/* Lower-case and quiet: it is a credit, not the byline. */
.review-artist { color: var(--bone-muted); text-transform: none; letter-spacing: 0.02em; }

/* Google reviews run several times longer than the Vagaro one-liners, so the
   cards align to the top of each row instead of stretching to match the
   tallest. */
.reviews-grid { align-items: start; }

/* ═══════════════════════════════════════════════════════
   SERVICES — the barber menu
═══════════════════════════════════════════════════════ */
.services { border-top: 1px solid var(--hairline); }
.svc-grid { display: grid; gap: var(--sp-8); }
@media (min-width: 820px)  { .svc-grid { grid-template-columns: repeat(3, 1fr); gap: var(--sp-6); } }

/* The pricing disclosure, cut as a hang tag: the one price tag on the menu,
   and it names the barber instead of a number (the shop's call, 2026-09-24 —
   each barber sets their own rates). Rose gold stays an edge, never a fill
   (tokens.css): the rose background shows only as the 1px rim around the ink
   lining in ::after. clip-path makes the tag its own stacking context, so the
   z-index:-1 lining paints over that background and under the text. */
.svc-tag {
  position: relative;
  margin-top: var(--sp-5);
  padding: var(--sp-3) var(--sp-4) var(--sp-3) calc(var(--sp-6) + var(--sp-2));
  color: var(--rose-bright);
  background: var(--rose);
  clip-path: polygon(var(--sp-5) 0, 100% 0, 100% 100%, var(--sp-5) 100%, 0 50%);
}
.svc-tag::after {
  content: '';
  position: absolute; inset: 1px; z-index: -1;
  background: var(--ink);
  clip-path: inherit;
}
/* The eyelet. */
.svc-tag::before {
  content: '';
  position: absolute; left: var(--sp-4); top: 50%;
  width: 8px; height: 8px; margin: -4px 0 0 -4px;
  border: 1px solid var(--rose);
  border-radius: 50%;
}

.svc-group-label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--rose);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--hairline);
  margin-bottom: var(--sp-4);
}
/* Group-level disclosure — sits under the rule, above the list, because a
   caveat printed after the list is a caveat nobody reads in time.
   Rose (7.1:1 on ink), the same metal as the pricing tag, so the two read as
   one disclosure. Never --bone-faint: this is information someone needs to
   act on, so it does not get the small-print treatment. */
.svc-group-note {
  font-size: var(--text-xs);
  line-height: 1.6;
  color: var(--rose);
  margin: calc(var(--sp-2) * -1) 0 var(--sp-5);
  max-width: 42ch;
}

/* The whole-menu disclosure, under the grid. Given a top rule and real
   breathing room so it reads as a statement about everything above it rather
   than a stray line belonging to the last column. */
.svc-footnote {
  margin-top: var(--sp-8);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--hairline);
  font-size: var(--text-xs);
  line-height: 1.75;
  color: var(--bone-muted);
  max-width: 52ch;
}

/* The rose-gold asterisk. Sized up and pulled down from true superscript —
   at natural <sup> size against Archivo Black it reads as a speck of dust
   rather than a deliberate mark. */
.svc-star {
  color: var(--rose);
  font-family: var(--font-body);
  font-size: 0.5em;
  font-weight: 500;
  vertical-align: super;
  line-height: 0;
  margin-left: 0.12em;
}

.svc-list { display: flex; flex-direction: column; gap: var(--sp-3); list-style: none; counter-reset: svc; }
/* Hairline between services: a printed menu card, not a bare list. */
.svc { counter-increment: svc; }
.svc + .svc { padding-top: var(--sp-3); border-top: 1px solid var(--hairline); }

/* Name and price on one line with a leader between — a menu, not a table.
   The price (and its leader) only renders when the config has one. */
.svc-head { display: flex; align-items: baseline; gap: var(--sp-3); }
/* The rose figures that used to close each line (the prices, retired
   2026-09-24) now open it: a running number per group, so the list keeps its
   rhythm. Decorative: the "/ ''" alt text keeps screen readers off it, and the
   first declaration is the fallback where that syntax is not supported. */
.svc-head::before {
  content: counter(svc, decimal-leading-zero);
  content: counter(svc, decimal-leading-zero) / '';
  flex: 0 0 1.5rem;
  font-family: var(--font-mono); font-size: var(--text-xs);
  color: var(--rose);
}
.svc-name { font-size: var(--text-base); color: var(--bone); }
.svc-note {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); color: var(--bone-faint);
}
.svc-dots {
  flex: 1 1 auto;
  border-bottom: 1px dotted var(--hairline-bright);
  transform: translateY(-3px);
  min-width: var(--sp-4);
}
.svc-price {
  font-family: var(--font-mono); font-size: var(--text-sm);
  color: var(--rose-bright); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.svc-desc {
  margin: 6px 0 0 calc(1.5rem + var(--sp-3));   /* under the name, not the number */
  font-size: var(--text-xs);
  line-height: 1.65;
  color: var(--bone-muted);
  max-width: 44ch;
}

/* ═══════════════════════════════════════════════════════
   AMENITIES — the experience
═══════════════════════════════════════════════════════ */
.amenities { border-top: 1px solid var(--hairline); }
.amenity-grid {
  display: grid; gap: var(--sp-4);
  grid-template-columns: 1fr;
}
@media (min-width: 620px)  { .amenity-grid { grid-template-columns: repeat(2, 1fr); gap: var(--sp-5); } }
@media (min-width: 1000px) { .amenity-grid { grid-template-columns: repeat(4, 1fr); } }

.amenity { display: flex; align-items: flex-start; gap: var(--sp-3); }
.amenity-dot {
  flex: 0 0 auto;
  width: 7px; height: 7px; margin-top: 8px;
  border-radius: 50%;
  background: var(--rose);
  box-shadow: 0 0 10px var(--rose-glow);
}
.amenity-text { display: flex; flex-direction: column; gap: 2px; }
.amenity-label { font-size: var(--text-sm); color: var(--bone); }
.amenity-note {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); color: var(--bone-faint);
}

/* Cancellation policy — set quietly, but present. */
.policy {
  margin-top: var(--sp-8);
  padding: var(--sp-5);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  background: var(--ink-raised);
  position: relative; overflow: hidden;
}
.policy::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--rose-sheen);
}
.policy-heading {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider); text-transform: uppercase;
  color: var(--rose); margin-bottom: var(--sp-3);
}
.policy-body {
  font-size: var(--text-xs); line-height: 1.75;
  color: var(--bone-muted); max-width: 52ch;
}

/* ═══════════════════════════════════════════════════════
   NEWS & EVENTS
   The one section the shop updates itself, so it has to look
   right with one entry or with eight.
═══════════════════════════════════════════════════════ */
.events { border-top: 1px solid var(--hairline); }
.ev-list { list-style: none; margin: var(--sp-8) 0 0; padding: 0; display: grid; gap: var(--sp-4); }

.ev {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-5);
  align-items: start;
  padding: var(--sp-5);
  background: var(--ink-raised);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  position: relative; overflow: hidden;
}
.ev::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--rose-sheen);
}
/* A closure is the one entry that costs someone a wasted journey, so it
   is the one that looks different. The distinction moved from the left rail
   to the top rule; it still reads, and it is no longer a generic card tab. */
.ev--closure::before { background: linear-gradient(90deg,
    rgba(var(--rose-bright-rgb), 0) 0%, var(--rose-bright) 40%, var(--rose-bright) 70%, rgba(var(--rose-bright-rgb), 0) 100%); }
.ev--news::before    { background: linear-gradient(90deg,
    rgba(46,46,51,0) 0%, var(--hairline-bright) 45%, rgba(46,46,51,0) 100%); }

.ev-date {
  text-align: center;
  min-width: 3.4rem;
  padding-top: 2px;
}
.ev-d {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  line-height: 1;
  color: var(--bone);
}
.ev-m {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  color: var(--rose);
  margin-top: 4px;
}

.ev-body { min-width: 0; }
.ev-kind {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--bone-faint);
  margin-bottom: var(--sp-2);
}
.ev--closure .ev-kind { color: var(--rose-bright); }
.ev-title { font-size: var(--text-lg); margin: 0 0 var(--sp-1); }
.ev-when  { font-family: var(--font-mono); font-size: var(--text-xs);
            color: var(--bone-muted); margin: 0; }
.ev-span  { font-family: var(--font-mono); font-size: var(--text-xs);
            color: var(--bone-faint); }
.ev-text  { font-size: var(--text-sm); line-height: 1.65;
            color: var(--bone-muted); margin: var(--sp-3) 0 0; max-width: 62ch; }
.ev-where { font-family: var(--font-mono); font-size: var(--text-xs);
            letter-spacing: var(--tracking-wide); color: var(--bone-faint);
            margin: var(--sp-2) 0 0; }

/* ═══════════════════════════════════════════════════════
   CONTACT
═══════════════════════════════════════════════════════ */
.route-grid {
  display: grid; gap: var(--sp-4);
  grid-template-columns: 1fr;
  margin-top: var(--sp-8);
}
@media (min-width: 700px) { .route-grid { grid-template-columns: repeat(2, 1fr); } }

.route {
  padding: var(--sp-5);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  background: var(--ink-raised);
  display: flex; flex-direction: column; gap: var(--sp-3);
  align-items: flex-start;
  position: relative; overflow: hidden;
}
.route::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--rose-sheen);
}
.route-label {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--rose);
}
.route-body { font-size: var(--text-sm); line-height: 1.6; color: var(--bone-muted); }
.route .btn { margin-top: auto; }

.contact-panel { margin-top: var(--sp-10); }
/* The "everything else" note sat in the full 1132px column at 89 characters
   per line. The form beneath it is the constrained thing; its introduction
   should match. */
.contact-panel > p.muted { max-width: 60ch; }
.contact-form-heading { font-size: var(--text-2xl); margin-bottom: var(--sp-2); }
.contact-form { margin-top: var(--sp-6); max-width: 46rem; }

.field { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-5); }
.field label {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--bone-muted);
}
.field-hint { color: var(--bone-faint); text-transform: none; letter-spacing: 0.02em; }

.field input, .field select, .field textarea {
  width: 100%;
  /* Grid and flex children default to min-width:auto, which lets a wide
     input push the whole column past the viewport. Same trap that silently
     cut off the Orvannis contact form on every phone. */
  min-width: 0;
  padding: var(--sp-3) var(--sp-4);
  background: var(--ink-raised);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  color: var(--bone);
  font-family: var(--font-body);
  /* 16px minimum: anything smaller makes iOS Safari zoom the page on focus
     and the visitor has to pinch back out. */
  font-size: 1rem;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.field textarea { resize: vertical; line-height: 1.6; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--rose);
}
.field select { appearance: none; cursor: pointer; }

.form-error {
  margin-bottom: var(--sp-4);
  font-size: var(--text-sm);
  color: var(--rose-bright);
}

.contact-success {
  margin-top: var(--sp-10);
  padding: var(--sp-6);
  border: 1px solid var(--rose-hair);
  border-radius: var(--r-sm);
  background: var(--ink-raised);
}
.contact-success h2 { font-size: var(--text-2xl); margin-bottom: var(--sp-3); }
.contact-success p { color: var(--bone-muted); line-height: 1.7; max-width: 60ch; }

.contact-footnote {
  margin-top: var(--sp-8);
  font-size: var(--text-xs); line-height: 1.75;
  color: var(--bone-faint); max-width: 52ch;
}

/* Score block — shown when a side has a rating but no quotes pulled yet.
   Deliberately built to look finished rather than pending: a rating and a
   count is a real trust signal, not a placeholder for one. */
.review-score {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-5);
  padding: var(--sp-6);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  background: var(--ink-raised);
  position: relative; overflow: hidden;
}
.review-score::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--rose-sheen);
}
.score-value {
  font-family: var(--font-display);
  font-size: var(--text-4xl);
  line-height: 1;
  color: var(--bone);
}
.score-stars { font-size: var(--text-xl); color: var(--rose); letter-spacing: 0.1em; }
.score-count {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); color: var(--bone-faint);
}
/* Link variant — same block, now tappable through to the live listing. */
a.review-score--link { text-decoration: none; transition: border-color var(--dur-fast) var(--ease-out); }
a.review-score--link:hover,
a.review-score--link:focus-visible { border-color: var(--rose); }
.score-go {
  flex-basis: 100%;
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); color: var(--rose);
}

/* The storefront, sitting with the address. Left in colour — the rest of
   the interface is monochrome, but this one is doing a job: it has to match
   what the visitor sees from the road. */
.visit-map {
  display: block;
  width: 100%;
  height: 300px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  margin-top: var(--sp-6);
}
.visit-photo {
  display: block;
  width: 100%;
  /* No aspect-ratio and no cover. The image is already composed — wordmark,
     sign, storefront, truck, stacked — so any fixed ratio crops one end off.
     A 4/3 slot ate the wordmark. Let it size to its own proportions. */
  height: auto;
  border-radius: var(--r-sm);
  border: 1px solid var(--hairline);
  margin-bottom: var(--sp-6);
}

/* ═══════════════════════════════════════════════════════
   AFTERCARE — tattoo side only
   Read on a phone, one-handed, probably at night. So: one
   column always, big touch-free spacing, numbers that stay
   findable when you scroll back to check where you were.
═══════════════════════════════════════════════════════ */
.aftercare { border-top: 1px solid var(--hairline); }
.care-list {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--sp-5);
  max-width: 62ch;
}
@media (min-width: 900px) {
  .care-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--sp-8);
    max-width: none;
  }
}

.care { display: flex; align-items: flex-start; gap: var(--sp-4); }
.care-num {
  flex: 0 0 auto;
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  color: var(--rose);
  padding-top: 3px;
  /* Fixed width so the labels align down the column regardless of digit. */
  width: 2.1em;
}
/* min-width:0 or a long unbroken note stretches the grid column past the
   viewport — the same trap that cut off the Orvannis contact form. */
.care-text { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.care-label {
  font-size: var(--text-base); line-height: 1.4; color: var(--bone);
}
.care-note {
  font-size: var(--text-sm); line-height: 1.65; color: var(--bone-muted);
}

.care-variant { margin-top: var(--sp-8); }
.care-footnote {
  margin-top: var(--sp-5);
  font-size: var(--text-xs); line-height: 1.75;
  color: var(--bone-faint); max-width: 52ch;
}

/* Bio block on the artist page — first used by Derek Nordgren, 2026-08-05 */
.artist-bio{max-width:38rem;margin:1.1rem 0 0}
.artist-bio p{margin:0 0 .8em;line-height:1.65;font-size:.97rem;opacity:.92}

/* Before-you-book FAQ on the artist page — Matt's seven, 2026-09-24.
   Native <details>. No numbers; the rose plus sits on the left and loses its
   upright stroke (turns into a minus) when the answer opens. */
.faq-list { max-width: 46rem; border-top: 1px solid var(--hairline); }
.faq-item { border-bottom: 1px solid var(--hairline); }
.faq-q {
  display: flex; align-items: center; gap: var(--sp-3);
  min-height: 3.25rem; padding: var(--sp-3) 0;
  list-style: none; cursor: pointer;
  font-size: var(--text-base); line-height: 1.4; color: var(--bone);
}
.faq-q::-webkit-details-marker { display: none; }
.faq-q::before {
  content: '';
  flex: 0 0 0.875rem; height: 0.875rem;
  background: linear-gradient(var(--rose), var(--rose)) center / 100% 1.5px no-repeat,
              linear-gradient(var(--rose), var(--rose)) center / 1.5px 100% no-repeat;
  transition: background-size 0.2s ease;
}
.faq-item[open] > .faq-q::before { background-size: 100% 1.5px, 1.5px 0; }
@media (hover: hover) { .faq-q:hover { color: var(--rose-bright); } }
.faq-q:focus-visible { outline: 2px solid var(--rose); outline-offset: 4px; }
.faq-a {
  padding: 0 0 var(--sp-5) calc(0.875rem + var(--sp-3));
  font-size: var(--text-sm); line-height: 1.7; color: var(--bone-muted);
  max-width: 62ch;
}
.faq-a p, .faq-a ul { margin: 0 0 var(--sp-3); }
.faq-a > :last-child { margin-bottom: 0; }
.faq-a ul { list-style: disc; padding-left: 1.1em; }
.faq-a li::marker { color: var(--rose); }
@media (prefers-reduced-motion: reduce) { .faq-q::before { transition: none; } }
/* The FAQ sits in the bio's place; the rose-gold FAQs button swaps them. */
.artist-faq { margin-top: var(--sp-6); }
.artist-faq .faq-list { margin-top: var(--sp-5); }
.btn--rose { border-color: var(--rose); color: var(--rose); cursor: pointer; }
