/* ==========================================================================
   The Barber Parlor - vintage barbershop single page
   Palette (4 core): barber red, cream, navy, brass. Sharp edges throughout.
   ========================================================================== */

:root {
  /* Palette as raw channels. Every solid colour and every transparency below
     derives from these ten lines, so rebranding is an edit here rather than a
     hunt through thirty hand-mixed rgba() values. */
  --red-rgb: 143 31 43;
  --red-dark-rgb: 112 23 34;
  --cream-rgb: 245 235 218;
  --cream-bright-rgb: 251 244 230;
  --navy-rgb: 20 38 58;
  --navy-deep-rgb: 13 26 41;
  --brass-rgb: 201 164 92;
  --ink-rgb: 29 44 63;
  --muted-rgb: 68 83 106;

  --red: rgb(var(--red-rgb));
  --red-dark: rgb(var(--red-dark-rgb));
  --cream: rgb(var(--cream-rgb));
  --cream-bright: rgb(var(--cream-bright-rgb));
  --navy: rgb(var(--navy-rgb));
  --navy-deep: rgb(var(--navy-deep-rgb));
  --brass: rgb(var(--brass-rgb));
  --ink: rgb(var(--ink-rgb));
  --muted: rgb(var(--muted-rgb));
  --cream-muted: rgb(var(--cream-rgb) / 0.78);

  /* Control surfaces. The invalid tint is an error signal, not a brand colour,
     so it stays put when the palette above is swapped. */
  --surface: #fff;
  --surface-invalid: #fdf3f0;
  --font-hero: 'RoyalKing', 'Georgia', serif;
  --font-display: 'BlueSpirits', 'Georgia', serif;
  --font-body: 'Archivo', 'Segoe UI', 'Helvetica Neue', sans-serif;

  /* Two type ramps.

     The display ramp is fluid and every step stays at least 1.25x from its
     neighbour at every viewport. That gap is the point: the hero and the
     section titles used to land 1.02x apart on a phone (33.6px against
     32.8px), so the most important line on the page did not lead.

     The text ramp is fixed, because body copy that resizes with the viewport
     buys nothing and costs predictability. Five steps, one per role. Before
     this there were twenty-two sizes, five of them inside 0.06rem of each
     other and all doing the same job. */
  --display-hero: clamp(2.25rem, 7.2vw, 4.5rem);
  --display-xl: clamp(1.75rem, 4.3vw, 3.1rem);
  --display-lg: clamp(1.5rem, 3.4vw, 2rem);
  --display-md: 1.5rem;
  --display-sm: clamp(1.0625rem, 2.8vw, 1.1875rem);

  --text-lead: 1.125rem;
  --text-body: 1rem;
  --text-meta: 0.875rem;
  --text-label: 0.75rem;
  /* Badges only. Anything that reads as a label, even a short one, takes the
     step above: at badge size a two-word service name starts wrapping around
     its own tag. */
  --text-micro: 0.625rem;

  /* Four tracking values, down from eleven. Capitals need opening up; the
     wide one is the shop's voice and is spent on exactly two elements. */
  --track-brand: 0.32em;
  --track-label: 0.18em;
  --track-caps: 0.14em;
  --track-btn: 0.1em;

  /* Light type on a dark ground reads a weight lighter than it is. The dark
     sections get the looser of these two. */
  --leading-body: 1.65;
  --leading-body-dark: 1.72;

  --header-h: 76px;

  --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ---------- Display faces ---------- */

/* Two display faces, self-hosted, both rebuilt from the supplied desktop files
   and shipped as woff2 (hinting dropped, kerning and layout features kept).

   Royal King draws the hero headline and nothing else. It sets all-caps
   cleanly, which is what that one line needs. Note its free build replaces
   every digit, the ampersand and both quote marks with a placeholder box, so
   it must never be pointed at anything but plain-letter headline text.

   Blue Spirits draws every other display element. Its swashes tangle when set
   all-caps and tight, so those elements run title case - see the rules further
   down. Neither face carries a peso sign; prices are set in the body face. */
@font-face {
  font-family: 'RoyalKing';
  src: url('fonts/royalking.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'BlueSpirits';
  src: url('fonts/bluespirits.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---------- Reset & base ---------- */

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

/* Form controls do not inherit type. Without this the two icon-only buttons
   sit on the UA's 13.33px, which is not a step on any scale here, and the
   moment either grows a text label it renders off-ramp. */
button,
input,
select,
textarea {
  font-family: inherit;
  font-size: inherit;
}

html {
  scroll-behavior: smooth;
}

/* Reduced motion means gentler, not none. Every keyframe on this page is
   movement - the spinning stamp, the sliding steps, the drawn tick - so those
   go. Colour and opacity transitions stay: killing them would hard-cut the
   dialog in over a full-strength scrim, which is worse than the fade it
   replaces. Delays go with the durations, or the staggered cards would still
   be timed out, just invisibly. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0s !important;
    scroll-behavior: auto !important;
  }

  /* The dialog keeps its fade and loses its 14px travel. The !important also
     outranks the @starting-style value further down, so there is no start
     position left to travel from. */
  .modal,
  .modal[open] {
    translate: none !important;
  }

  .js .reveal {
    opacity: 1;
    transform: none;
  }
}

body {
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  color: var(--ink);
  background: var(--cream);
  -webkit-font-smoothing: antialiased;
  font-kerning: normal;
}

/* Light-on-dark compensation, applied where the ground actually is dark
   rather than element by element. */
.section-dark,
.hero,
.site-footer {
  line-height: var(--leading-body-dark);
}

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

h1, h2, h3 {
  text-wrap: balance;
}

p {
  text-wrap: pretty;
}

a {
  color: inherit;
}

ul {
  list-style: none;
}

.container {
  width: min(1140px, 92%);
  margin-inline: auto;
}

section {
  scroll-margin-top: calc(var(--header-h) + 12px);
}

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

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

.skip-link {
  position: absolute;
  top: -60px;
  left: 1rem;
  z-index: 100;
  padding: 0.75rem 1.25rem;
  background: var(--red);
  color: var(--cream);
  font-weight: 600;
  text-decoration: none;
  /* No transition. This is keyboard-initiated and `top` is a layout property:
     someone tabbing for the skip link wants it there, not sliding in. */
}

.skip-link:focus {
  top: 1rem;
}

/* ---------- Shared bits ---------- */

.stripe {
  height: 10px;
  background: repeating-linear-gradient(
    -45deg,
    var(--red) 0 16px,
    var(--cream) 16px 26px,
    var(--navy) 26px 42px,
    var(--cream) 42px 52px
  );
}

/* Used once on the page, above one section. A kicker over every heading is
   template grammar; a single one is a place to put the voice. */
.eyebrow {
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: var(--track-brand);
  text-transform: uppercase;
}

.eyebrow-brass { color: var(--brass); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 48px;
  padding: 0.9rem 1.9rem;
  border: 2px solid transparent;
  font-family: var(--font-body);
  font-size: var(--text-meta);
  font-weight: 700;
  letter-spacing: var(--track-btn);
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  /* Press tracks under 80ms so the button feels connected to the finger. */
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease,
    transform 0.07s ease;
}

.btn-primary {
  background: var(--red);
  border-color: var(--red);
  color: var(--cream);
}

.btn-primary:hover {
  background: var(--red-dark);
  border-color: var(--red-dark);
}

.btn-ghost {
  background: transparent;
  border-color: var(--cream);
  color: var(--cream);
}

.btn-ghost:hover {
  background: rgb(var(--cream-rgb) / 0.14);
}

.btn-outline-navy {
  background: transparent;
  border-color: var(--navy);
  color: var(--navy);
}

.btn-outline-navy:hover {
  background: var(--navy);
  color: var(--cream);
}

/* Press feedback. A shift rather than a scale: the page is built from
   sharp-edged physical objects, and a button that depresses suits them. */
.btn:active,
.svc-book:active,
.barber-book:active,
.choice:active,
.slot:not(:disabled):active,
.modal-close:active,
.nav-toggle:active {
  transform: translateY(1px);
}

.btn-sm {
  min-height: 44px;
  padding: 0.6rem 1.3rem;
  font-size: var(--text-label);
}

.btn-block {
  width: 100%;
}

/* ---------- Header ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--navy);
  border-bottom: 2px solid var(--brass);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 2rem;
  min-height: var(--header-h);
  padding-block: 0.5rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.8rem;
  color: var(--cream);
  text-decoration: none;
}

.brand-badge {
  width: 46px;
  height: 46px;
  color: var(--brass);
  flex-shrink: 0;
}

.brand-text {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
}

/* Sized off the viewport rather than fixed: a display face wider than the
   original slab pushed this onto a second line at 375px and grew the header
   from 76px to 88px. The nowrap is the guard against it happening silently
   again the next time the face changes. */
.brand-name {
  font-family: var(--font-display);
  font-size: clamp(0.95rem, 4.3vw, 1.1875rem);
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.brand-sub {
  font-size: var(--text-micro);
  font-weight: 600;
  letter-spacing: var(--track-brand);
  text-transform: uppercase;
  color: var(--brass);
}

.site-nav {
  margin-left: auto;
}

.site-nav ul {
  display: flex;
  align-items: center;
  gap: 1.75rem;
}

.site-nav a:not(.btn) {
  font-size: var(--text-meta);
  font-weight: 600;
  letter-spacing: var(--track-btn);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--cream);
  padding: 0.5rem 0;
  border-bottom: 2px solid transparent;
  transition: color 0.2s ease, border-color 0.2s ease;
}

.site-nav a:not(.btn):hover {
  color: var(--brass);
  border-bottom-color: var(--brass);
}

.nav-toggle {
  display: none;
  margin-left: auto;
  width: 48px;
  height: 48px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  background: transparent;
  border: 2px solid var(--brass);
  cursor: pointer;
}

.nav-toggle:hover {
  background: rgb(var(--brass-rgb) / 0.16);
}

/* The panel below snaps open, so the icon snaps with it. A 200ms morph on the
   bars while the menu they open appears instantly reads as a dropped frame. */
.nav-toggle-bar {
  width: 22px;
  height: 2px;
  background: var(--cream);
}

.nav-open .nav-toggle-bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-open .nav-toggle-bar:nth-child(2) {
  opacity: 0;
}

.nav-open .nav-toggle-bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  display: flex;
  align-items: center;
  /* svh so a phone measures the visible viewport rather than the area behind
     the browser chrome; the vh line above it is the fallback. */
  min-height: min(92vh, 62rem);
  min-height: min(92svh, 62rem);
  background: var(--navy-deep);
  overflow: hidden;
}

.hero-bg {
  position: absolute;
  inset: 0;
  /* Plain url() first as the fallback; browsers without image-set() keep it. */
  background: url('images/hero-960w.jpg') center / cover no-repeat;
  background-image: image-set(
    url('images/hero-960w.webp') type('image/webp'),
    url('images/hero-960w.jpg') type('image/jpeg')
  );
}

@media (min-width: 800px) {
  .hero-bg {
    background-image: url('images/hero-1920w.jpg');
    background-image: image-set(
      url('images/hero-1920w.webp') type('image/webp'),
      url('images/hero-1920w.jpg') type('image/jpeg')
    );
  }
}

.hero-overlay {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(100deg, rgb(var(--navy-deep-rgb) / 0.93) 0%, rgb(var(--navy-deep-rgb) / 0.78) 42%, rgb(var(--navy-deep-rgb) / 0.28) 100%),
    linear-gradient(to top, rgb(var(--navy-deep-rgb) / 0.65) 0%, rgb(var(--navy-deep-rgb) / 0) 30%);
}

.hero-content {
  position: relative;
  z-index: 1;
  /* Fluid so a landscape phone is not mostly padding. */
  padding-block: clamp(2.5rem, 10vh, 7rem);
  max-width: 1140px;
}

.hero-content > * {
  max-width: 620px;
}

/* The one element on the page in Royal King, and the one that stays all-caps:
   the face sets caps cleanly, and this line is plain letters and a period, so
   it never touches the placeholder glyphs in the free build. */
.hero-title {
  font-family: var(--font-hero);
  font-weight: 400;
  /* Two constraints the body copy does not share: the display size needs room
     for "Sit down ordinary." to hold one line, which 620px never allowed past
     ~1000px, and the size has to track the container below ~800px, where a
     fixed floor overflowed a phone by up to 98px. */
  max-width: 57.5rem;
  font-size: var(--display-hero);
  line-height: 1.04;
  text-transform: uppercase;
  color: var(--cream);
}

.hero-title .accent {
  color: var(--brass);
}

.hero-sub {
  margin-top: 1.4rem;
  font-size: var(--text-lead);
  line-height: var(--leading-body-dark);
  color: var(--cream-muted);
  max-width: 54ch;
}

.hero-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: 2.2rem;
}

.hero-note {
  margin-top: 1.6rem;
  font-size: var(--text-meta);
  font-weight: 500;
  letter-spacing: 0.06em;
  color: rgb(var(--cream-rgb) / 0.62);
}

.hero-stamp {
  position: absolute;
  right: 7%;
  top: 50%;
  transform: translateY(-50%);
  width: 168px;
  height: 168px;
  color: var(--brass);
  z-index: 1;
  overflow: visible;
}

.hero-stamp textPath {
  fill: var(--cream);
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 600;
  /* 0.13em, not the 0.24em this used to carry. At 0.24em the string set 462
     units around a 402-unit circle, lapped its own start and rendered as
     "MAKATI CITTHE BARBER PARLOR". The textLength on the element is the real
     guarantee, but Safari and Firefox honour textLength on a textPath
     inconsistently, so the natural length has to fit on its own too. This
     value measures ~399, just inside the circle, and textLength nudges it the
     last 3 units in engines that do support it. */
  letter-spacing: 0.13em;
}

.stamp-ring {
  transform-origin: 80px 80px;
  animation: stamp-spin 48s linear infinite;
}

@keyframes stamp-spin {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .stamp-ring {
    animation: none;
  }
}

.stamp-est,
.stamp-year {
  fill: var(--brass);
  font-family: var(--font-display);
}

.stamp-est { font-size: 15px; }
.stamp-year { font-size: 26px; }

/* The headline box is 920px at full size; below this the stamp crowds it.
   Measured, not guessed: at 1241px the two were 3px apart. */
@media (max-width: 1320px) {
  .hero-stamp {
    display: none;
  }
}

/* A landscape phone has width to spare and no height at all. Sized off the
   viewport width alone, the headline pushed Book Your Chair below the fold. */
@media (max-height: 520px) {
  .hero-content {
    padding-block: 2.25rem;
  }

  .hero-title {
    font-size: clamp(1.9rem, 4.6vw, 3rem);
  }

  .hero-sub {
    margin-top: 1rem;
    font-size: var(--text-body);
  }

  .hero-ctas {
    margin-top: 1.4rem;
  }
}

/* ---------- Sections ---------- */

.section {
  padding-block: 5.5rem;
}

.section-dark {
  background: var(--navy);
  color: var(--cream);
}

.section-red {
  background: var(--red);
  color: var(--cream);
}

.section-head {
  text-align: center;
  max-width: 640px;
  margin: 0 auto 3.25rem;
}

/* The section kicker survives in one place only, so its spacing is scoped to
   that pairing rather than baked into every heading. */
.eyebrow + .section-title {
  margin-top: 0.9rem;
}

/* Title case, not caps. Blue Spirits' swashes collide between lines when it is
   set all-caps and tight - "Meet Your Barbers" ran into the line above it, and
   "Classic Hot Towel Shave" closed up into one word. The copy is authored in
   title case already, so this is the natural setting for the face. */
.section-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-xl);
  line-height: 1.12;
  color: var(--navy);
}

.section-dark .section-title,
.section-red .section-title {
  color: var(--cream);
}

.section-sub {
  margin-top: 1.1rem;
  font-size: var(--text-body);
  color: var(--muted);
}

.section-dark .section-sub {
  color: var(--cream-muted);
}

.ornament {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.9rem;
  margin-top: 1.2rem;
  color: var(--red);
}

.ornament-brass { color: var(--brass); }
.ornament-cream { color: var(--cream); }

.orn-line {
  width: 64px;
  height: 2px;
  background: currentColor;
}

.orn-icon {
  width: 22px;
  height: 22px;
}

/* ---------- Services ---------- */

.menu-board {
  background: var(--cream-bright);
  border: 3px solid var(--navy);
  outline: 1px solid var(--navy);
  outline-offset: 6px;
  padding: clamp(1.75rem, 4vw, 3.25rem);
}

.menu-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 3.5rem;
  row-gap: 2.2rem;
}

.svc-head {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
}

.svc-head h3 {
  font-family: var(--font-display);
  font-weight: 400;
  /* Holds the old size where the row is narrow, takes the larger step only once
     there is room for the name, the leader and the price on one line. */
  font-size: var(--display-sm);
  letter-spacing: 0.02em;
  color: var(--navy);
}

.dots {
  flex: 1;
  min-width: 24px;
  border-bottom: 3px dotted var(--brass);
  transform: translateY(-5px);
}

/* Body face, not display: Bridgnorth has no peso sign, so a display price
   renders its digits in one face and its currency mark in another, mid-word. */
.price {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--text-lead);
  letter-spacing: 0.01em;
  /* Lining tabular figures so the price column reads as a column: the digits
     sit on the same rhythm down the menu instead of drifting. */
  font-variant-numeric: tabular-nums;
  color: var(--red);
  white-space: nowrap;
}

.svc p {
  margin-top: 0.5rem;
  font-size: var(--text-body);
  color: var(--muted);
  max-width: 48ch;
}

.tag {
  display: inline-block;
  vertical-align: 3px;
  margin-left: 0.4rem;
  padding: 0.28rem 0.5rem;
  background: var(--red);
  color: var(--cream);
  font-family: var(--font-body);
  font-size: var(--text-micro);
  font-weight: 700;
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
}

/* ---------- Barbers ---------- */

.barber-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2rem;
}

.barber-photo {
  position: relative;
  border: 2px solid var(--brass);
  outline: 1px solid var(--brass);
  outline-offset: 5px;
  aspect-ratio: 3 / 4;
  background: var(--navy-deep);
}

.barber-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.yrs {
  position: absolute;
  left: -2px;
  bottom: -2px;
  padding: 0.45rem 0.7rem;
  background: var(--red);
  color: var(--cream);
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
}

.barber-name {
  margin-top: 1.4rem;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-md);
  line-height: 1.25;
  color: var(--cream);
}

.barber-role {
  margin-top: 0.3rem;
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--brass);
}

.barber-bio {
  margin-top: 0.7rem;
  font-size: var(--text-body);
  color: var(--cream-muted);
}

/* Placeholder block used only if an AI image slot failed to generate */
.img-fallback {
  aspect-ratio: 3 / 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1.25rem;
  text-align: center;
  background: repeating-linear-gradient(-45deg, rgb(var(--cream-rgb) / 0.05) 0 14px, transparent 14px 28px), var(--navy-deep);
  border: 2px dashed var(--brass);
  color: var(--cream-muted);
  font-size: var(--text-label);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ---------- Booking ---------- */

.booking-layout {
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: 4rem;
  align-items: start;
}


.booking-lead {
  margin-top: 1.2rem;
  font-size: var(--text-lead);
  color: var(--muted);
  max-width: 46ch;
}

.assurance {
  margin-top: 1.8rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.assurance li {
  display: flex;
  align-items: flex-start;
  gap: 0.8rem;
  font-weight: 500;
}

.assurance svg {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--red);
}

.booking-walkin {
  margin-top: 1.8rem;
  padding: 1rem 1.2rem;
  border: 2px solid var(--brass);
  background: var(--cream-bright);
  font-size: var(--text-body);
  color: var(--muted);
}

.book-card {
  background: var(--cream-bright);
  border: 3px solid var(--navy);
  outline: 1px solid var(--navy);
  outline-offset: 6px;
  padding: clamp(1.75rem, 3.5vw, 2.75rem);
}

.book-card-kicker {
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--red);
}

.book-steps {
  margin: 1.4rem 0 1.9rem;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  counter-reset: bookstep;
}

.book-steps li {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  font-weight: 500;
  color: var(--muted);
}

.book-step-n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  background: var(--navy);
  color: var(--cream);
  font-family: var(--font-display);
  font-size: var(--text-meta);
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-bottom: 1.1rem;
}

.field label {
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--navy);
}

.field input {
  width: 100%;
  min-height: 48px;
  padding: 0.7rem 0.9rem;
  border: 2px solid var(--navy);
  background: var(--surface);
  font-family: var(--font-body);
  font-size: var(--text-body);
  color: var(--ink);
  border-radius: 0;
}

.field input:focus {
  outline: 3px solid var(--brass);
  outline-offset: 1px;
}

.field.invalid input {
  border-color: var(--red);
  background: var(--surface-invalid);
}

.err {
  display: none;
  font-size: var(--text-meta);
  font-weight: 600;
  color: var(--red);
}

.field.invalid .err {
  display: block;
}

.form-micro {
  margin-top: 0.9rem;
  text-align: center;
  font-size: var(--text-meta);
  color: var(--muted);
}

[hidden] {
  display: none !important;
}

/* Success state */

.modal-success {
  display: none;
  text-align: center;
  padding: clamp(1.75rem, 4vw, 2.75rem);
  /* A single unbroken 100-character name must wrap, not widen the dialog. */
  overflow-wrap: break-word;
}

.modal-success.show {
  display: block;
  animation: success-in 0.35s var(--ease-out-quint);
}

@keyframes success-in {
  from { opacity: 0; transform: translateY(10px); }
}

.success-icon {
  width: 60px;
  height: 60px;
  margin: 0 auto 1.2rem;
  color: var(--brass);
}

/* The one celebration on the page: the ring closes, then the tick is drawn.
   Everything before this is feedback; this is the payoff. */
.modal-success.show .success-icon circle {
  stroke-dasharray: 183;
  stroke-dashoffset: 183;
  animation: draw-stroke 0.55s var(--ease-out-quint) forwards;
}

.modal-success.show .success-icon path {
  stroke-dasharray: 40;
  stroke-dashoffset: 40;
  animation: draw-stroke 0.3s var(--ease-out-quint) 0.32s forwards;
}

@keyframes draw-stroke {
  to { stroke-dashoffset: 0; }
}

.modal-success h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-md);
  color: var(--navy);
}

.success-lead {
  margin-top: 0.6rem;
  font-size: var(--text-body);
  color: var(--muted);
}

.success-summary {
  margin: 1.5rem 0;
  border: 2px solid var(--brass);
  padding: 1.2rem 1.4rem;
  text-align: left;
}

.success-summary > div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.45rem 0;
  border-bottom: 1px dotted var(--brass);
}

.success-summary > div:last-child {
  border-bottom: none;
}

.success-summary dt {
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--muted);
}

/* The confirmation is read as a column of values, so the figures in it (price,
   date, time, duration) line up rather than wander. */
.success-summary dd {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--navy);
  text-align: right;
}

.success-note {
  margin-bottom: 1.5rem;
  font-size: var(--text-meta);
  color: var(--muted);
}

/* ---------- Reviews ---------- */

.review-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.75rem;
}

.review {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  background: var(--cream);
  border: 2px solid var(--navy);
  padding: 1.6rem;
  color: var(--ink);
}

.demo-chip {
  align-self: flex-start;
  padding: 0.3rem 0.55rem;
  background: var(--navy);
  color: var(--cream);
  font-size: var(--text-micro);
  font-weight: 600;
  letter-spacing: var(--track-btn);
  text-transform: uppercase;
}

.stars {
  display: flex;
  gap: 0.25rem;
}

.stars svg {
  width: 17px;
  height: 17px;
  fill: var(--brass);
}

.review blockquote {
  font-size: var(--text-body);
  line-height: var(--leading-body);
  max-width: 60ch;
  color: var(--ink);
}

.review-author {
  margin-top: auto;
  font-size: var(--text-meta);
  color: var(--muted);
}

.review-author strong {
  color: var(--navy);
}

/* ---------- Visit ---------- */

.visit-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4rem;
  align-items: stretch;
}

.visit-info {
  display: flex;
  flex-direction: column;
  gap: 1.9rem;
}

.visit-block h3 {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-body);
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--brass);
  margin-bottom: 0.55rem;
}

.visit-block h3 svg {
  width: 19px;
  height: 19px;
}

.visit-block p {
  color: var(--cream-muted);
}

.visit-block a {
  color: var(--cream);
  font-weight: 600;
  text-decoration-color: var(--brass);
  text-underline-offset: 3px;
}

.visit-block a:hover {
  color: var(--brass);
}

.visit-muted {
  font-size: var(--text-meta);
  color: rgb(var(--cream-rgb) / 0.55);
}

.hours {
  max-width: 420px;
}

/* Opening hours are a table in disguise; tabular figures keep the times in a
   column so the eye can scan down the week. */
.hours li {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.4rem 0;
  font-variant-numeric: tabular-nums;
  color: var(--cream-muted);
}

.hours li span:last-child {
  white-space: nowrap;
}

.hours-dots {
  flex: 1;
  border-bottom: 2px dotted rgb(var(--brass-rgb) / 0.55);
  transform: translateY(-4px);
}

.socials {
  display: flex;
  gap: 0.8rem;
}

.social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border: 2px solid var(--brass);
  color: var(--cream);
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}

/* Gated: a tap on touch fires a hover that then sticks until the next tap. */
@media (hover: hover) and (pointer: fine) {
  .social:hover {
    background: var(--brass);
    color: var(--navy);
  }
}

.social svg {
  width: 20px;
  height: 20px;
  fill: currentColor;
}

.socials-note {
  margin-top: 0.7rem;
}

.map-ph {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.9rem;
  min-height: 400px;
  padding: 2.5rem;
  text-align: center;
  border: 2px solid var(--brass);
  outline: 1px solid var(--brass);
  outline-offset: 5px;
  background:
    linear-gradient(rgb(var(--brass-rgb) / 0.08) 1px, transparent 1px),
    linear-gradient(90deg, rgb(var(--brass-rgb) / 0.08) 1px, transparent 1px),
    var(--navy-deep);
  background-size: 34px 34px, 34px 34px, auto;
}

.map-pin {
  width: 46px;
  height: 46px;
  color: var(--red);
}

.map-title {
  font-family: var(--font-display);
  font-size: var(--display-sm);
  letter-spacing: 0.04em;
  color: var(--cream);
}

.map-sub {
  max-width: 34ch;
  font-size: var(--text-body);
  color: var(--cream-muted);
}

.map-addr {
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--brass);
}

/* ---------- Footer ---------- */

.site-footer {
  background: var(--navy-deep);
  color: var(--cream-muted);
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 3rem;
  padding-block: 3.5rem;
}

.footer-brand .brand {
  margin-bottom: 1rem;
}

.footer-blurb {
  max-width: 34ch;
  font-size: var(--text-body);
}

.site-footer h3 {
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--brass);
  margin-bottom: 0.9rem;
}

.footer-links ul,
.footer-hours ul {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}

.footer-links ul {
  gap: 0.1rem;
}

.footer-links a {
  /* Padded into a real tap target: the bare text ran 19px tall. */
  display: inline-block;
  padding-block: 0.35rem;
  text-decoration: none;
  color: var(--cream-muted);
  transition: color 0.2s ease;
}

.footer-links a:hover {
  color: var(--brass);
}

.footer-contact {
  margin-top: 1rem;
  font-size: var(--text-meta);
}

.footer-contact a {
  color: var(--cream);
  text-decoration-color: var(--brass);
  text-underline-offset: 3px;
}

.footer-contact a:hover {
  color: var(--brass);
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.5rem 2rem;
  padding-block: 1.4rem;
  border-top: 1px solid rgb(var(--cream-rgb) / 0.14);
  font-size: var(--text-meta);
}

/* ---------- Booking triggers on cards ---------- */

.svc-book {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-top: 0.7rem;
  padding: 0.3rem 0;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  font-family: var(--font-body);
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--red);
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease;
}

.svc-book svg {
  width: 15px;
  height: 15px;
}

.svc-book:hover {
  color: var(--red-dark);
  border-bottom-color: var(--red);
}

.barber-book {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  width: 100%;
  min-height: 44px;
  margin-top: 1rem;
  padding: 0.6rem 1rem;
  background: transparent;
  border: 2px solid var(--brass);
  font-family: var(--font-body);
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--cream);
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.barber-book svg {
  width: 15px;
  height: 15px;
}

.barber-book:hover {
  background: var(--brass);
  color: var(--navy);
}

/* ---------- Booking modal ---------- */

/* The scroll container is <html>, so the lock has to land there too - setting it
   on <body> alone leaves the page scrolling behind the open dialog. */
.modal-open {
  overflow: hidden;
}

.modal {
  width: min(760px, 94vw);
  max-height: min(88vh, 900px);
  /* Restores the centring the global `* { margin: 0 }` reset strips off <dialog>. */
  margin: auto;
  padding: 0;
  border: 3px solid var(--navy);
  background: var(--cream-bright);
  color: var(--ink);
  overflow: hidden;
}

/* The one signature entrance on the page. The dialog is the closing argument,
   so it arrives rather than appears. allow-discrete carries the exit too. */
.modal {
  opacity: 0;
  translate: 0 14px;
  transition:
    opacity 0.28s var(--ease-out-quint),
    translate 0.28s var(--ease-out-quint),
    overlay 0.28s allow-discrete,
    display 0.28s allow-discrete;
}

.modal[open] {
  display: flex;
  flex-direction: column;
  opacity: 1;
  translate: 0 0;
}

@starting-style {
  .modal[open] {
    opacity: 0;
    translate: 0 14px;
  }
}

.modal::backdrop {
  background: rgb(var(--navy-deep-rgb) / 0);
  transition:
    background 0.28s var(--ease-out-quint),
    overlay 0.28s allow-discrete,
    display 0.28s allow-discrete;
}

.modal[open]::backdrop {
  background: rgb(var(--navy-deep-rgb) / 0.72);
}

@starting-style {
  .modal[open]::backdrop {
    background: rgb(var(--navy-deep-rgb) / 0);
  }
}

.modal > .stripe {
  flex-shrink: 0;
  height: 8px;
}

.modal-close {
  position: absolute;
  top: 18px;
  right: 14px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  background: transparent;
  border: 2px solid transparent;
  color: var(--navy);
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.modal-close svg {
  width: 20px;
  height: 20px;
}

.modal-close:hover {
  background: var(--navy);
  color: var(--cream);
}

.modal form {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1;
}

.modal-head {
  flex-shrink: 0;
  padding: clamp(1.4rem, 3vw, 2rem) clamp(1.25rem, 3vw, 2.25rem) 0;
}

.modal-head h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-lg);
  line-height: 1.1;
  color: var(--navy);
}

.steps {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.4rem;
  margin-top: 1.1rem;
}

.steps li {
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  /* Pending steps still have to be legible: 0.42 measured 2.4:1. */
  color: rgb(var(--ink-rgb) / 0.7);
}

.steps li.done {
  color: var(--muted);
}

.steps li.on {
  color: var(--red);
}

.progress {
  height: 6px;
  margin-top: 0.7rem;
  background: rgb(var(--navy-rgb) / 0.14);
}

/* Revealed by clip-path rather than width: no layout on each step, and the
   barber-pole stripes keep their phase instead of re-tiling as the bar grows. */
.progress span {
  display: block;
  height: 100%;
  width: 100%;
  background: repeating-linear-gradient(
    -45deg,
    var(--red) 0 8px,
    var(--cream-bright) 8px 13px,
    var(--navy) 13px 21px,
    var(--cream-bright) 21px 26px
  );
  clip-path: inset(0 75% 0 0);
  /* Same curve as the step it advances with; on `ease` the two visibly
     disagreed over the 300ms they share. */
  transition: clip-path 0.3s var(--ease-out-quint);
}

.modal-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: clamp(1.25rem, 3vw, 1.9rem) clamp(1.25rem, 3vw, 2.25rem);
}

.step {
  display: none;
}

/* Steps travel: forward on the way in, back the other way, so the flow has a
   direction instead of snapping between four unrelated panels. */
.step.on {
  display: block;
  animation: step-in 0.3s var(--ease-out-quint);
}

.modal-body[data-dir="back"] .step.on {
  animation-name: step-back;
}

.modal-body[data-dir="none"] .step.on {
  animation: none;
}

@keyframes step-in {
  from { opacity: 0; transform: translateX(14px); }
}

@keyframes step-back {
  from { opacity: 0; transform: translateX(-14px); }
}

.step-hint {
  margin-bottom: 1.1rem;
  color: var(--muted);
}

.err.show {
  display: block;
  margin-top: 0.8rem;
}

/* Choice buttons */

.choice-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.8rem;
}

.choice-grid-barbers {
  grid-template-columns: 1fr;
}

.choice {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  width: 100%;
  min-height: 56px;
  padding: 0.85rem 1rem;
  background: var(--surface);
  border: 2px solid rgb(var(--navy-rgb) / 0.22);
  font-family: var(--font-body);
  text-align: left;
  color: var(--ink);
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

/* Gated: on touch the tapped choice keeps its hover background sitting next to
   the one that is actually selected, and the two become hard to tell apart. */
@media (hover: hover) and (pointer: fine) {
  .choice:hover {
    border-color: var(--navy);
    background: var(--cream);
  }
}

.choice.sel {
  border-color: var(--red);
  background: var(--cream);
  box-shadow: inset 0 0 0 2px var(--red);
}

.choice-name {
  display: block;
  font-weight: 700;
  line-height: 1.3;
  color: var(--navy);
}

.choice-meta {
  display: block;
  font-size: var(--text-meta);
  color: var(--muted);
}

.choice[data-service] {
  flex-wrap: wrap;
  gap: 0 0.6rem;
}

.choice[data-service] .choice-name {
  flex: 1 1 100%;
}

.choice[data-service] .choice-meta {
  flex: 1;
}

/* Same peso-sign reason as .price above. */
.choice-price {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--text-body);
  font-variant-numeric: tabular-nums;
  color: var(--red);
}

.choice-barber img,
.choice-any {
  width: 52px;
  height: 52px;
  flex-shrink: 0;
  object-fit: cover;
  border: 2px solid var(--brass);
}

.choice-any {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--navy);
  color: var(--brass);
}

.choice-any svg {
  width: 24px;
  height: 24px;
}

/* Date & slots */

.field-date {
  max-width: 260px;
}

.slots-label {
  margin-bottom: 0.7rem;
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--navy);
}

.slot-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 0.55rem;
}

.slot {
  min-height: 46px;
  padding: 0.6rem 0.4rem;
  background: var(--surface);
  border: 2px solid rgb(var(--navy-rgb) / 0.22);
  font-family: var(--font-body);
  font-size: var(--text-meta);
  font-weight: 600;
  /* Every slot is a time; equal-width figures stop the grid jittering as the
     hour rolls from 9:30 to 10:00. */
  font-variant-numeric: tabular-nums;
  color: var(--navy);
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease;
}

/* Gated for the same reason as the choices: a stuck hover on the time you just
   tapped competes with the red fill that marks it as chosen. */
@media (hover: hover) and (pointer: fine) {
  .slot:hover:not(:disabled) {
    border-color: var(--navy);
    background: var(--cream);
  }
}

/* No pop on selection. Picking a time is a compare-and-switch action - three or
   four taps in a row - and a keyframe restarts from zero on every one of them,
   dropping the previous slot's animation mid-flight. The solid red already says
   "this one" without any help. */
.slot.sel {
  background: var(--red);
  border-color: var(--red);
  color: var(--cream);
}

/* Booked slots are information, not decoration: which times are gone is
   half of what the grid says. Recede them by surface and rule, not by
   fading the text past legibility. */
.slot.is-taken {
  background: rgb(var(--navy-rgb) / 0.06);
  border-color: transparent;
  color: var(--muted);
  text-decoration: line-through;
  cursor: not-allowed;
}

.slot-empty {
  grid-column: 1 / -1;
  color: var(--muted);
}

/* Footer */

.modal-foot {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem clamp(1.25rem, 3vw, 2.25rem);
  border-top: 2px solid rgb(var(--navy-rgb) / 0.16);
  background: var(--cream);
}

.modal-foot .btn:last-child {
  margin-left: auto;
}

.run-summary {
  flex: 1;
  min-width: 0;
  font-size: var(--text-meta);
  font-weight: 600;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.success-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.8rem;
}

@media (max-width: 620px) {
  .modal {
    width: 100vw;
    max-width: 100vw;
    max-height: 100vh;
    height: 100vh;
    margin: 0;
    border-width: 0;
  }

  .choice-grid {
    grid-template-columns: 1fr;
  }

  .slot-grid {
    grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  }

  .modal-foot {
    flex-wrap: wrap;
  }

  .run-summary {
    order: -1;
    flex: 1 1 100%;
    white-space: normal;
  }

  .success-actions .btn {
    flex: 1 1 100%;
  }
}

/* ---------- Reveal on scroll ---------- */

/* Only the two card grids animate in, and only when scripting is running.
   Gating visibility on a class the observer may never add ships blank
   sections to headless renderers and to anyone whose JS fails. */
.js .reveal {
  opacity: 0;
  transform: translateY(14px);
}

.js .reveal.in {
  opacity: 1;
  transform: none;
  transition:
    opacity 0.5s var(--ease-out-quint) calc(var(--i, 0) * 70ms),
    transform 0.5s var(--ease-out-quint) calc(var(--i, 0) * 70ms);
}

/* ---------- Responsive ---------- */

@media (max-width: 1024px) {
  .barber-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 2.5rem 2rem;
  }

  .booking-layout,
  .visit-layout {
    grid-template-columns: 1fr;
    gap: 3rem;
  }

  .review-grid {
    grid-template-columns: 1fr;
    max-width: 620px;
    margin-inline: auto;
  }
}

@media (max-width: 900px) {
  .nav-toggle {
    display: flex;
  }

  .site-nav {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--navy-deep);
    border-bottom: 3px solid var(--brass);
    padding: 1.25rem 4%;
  }

  .nav-open .site-nav {
    display: block;
  }

  .site-nav ul {
    flex-direction: column;
    align-items: stretch;
    gap: 0.4rem;
  }

  .site-nav a:not(.btn) {
    display: block;
    padding: 0.8rem 0.4rem;
    border-bottom: 1px solid rgb(var(--cream-rgb) / 0.12);
  }

  .nav-cta {
    margin-top: 0.8rem;
  }

  .nav-cta .btn {
    width: 100%;
  }
}

@media (max-width: 800px) {
  .section {
    padding-block: 3.75rem;
  }

  .menu-grid {
    grid-template-columns: 1fr;
    row-gap: 1.9rem;
  }

  .hero-content {
    padding-block: 5.5rem;
  }
}

@media (max-width: 640px) {
  /* Too narrow for a dotted leader to read as one: a 24px stub beside a
     three-line name looks like a bug. Name left, price right, no rule. */
  .svc-head {
    align-items: flex-start;
    gap: 0.6rem;
  }

  .svc-head h3 {
    flex: 1;
  }

  .dots {
    display: none;
  }

  .barber-grid {
    grid-template-columns: 1fr;
    max-width: 380px;
    margin-inline: auto;
  }

  .footer-grid {
    grid-template-columns: 1fr;
    gap: 2.25rem;
  }

  .footer-bottom {
    flex-direction: column;
  }

  .hero-ctas .btn {
    flex: 1 1 100%;
  }
}
