/* ============================================================================
   Craft Collective Salon Group — shared theme + responsive layer
   ----------------------------------------------------------------------------
   Loaded from every page immediately after that page's inline <style>, so
   equal-specificity rules here win on document order. Selectors deliberately
   mirror the specificity the page styles already use; !important is reserved
   for the handful of places a page rule (or an inline style attribute) uses it
   first.

   THEME
     The original design ran dark panels edge to edge — near-black heroes,
     near-black about/locations/testimonial bands — with low-opacity off-white
     copy on top. It read as heavy and, at 0.4-0.5 alpha, several text roles
     fell under 3:1 against their own background. This layer inverts that:
     light paper surfaces carry the page, and the near-black is spent only on
     the nav, the footer and the occasional accent band. Gold stays, but gold
     used as *text* on a light surface moves to a deeper mix that clears AA.

   Breakpoints
     <=  400px   very small phones
     <=  480px   small phones (320-428 target range)
     <=  600px   phones
     <=  900px   tablets / collapsed nav
     >=  901px   desktop
     >= 1600px   wide desktop
   ========================================================================== */

/* ==========================================================================
   1. TOKENS
   ========================================================================== */

:root {
  /* Surfaces, light to dark. */
  --paper: #ffffff;
  --paper-warm: #fbf9f5;
  --off-white: #fbf9f5;
  --cream: #f4efe6;
  --cream-deep: #ece5d8;

  /* Ink. --black is left addressable because page CSS uses it for *text* on
     gold as often as for backgrounds; the background uses are re-pointed
     individually below rather than by redefining the token. */
  --black: #1A2440;
  --ink: #1A2440;
  --ink-2: #232E4D;
  --text: #232A3D;
  --mid: #565F75;
  --muted: #565F75;

  /* Brand gold, in two mixes.

     Page CSS reaches for var(--gold) far more often as a *text* color than
     as a fill — stylist roles, "Learn More" links, section labels, star rows —
     across selectors too varied to enumerate. At #b08d57 every one of those
     lands at 3.09:1 on white, under AA. So the token defaults to the
     text-safe mix, and the fills, which ARE a closed set (.nav-book,
     .btn-primary, .book-cta, .cta-section, .contact-strip, .location-cta,
     .about-image-badge, .filter-btn.active and the decorative ::before rules),
     opt back in via --gold-fill below. Getting it the other way round means
     every page rule the theme layer has not seen fails quietly. */
  --gold: #866336;        /* 5.5:1 on #fff, 4.7:1 on cream — text-safe */
  --gold-deep: #7a5b31;   /* headings and hovers that want more weight */
  --gold-fill: #b08d57;   /* the brand gold, for grounds and buttons */
  --gold-light: #d4b98a;  /* text mix for dark grounds only */
  --gold-wash: #f7f1e6;

  --rule: #e3e2e6;
  --rule-soft: #eeedf1;

  --shadow-sm: 0 1px 2px rgba(26, 36, 64, 0.04), 0 2px 8px rgba(26, 36, 64, 0.04);
  --shadow-md: 0 2px 4px rgba(26, 36, 64, 0.04), 0 8px 24px rgba(26, 36, 64, 0.07);
  --shadow-lg: 0 4px 8px rgba(26, 36, 64, 0.05), 0 18px 44px rgba(26, 36, 64, 0.10);

  --nav-h: 68px;
  --cta-bar-h: 0px;
}

/* ==========================================================================
   2. BASE
   ========================================================================== */

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: 88px; /* fixed nav + breathing room for #anchors */
}

body {
  background: var(--paper);
  color: var(--text);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Nothing may push the page sideways. */
img,
video,
iframe,
svg,
table {
  max-width: 100%;
}

img,
video {
  height: auto;
}

iframe,
.map-embed iframe {
  max-width: 100%;
  border: 0;
}

/* Grid and flex children default to min-width:auto, so one long address or
   phone number can force a track wider than its container. */
[class*='grid'] > *,
.about-body > *,
.about > *,
.hero > *,
.derek-hero > *,
.lead > *,
.location-detail > *,
.split-grid > *,
.hero-actions > *,
.cta-actions > * {
  min-width: 0;
}

/* Long unbroken strings (URLs, emails) are the usual 320px overflow culprit.

   `anywhere` rather than `break-word`: both add the same soft-wrap
   opportunities, but only `anywhere` feeds them into intrinsic sizing. That
   distinction is the whole bug — a bare phorest.com booking URL in the /about
   copy gave its paragraph a 340px min-content width, which forced the grid
   track wider than the 256px it had to fill and put the page into horizontal
   scroll at 320px. `break-word` alone left the track exactly as wide. */
p,
li,
td,
dd,
h1,
h2,
h3,
h4,
.prose,
.article-content,
.footer-contact,
.nap-box,
.info-value,
.map-address {
  overflow-wrap: anywhere;
  word-break: normal;
}

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

::selection {
  background: var(--gold-light);
  color: var(--ink);
}

/* Skip link — first tab stop, invisible until focused. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--ink);
  color: var(--paper-warm);
  padding: 0.85rem 1.4rem;
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
}

.skip-link:focus {
  left: 0;
}

/* ==========================================================================
   3. NAVIGATION — the dark bar is kept; it anchors the light page beneath it
   ========================================================================== */

.nav {
  background: rgba(26, 36, 64, 0.97);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(176, 141, 87, 0.28);
  box-shadow: 0 1px 24px rgba(26, 36, 64, 0.10);
}

.nav-logo,
.footer-brand-name {
  color: #fbf9f5;
}

.nav-logo span {
  color: var(--gold-light);
}

.nav-links a {
  color: rgba(251, 249, 245, 0.82);
}

.nav-links a:hover,
.nav-links a:focus {
  color: var(--gold-light);
}

/* Current section. The underline carries the state visually; aria-current
   carries it to assistive tech. */
.nav-links a[aria-current='page'] {
  color: var(--gold-light);
  position: relative;
}

.nav-links a[aria-current='page']:not(.nav-book)::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -6px;
  height: 1px;
  background: var(--gold-fill);
}

@media (max-width: 900px) {
  .nav-links a[aria-current='page'] {
    box-shadow: inset 3px 0 0 var(--gold-fill);
  }
  .nav-links a[aria-current='page']:not(.nav-book)::after { display: none; }
}

/* ------------------------------------------------- scroll reveal */

/* Sections lift in as they enter the viewport. Applied only once JS confirms
   support, so with JS off (or before it runs) nothing is ever left hidden —
   the class that hides them is added by script, not shipped in the markup. */
.js-reveal .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 0.7s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: opacity, transform;
}

.js-reveal .reveal.is-in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .js-reveal .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

.nav-book {
  background: var(--gold-fill);
  color: #1A2440 !important;
}

.nav-book:hover,
.nav-book:focus {
  background: var(--gold-light) !important;
  color: #1A2440 !important;
}

.nav-mobile-actions {
  display: none;
  align-items: center;
  gap: 0.5rem;
}

.nav-book-mobile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 1.1rem;
  background: var(--gold-fill);
  color: #1A2440;
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}

.nav-book-mobile:hover,
.nav-book-mobile:focus {
  background: var(--gold-light);
  color: #1A2440;
}

/* Hamburger — three bars, morphs to an X when open. */
.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  color: #fbf9f5;
}

.nav-toggle span {
  position: relative;
  display: block;
  width: 24px;
  height: 2px;
  background: currentColor;
  transition: background 0.2s ease;
}

.nav-toggle span::before,
.nav-toggle span::after {
  content: '';
  position: absolute;
  left: 0;
  width: 24px;
  height: 2px;
  background: currentColor;
  transition: transform 0.25s ease;
}

.nav-toggle span::before { transform: translateY(-8px); }
.nav-toggle span::after  { transform: translateY(8px); }

.nav-toggle[aria-expanded='true'] span { background: transparent; }
.nav-toggle[aria-expanded='true'] span::before { transform: rotate(45deg); }
.nav-toggle[aria-expanded='true'] span::after  { transform: rotate(-45deg); }

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

  /* Above .cta-bar (120), so the drawer is never clipped by the sticky
     booking bar — which it was in landscape, where the viewport is short
     enough that the drawer runs the full height of the screen. */
  .nav { z-index: 130; }

  .nav-inner {
    height: 64px;
    padding: 0 1rem;
    gap: 0.75rem;
  }

  /* The panel: full-width drawer under the bar, scrollable if it runs long.

     It stays laid out and is hidden with visibility/opacity rather than
     `display`, so opening and closing can animate. `visibility` is what keeps
     the closed drawer out of the tab order and off the accessibility tree —
     opacity alone would leave eight invisible links tabbable. */
  .nav-links {
    display: flex;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 0;
    padding: 0.5rem 0 max(1rem, env(safe-area-inset-bottom));
    margin: 0;
    list-style: none;
    background: #1A2440;
    border-top: 1px solid rgba(176, 141, 87, 0.25);
    border-bottom: 1px solid rgba(176, 141, 87, 0.25);
    max-height: calc(100vh - 64px);
    max-height: calc(100dvh - 64px);
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    box-shadow: 0 18px 40px rgba(26, 36, 64, 0.28);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-10px);
    pointer-events: none;
    transition: opacity 0.22s ease, transform 0.22s ease,
                visibility 0s linear 0.22s;
  }

  .nav-links.is-open,
  .nav-links.active {
    opacity: 1;
    visibility: visible;
    transform: none;
    pointer-events: auto;
    transition: opacity 0.22s ease, transform 0.22s ease, visibility 0s;
  }

  .nav-links li {
    border-bottom: 1px solid rgba(176, 141, 87, 0.12);
  }

  .nav-links li:last-child { border-bottom: 0; }

  .nav-links a {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    min-height: 52px;
    padding: 0.85rem 1.25rem;
    font-size: 0.875rem;
    letter-spacing: 0.12em;
    color: rgba(251, 249, 245, 0.88);
  }

  .nav-links a:hover,
  .nav-links a:focus { color: var(--gold-light); }

  /* Book Now is the one action the drawer exists to funnel people to, so it
     keeps the filled pill rather than reading as the ninth link in a list. */
  .nav-links .nav-book-item {
    border-bottom: 0;
    padding: 0.9rem 1.25rem 0.4rem;
  }

  .nav-links .nav-book {
    display: flex;
    justify-content: center;
    min-height: 52px;
    padding: 0.9rem 1.25rem;
    background: var(--gold-fill);
    color: #1A2440 !important;
    font-weight: 500;
    letter-spacing: 0.14em;
  }

  /* Calling is the only way to book the Canonsburg studio, so the number is
     a tap target in the drawer, not just something to read in the footer. */
  .nav-links .nav-call-item {
    border-bottom: 0;
    padding: 0.35rem 1.25rem 0.25rem;
  }

  /* `display` is restated because the site-wide `a[href^='tel:']` rule further
     down sets inline-flex, which left this one shrink-wrapped to its text
     while Book Now above it ran the full width. */
  .nav-links .nav-call {
    display: flex;
    width: 100%;
    justify-content: center;
    min-height: 52px;
    padding: 0.9rem 1.25rem;
    border: 1px solid rgba(176, 141, 87, 0.55);
    color: var(--gold-light);
    letter-spacing: 0.1em;
  }

  .nav-links .nav-call:hover,
  .nav-links .nav-call:focus {
    background: rgba(176, 141, 87, 0.14);
    color: var(--gold-light);
  }

  /* The drawer's own CTAs replace the sticky bar while it is open — leaving
     both up stacked two booking buttons over each other at the fold. */
  body.nav-open .cta-bar { display: none; }

  /* Body scroll lock while the drawer is open. */
  body.nav-open { overflow: hidden; }

  .nav-logo {
    display: flex;
    align-items: center;
    /* A flex container drops the whitespace between "Craft" and the
       <span>Collective</span>, which ran the wordmark together. */
    gap: 0.3em;
    min-height: 44px;
    font-size: 1rem;
    min-width: 0;             /* allow the flex item to shrink... */
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }

  .nav-mobile-actions { flex: 0 0 auto; }  /* ...so these never get pushed out */
}

/* The scrim behind the open drawer.

   It is not decoration. Tapping the page to dismiss a menu is implemented
   everywhere as a document-level click listener, and on iOS Safari a tap on a
   plain, non-interactive element does not produce a click event at document
   level at all — so "tap outside to close" silently does nothing on iPhones,
   which is where the drawer exists in the first place. A real element under
   the finger always fires, so the scrim is what makes that gesture work. */
.nav-scrim {
  position: fixed;
  top: 64px;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 125;
  display: none;
  background: rgba(10, 14, 26, 0.45);
  opacity: 0;
  transition: opacity 0.22s ease;
  -webkit-tap-highlight-color: transparent;
}

@media (max-width: 900px) {
  .nav-scrim { display: block; pointer-events: none; }
  /* `touch-action: none` is the scroll lock that actually holds on iOS, where
     `overflow: hidden` on the body does not stop a drag on the page behind. */
  body.nav-open .nav-scrim {
    pointer-events: auto;
    opacity: 1;
    touch-action: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .nav-links,
  .nav-links.is-open,
  .nav-links.active,
  .nav-scrim { transition: none; }
}

/* At 320px the wordmark, the Book pill and the hamburger no longer fit at
   full size — the toggle was rendering partly off-screen and unreachable. */
@media (max-width: 400px) {
  .nav-logo { font-size: 0.85rem; letter-spacing: 0.08em; }
  .nav-inner { padding: 0 0.75rem; gap: 0.4rem; }
  .nav-book-mobile { padding: 0 0.75rem; font-size: 0.75rem; }
}

/* ==========================================================================
   4. LIGHT SURFACES — the theme inversion proper
   ========================================================================== */

/* --------------------------------------------------------- 4a. home hero */

.hero,
.derek-hero {
  background: var(--paper-warm);
}

.hero-text {
  background: var(--paper-warm);
}

.hero-eyebrow,
.page-eyebrow {
  color: var(--gold-deep) !important;
  font-weight: 500;
}

.hero-headline,
.derek-name,
.name {
  color: var(--ink) !important;
}

.hero-headline em,
.derek-name em,
.name em {
  color: var(--gold-deep) !important;
}

.hero-sub,
.derek-intro,
.intro,
.lead-bio {
  color: var(--mid) !important;
}

.hero-loc-item {
  color: var(--mid) !important;
}

.hero-loc-item::before {
  background: var(--gold-deep);
}

/* The scrim exists to keep the headline legible where it overlaps the photo.
   On a light hero it has to fade from paper, not from near-black. */
.hero-image-overlay {
  background: linear-gradient(to right, var(--paper-warm) 0%, rgba(251, 249, 245, 0) 34%);
}

/* The photos were dimmed to sit under light text. On a light page they should
   be the brightest thing on screen. */
.hero-image-panel img,
.hero-image img,
.about-image img,
.lead-image img,
.gallery-item img,
.article-hero-img,
.team-card img,
.derek-hero img {
  filter: none;
}

.about-image,
.lead-image,
.hero-image,
.hero-image-panel {
  background: var(--cream);
}

.btn-ghost {
  color: var(--ink);
  border-bottom-color: rgba(26, 36, 64, 0.28);
}

.lead-title,
.hero-page .lead-title,
.team-lead .lead-title {
  color: var(--gold) !important;
}

.btn-ghost:hover,
.btn-ghost:focus {
  color: var(--gold-deep);
  border-bottom-color: var(--gold-deep);
}

/* ------------------------------------------------- 4b. inner-page heroes */

/* /services/*, /locations/*, /blog/*, /reviews, /faq … every inner page led
   with a near-black band. They become a warm cream masthead with a hairline
   gold rule, so the page reads as one continuous light document. */
.hero-page,
.page-hero {
  background: linear-gradient(180deg, var(--cream) 0%, var(--paper-warm) 100%);
  border-bottom: 1px solid var(--rule);
}

.hero-page h1,
.page-hero h1,
.page-headline {
  color: var(--ink) !important;
}

.hero-page h1 em,
.page-hero h1 em,
.page-headline em {
  color: var(--gold-deep) !important;
}

.hero-page .subtitle,
.page-hero .subtitle,
.subtitle,
.page-sub,
.article-meta,
.reviews-hero-meta {
  color: var(--mid) !important;
}

.breadcrumb,
.breadcrumb-bar {
  color: var(--mid) !important;
}

.breadcrumb a,
.breadcrumb-bar a {
  color: var(--gold-deep) !important;
  text-decoration: none;
}

.breadcrumb a:hover,
.breadcrumb-bar a:hover {
  color: var(--ink) !important;
  text-decoration: underline;
}

.breadcrumb span,
.breadcrumb-bar span {
  color: var(--rule);
  margin: 0 0.5rem;
}

/* --------------------------------------------- 4c. body bands and panels */

.about-content,
.lead-content,
.locations,
.testimonials,
.areas,
.pillars,
.brands,
.maps-section {
  background: var(--cream) !important;
}

/* Alternating rhythm so consecutive bands don't merge into one field. */
.services,
.gallery-preview,
.content-section,
.about-section,
.faq,
.faq-section,
.team-section,
.reviews-main,
.gallery-main,
.services-main,
.blog-main,
.related-posts,
.why-us,
.expect,
.booking-locations {
  background: var(--paper);
}

.content-section.alt,
.section-alt,
.panel-light {
  background: var(--paper-warm) !important;
}

.about-content .section-headline,
.locations-header .section-headline,
.testimonials .section-headline,
.areas .section-headline,
.pillars .section-headline,
.maps-section .section-headline,
.brands .section-headline,
.lead-content .section-headline,
.section-headline {
  color: var(--ink) !important;
}

.section-headline em,
.cta-headline em,
h2 em,
h3 em {
  font-style: italic;
  color: var(--gold-deep) !important;
}

.about-body,
.location-detail,
.area-desc,
.pillar-desc,
.map-address,
.credential,
.stat-label,
.brands-label {
  color: var(--mid) !important;
}

.location-detail strong,
.area-name,
.pillar-title,
.brand-name,
.location-name,
.derek-name,
.award-text,
.gallery-overlay-title {
  color: var(--ink) !important;
}

.credential::before,
.hero-loc-item::before {
  background: var(--gold-deep);
}

.section-label,
.footer-col-head,
.location-tag,
.area-tag,
.category-label,
.blog-card-eyebrow,
.cred-year,
.map-card-label,
.info-label,
.stat-num,
.service-num,
.service-arrow,
.testimonial-stars,
.review-stars {
  color: var(--gold-deep);
}

/* --------------------------------------------------- 4c-bis. gold fills */

/* The closed set of surfaces painted with the brand gold. Everything here
   also states its own text color, because ink on gold is the only pairing
   on that ground that clears AA. */
.nav-book,
.nav-book-mobile,
.btn-primary,
.location-cta,
.filter-btn.active,
.btn-outline:hover,
.tag-pill,
.cta-bar-book,
.about-image-badge,
.contact-strip {
  background: var(--gold-fill);
  color: #1A2440;
}

/* `:not([class*='btn'])` again: the contact strip contains a .btn-dark, and
   forcing ink on it painted ink type onto an ink button. Buttons carry their
   own ground and so must be exempt from any container-level color. */
.about-image-badge,
.about-image-badge .badge-num,
.about-image-badge .badge-text,
.contact-strip,
.contact-strip p,
.contact-strip a:not([class*='btn']),
.contact-strip strong,
.contact-strip .section-label,
.contact-strip h2,
.contact-strip h3 {
  color: #1A2440 !important;
}

.contact-strip a:not([class*='btn']) {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Decorative rules — short hairlines, not text, so no contrast threshold
   applies and the deeper mix reads better against paper anyway. */
.credential::before,
.hero-loc-item::before,
.why-title::before {
  background: var(--gold);
}

/* Reversed context: the footer and nav keep the dark ground, so gold there has
   to move the other way — the text-safe mix is 3.5:1 against #1A2440. This is
   a bare `footer a` on purpose: it is the catch-all for links the theme layer
   has not named, and every footer link class that wants a different color
   (.footer-links a) outranks it on specificity anyway. */
footer .footer-col-head,
footer .section-label,
footer a,
footer .footer-contact-info a,
footer [class*='gold'],
.nav .section-label {
  color: var(--gold-light);
}

/* ----------------------------------------------------- 4d. cards on light */

.location-card,
.testimonial-card,
.review-card,
.area-card,
.pillar-card,
.map-card,
.stat-card,
.brand-card {
  background: var(--paper);
  border: 1px solid var(--rule);
  box-shadow: var(--shadow-sm);
}

.locations-grid,
.testimonials-grid,
.reviews-grid {
  background: transparent;
  gap: 1.25rem;
}

.testimonial-text,
.review-text {
  color: var(--text) !important;
}

.testimonial-name,
.review-name {
  color: var(--ink) !important;
  font-weight: 500;
}

.testimonial-detail,
.review-detail {
  color: var(--mid) !important;
}

.service-card {
  background: var(--paper);
  border: 1px solid var(--rule);
}

.services-grid,
.service-grid {
  background: transparent;
  gap: 1.25rem;
}

.service-card:hover,
.service-card:focus-within {
  background: var(--gold-wash);
  border-color: var(--gold);
}

.service-name,
.service-item-name,
.team-card-name,
.blog-card-title,
.related-card h3,
.tip-title,
.why-title,
.expect-title {
  color: var(--ink);
}

.service-desc,
.service-item-desc,
.team-card-bio,
.blog-card-excerpt,
.related-card p,
.tip-desc,
.why-desc,
.expect-desc,
.loc-card-detail,
.faq-answer,
.prose,
.article-content {
  color: var(--text);
}

.team-grid,
.related-grid,
.tips-grid,
.why-grid,
.gallery-grid {
  background: transparent;
}

.team-card,
.blog-card,
.related-card,
.tip-card,
.why-card,
.expect-card {
  background: var(--paper);
  border: 1px solid var(--rule);
}

.team-card:hover,
.blog-card:hover,
.related-card:hover,
.tip-card:hover {
  border-color: var(--gold);
}

/* --------------------------------------------------------- 4e. gallery */

/* Photos were sitting at brightness(0.85) so they could carry white overlay
   text on a dark page. Against paper they run at full strength, and the tag
   gets its own scrim instead. */
.gallery-item {
  background: var(--cream);
  overflow: hidden;
}

.gallery-item img {
  filter: none;
}

.gallery-item:hover img {
  transform: scale(1.04);
  filter: none;
}

.gallery-tag,
.gallery-overlay-tag {
  background: rgba(26, 36, 64, 0.78);
  color: #fbf9f5;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

/* --------------------------------------------------------- 4f. prose */

.prose h2,
.prose h3,
.article-content h2,
.article-content h3,
.content-inner h2,
.content-inner h3 {
  color: var(--ink);
  font-family: 'Cormorant Garamond', serif;
  font-weight: 400;
}

.prose h2,
.article-content h2 {
  margin-top: 2.5rem;
  margin-bottom: 0.9rem;
}

.prose h3,
.article-content h3 {
  margin-top: 2rem;
  margin-bottom: 0.75rem;
}

.prose p,
.article-content p,
.prose li,
.article-content li {
  margin-bottom: 1.1rem;
}

.prose ul,
.prose ol,
.article-content ul,
.article-content ol {
  margin: 0 0 1.4rem 1.25rem;
}

/* `:not([class*='btn'])` matters: `.article-content a` is (0,2,0) and beats a
   bare `.btn-primary` at (0,1,0), so without the exclusion every CTA button
   sitting inside an article body was repainted gold-on-gold — 2:1, an
   invisible button on exactly the pages where booking matters most. */
.prose a:not([class*='btn']),
.article-content a:not([class*='btn']),
.nap-box a,
.info-value a,
.plain-list a:not([class*='btn']) {
  color: var(--gold);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(138, 103, 57, 0.45);
}

.prose a:not([class*='btn']):hover,
.article-content a:not([class*='btn']):hover {
  color: var(--ink);
  text-decoration-color: currentColor;
}

/* Buttons keep their own palette wherever they are nested. */
.prose .btn-primary,
.article-content .btn-primary,
.article-cta .btn-primary,
.book-cta .btn-primary {
  background: var(--gold-fill);
  color: #1A2440;
}

.prose .btn-dark,
.article-content .btn-dark,
.article-cta .btn-dark {
  background: var(--ink);
  color: #fbf9f5;
}

.prose .btn-outline,
.article-content .btn-outline,
.article-cta .btn-outline,
.btn-outline {
  color: var(--ink);
  border-color: var(--ink);
}

.nap-box {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--gold);
  box-shadow: var(--shadow-sm);
}

.nap-box h3 {
  color: var(--ink);
}

.nap-box p,
.hours-day,
.hours-time,
.info-value {
  color: var(--text);
}

.article-hero-img {
  width: 100%;
  object-fit: cover;
}

.article-cta {
  background: var(--gold-wash);
  border: 1px solid var(--gold);
  padding: 2rem;
  margin: 2.5rem 0;
  text-align: center;
}

.article-cta h3 {
  color: var(--ink);
  margin-bottom: 0.6rem;
}

.article-cta p {
  color: var(--text);
  margin-bottom: 1.4rem;
}

/* ------------------------------------------------------- 4g. buttons */

.btn-primary {
  background: var(--gold-fill);
  color: #1A2440;
  font-weight: 500;
}

.btn-primary:hover,
.btn-primary:focus {
  background: var(--gold-deep);
  color: #ffffff;
}

.btn-dark {
  background: var(--ink);
  color: #fbf9f5;
}

.btn-dark:hover,
.btn-dark:focus {
  background: var(--gold-deep);
  color: #ffffff;
}

.btn-outline,
.btn-outline-dark {
  border: 1.5px solid var(--ink);
  color: var(--ink);
  background: transparent;
}

.btn-outline:hover,
.btn-outline-dark:hover,
.btn-outline:focus,
.btn-outline-dark:focus {
  background: var(--ink);
  color: #fbf9f5;
}

.location-cta {
  background: var(--gold-fill);
  color: #1A2440;
}

.location-cta:hover,
.location-cta:focus {
  background: var(--gold-deep);
  color: #ffffff;
}

.filter-btn {
  background: var(--paper);
  border: 1px solid var(--rule);
  color: var(--text);
}

.filter-btn:hover,
.filter-btn.active {
  border-color: var(--gold);
  background: var(--gold-wash);
  color: var(--gold-deep);
}

/* ------------------------------------------------- 4h. gold CTA bands */

/* .book-cta and .cta-section are the pages' one saturated moment. Ink type on
   a gold ground is the highest-contrast pairing on the site, which is what a
   conversion band should be.

   The band is a gradient rather than flat --gold for one reason: the design
   sets the emphasised half of the headline in off-white, and off-white on
   flat #b08d57 is 2.6:1 — under the 3:1 that even large display type needs.
   Deepening the ground to #9a7844 at the foot takes it to 3.4:1 while ink
   type rises to 6.3:1. */
.book-cta,
.cta-section {
  background: linear-gradient(160deg, #b08d57 0%, #9a7844 100%) !important;
  text-align: center;
}

.book-cta h2,
.cta-section .cta-headline,
.cta-headline {
  color: #1A2440 !important;
}

.book-cta h2 em,
.cta-section h2 em,
.contact-strip h2 em,
.cta-headline em {
  color: #ffffff !important;
  font-style: italic;
}

.book-cta p,
.cta-sub {
  color: rgba(26, 36, 64, 0.82) !important;
}

/* Gold-on-gold: the eyebrow label inherits --gold-deep from the light-surface
   rules, which is all but invisible once the band behind it is also gold. */
.book-cta .section-label,
.cta-section .section-label,
.book-cta .page-eyebrow,
.cta-section .page-eyebrow,
.book-cta .hero-eyebrow,
.cta-section .hero-eyebrow,
.book-cta .footer-col-head,
.cta-section .footer-col-head {
  color: rgba(26, 36, 64, 0.72) !important;
}

.book-cta .btn-dark,
.cta-section .btn-dark {
  background: var(--ink);
  color: #fbf9f5;
}

.book-cta .btn-dark:hover,
.cta-section .btn-dark:hover {
  background: #ffffff;
  color: var(--ink);
}

.book-cta .btn-outline-dark:hover,
.cta-section .btn-outline-dark:hover {
  background: var(--ink);
  color: #fbf9f5;
}

/* ---------------------------------------------------- 4i. services strip */

.services-strip {
  background: var(--ink);
  border-top: 0;
  border-bottom: 0;
}

.strip-item {
  color: rgba(251, 249, 245, 0.72);
}

.strip-item::after {
  color: var(--gold-light);
}

/* -------------------------------------------------------- 4j. footer */

/* The footer keeps the dark ground — it closes the page and carries the NAP
   block. Opacities are lifted so nothing sits under 4.5:1. */
footer {
  background: var(--ink);
  border-top: 3px solid var(--gold);
}

.footer-tagline {
  color: rgba(251, 249, 245, 0.62) !important;
}

.footer-contact,
.footer-contact-info,
.footer-links a {
  color: rgba(251, 249, 245, 0.78) !important;
}

.footer-contact a {
  color: var(--gold-light) !important;
}

.footer-links a:hover,
.footer-contact a:hover {
  color: #ffffff !important;
}

.footer-copy {
  color: rgba(251, 249, 245, 0.5) !important;
}

.footer-bottom {
  border-top: 1px solid rgba(251, 249, 245, 0.12);
}

/* ==========================================================================
   5. NEW COMPONENTS
   ========================================================================== */

/* ------------------------------------------------- 5a. sticky mobile CTA */

/* A salon site's whole job on a phone is "call" or "book". Both live in a
   fixed bar so neither is ever more than one thumb-reach away, at any scroll
   depth, on any page. */
.cta-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 120;
  display: none;
  background: rgba(26, 36, 64, 0.98);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-top: 1px solid rgba(176, 141, 87, 0.4);
  box-shadow: 0 -6px 24px rgba(26, 36, 64, 0.18);
  padding-bottom: env(safe-area-inset-bottom);
}

.cta-bar-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: rgba(176, 141, 87, 0.3);
}

.cta-bar a {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 56px;
  padding: 0.5rem 0.75rem;
  font-family: 'Jost', sans-serif;
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  text-align: center;
  line-height: 1.2;
}

.cta-bar-call {
  background: #1A2440;
  color: #fbf9f5;
}

.cta-bar-book {
  background: var(--gold-fill);
  color: #1A2440;
}

.cta-bar-call:hover,
.cta-bar-call:focus { background: #232E4D; color: #ffffff; }
.cta-bar-book:hover,
.cta-bar-book:focus { background: var(--gold-light); color: #1A2440; }

.cta-bar svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@media (max-width: 900px) {
  .cta-bar { display: block; }

  /* Reserve the bar's height so it never covers the last line of the footer. */
  body { padding-bottom: 58px; }
}

@media (max-width: 400px) {
  .cta-bar a { font-size: 0.75rem; letter-spacing: 0.06em; }
}

@media print {
  .cta-bar, .nav { display: none !important; }
}

/* ------------------------------------------- 5a-bis. page imagery */

/* Nine service pages and twenty location pages had no image on them at all.
   These give every page a full-bleed shot under the masthead, sized by
   aspect-ratio so the space is reserved before the file arrives. */
.loc-hero-img,
.blog-hero-img {
  position: relative;
  overflow: hidden;
  background: var(--cream);
  aspect-ratio: 21 / 9;
  max-height: 60vh;
}

.blog-hero-img { aspect-ratio: 3 / 1; }

.loc-hero-img img,
.blog-hero-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 35%;
  display: block;
}

@media (max-width: 900px) {
  .loc-hero-img { aspect-ratio: 16 / 10; }
  .blog-hero-img { aspect-ratio: 16 / 9; }
}

@media (max-width: 600px) {
  .loc-hero-img,
  .blog-hero-img { aspect-ratio: 4 / 3; }
}

/* Recent-work three-up on service pages. "Balayage" is something people want
   to see before they book it. */
.svc-work {
  background: var(--paper-warm);
  border-top: 1px solid var(--rule);
  padding: 5rem 2rem;
}

.svc-work-inner { max-width: 1200px; margin: 0 auto; }

.svc-work h2 {
  font-family: 'Cormorant Garamond', serif;
  font-size: clamp(1.8rem, 3.5vw, 2.75rem);
  font-weight: 300;
  line-height: 1.15;
  color: var(--ink);
  margin-bottom: 2.25rem;
}

.svc-work h2 em { font-style: italic; color: var(--gold); }

.svc-work-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.25rem;
}

.svc-shot {
  margin: 0;
  overflow: hidden;
  background: var(--cream);
  aspect-ratio: 4 / 3;
  border: 1px solid var(--rule);
}

.svc-shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.4s ease;
}

@media (hover: hover) and (pointer: fine) {
  .svc-shot:hover img { transform: scale(1.04); }
}

.svc-work-note { margin-top: 1.5rem; }

@media (max-width: 900px) {
  .svc-work { padding: 3.5rem 1.5rem; }
  .svc-work-grid { gap: 0.75rem; }
}

@media (max-width: 600px) {
  .svc-work { padding: 3rem 1.25rem; }
  /* Three stacked full-width photos is a long scroll; two-up keeps the
     section scannable, with the third running full width beneath. */
  .svc-work-grid { grid-template-columns: repeat(2, 1fr); gap: 6px; }
  .svc-shot:last-child { grid-column: span 2; aspect-ratio: 16 / 9; }
}

/* ------------------------------------------------------ 5b. trust bar */

.trust-bar {
  background: var(--paper-warm);
  border-bottom: 1px solid var(--rule);
  padding: 1.75rem 2rem;
}

.trust-inner {
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.5rem;
  align-items: start;
}

.trust-item {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  text-align: center;
}

/* The four values are set in different faces and sizes (stars, a word, two
   numerals), so a fixed box keeps their baselines on one line across the row
   instead of letting each float to the center of its own label height. */
.trust-value {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 1.75rem;
  font-family: 'Cormorant Garamond', serif;
  font-size: 1.6rem;
  font-weight: 400;
  line-height: 1;
  color: var(--ink);
}

.trust-value .stars {
  color: var(--gold-deep);
  letter-spacing: 0.1em;
  font-size: 1.1rem;
}

.trust-label {
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--mid);
  font-weight: 400;
}

@media (max-width: 900px) {
  .trust-bar { padding: 1.5rem 1.25rem; }
  .trust-inner { grid-template-columns: repeat(2, 1fr); gap: 1.5rem 1rem; }
  .trust-value { font-size: 1.4rem; }
}

/* ----------------------------------------------------- 5c. FAQ section */

.faq-block {
  background: var(--paper-warm);
  padding: 5rem 2rem;
  border-top: 1px solid var(--rule);
}

.faq-block-inner {
  max-width: 820px;
  margin: 0 auto;
}

.faq-block .section-label {
  font-size: 0.65rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--gold-deep);
  margin-bottom: 0.9rem;
}

.faq-block h2 {
  font-family: 'Cormorant Garamond', serif;
  font-size: clamp(1.8rem, 3.5vw, 2.75rem);
  font-weight: 300;
  line-height: 1.15;
  color: var(--ink);
  margin-bottom: 2.25rem;
}

.faq-block h2 em {
  font-style: italic;
  color: var(--gold-deep);
}

.faq-block .faq-item {
  border-top: 1px solid var(--rule);
  padding: 0;
}

.faq-block .faq-item:last-child {
  border-bottom: 1px solid var(--rule);
}

.faq-block .faq-question {
  font-family: 'Cormorant Garamond', serif;
  font-size: 1.2rem;
  font-weight: 400;
  color: var(--ink);
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 1.35rem 0;
  min-height: 44px;
}

.faq-block .faq-question::after {
  content: '+';
  font-family: 'Jost', sans-serif;
  font-size: 1.35rem;
  font-weight: 300;
  color: var(--gold-deep);
  flex-shrink: 0;
  transition: transform 0.2s ease;
}

.faq-block .faq-item.open .faq-question::after {
  transform: rotate(45deg);
}

.faq-block .faq-answer {
  font-size: 0.9375rem;
  line-height: 1.85;
  color: var(--text);
}

.faq-block .faq-item.open .faq-answer {
  padding-bottom: 1.35rem;
}

@media (max-width: 900px) {
  .faq-block { padding: 3.5rem 1.5rem; }
  .faq-block .faq-question { font-size: 1.0625rem; }
  .faq-block .faq-answer { font-size: 1rem; }
}

@media (max-width: 600px) {
  .faq-block { padding: 3rem 1.25rem; }
}

/* ------------------------------------------------ 5d. related links row */

.xlinks {
  background: var(--paper);
  border-top: 1px solid var(--rule);
  padding: 3rem 2rem;
}

.xlinks-inner {
  max-width: 1200px;
  margin: 0 auto;
}

.xlinks h2 {
  font-family: 'Cormorant Garamond', serif;
  font-size: 1.5rem;
  font-weight: 400;
  color: var(--ink);
  margin-bottom: 1.4rem;
}

.xlinks-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

.xlinks-grid a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.55rem 1.1rem;
  background: var(--paper-warm);
  border: 1px solid var(--rule);
  color: var(--text);
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-decoration: none;
  transition: all 0.2s ease;
}

.xlinks-grid a:hover,
.xlinks-grid a:focus {
  background: var(--gold-wash);
  border-color: var(--gold);
  color: var(--gold-deep);
}

@media (max-width: 600px) {
  .xlinks { padding: 2.5rem 1.25rem; }
}

/* ==========================================================================
   6. READABLE TYPE
   ========================================================================== */

@media (max-width: 900px) {
  /* Body copy floor: 16px. Nothing a visitor has to actually read sits below. */
  .prose,
  .prose p,
  .prose li,
  .hero-sub,
  .about-body,
  .bio-paragraph,
  .intro,
  .subtitle,
  .service-desc,
  .service-item-desc,
  .service-card p,
  .team-card-bio,
  .blog-card-excerpt,
  .review-text,
  .testimonial-text,
  .location-detail,
  .loc-card-detail,
  .area-desc,
  .tip-desc,
  .why-desc,
  .expect-desc,
  .pillar-desc,
  .cred-desc,
  .credential,
  .related-card p,
  .nap-box p,
  .hours-day,
  .hours-time,
  .map-address,
  .appt-notice p,
  .contact-text p,
  .book-cta p,
  .footer-contact,
  .footer-contact-info,
  .info-value,
  .page-sub,
  .article-content,
  .article-content p,
  .article-content li,
  .faq-answer {
    font-size: 1rem;
    line-height: 1.75;
  }

  .prose h2 { font-size: 1.6rem; line-height: 1.25; }
  .prose h3 { font-size: 1.25rem; line-height: 1.3; }

  /* Navigation-weight links: 15px. */
  .footer-links a,
  .service-item-name,
  .team-card-name,
  .review-name,
  .testimonial-name,
  .blog-card-title,
  .info-label {
    font-size: 0.9375rem;
  }

  /* Buttons: 14px uppercase — legible without shouting. */
  .btn-primary,
  .btn-dark,
  .btn-ghost,
  .btn-outline,
  .btn-outline-dark,
  .location-cta,
  .service-arrow,
  .service-card a,
  .filter-btn,
  .nav-book {
    font-size: 0.875rem;
  }

  /* Uppercase micro-labels: 12px floor. Tracked caps stay legible here and
     dropping the design's label scale entirely would flatten the hierarchy. */
  .section-label,
  .page-eyebrow,
  .hero-eyebrow,
  .footer-col-head,
  .location-tag,
  .category-label,
  .blog-card-eyebrow,
  .cred-year,
  .gallery-tag,
  .gallery-overlay-tag,
  .specialty-tag,
  .badge-text,
  .brands-label,
  .breadcrumb,
  .breadcrumb-bar,
  .hero-loc-item,
  .article-meta,
  .blog-card-date,
  .team-card-role,
  .service-item-duration,
  .review-detail,
  .testimonial-detail,
  .stat-label,
  .footer-copy,
  .footer-tagline,
  .strip-item,
  .area-tag,
  .map-card-label,
  .award-text,
  .award-text strong,
  .badge-text strong,
  .featured-badge span,
  .reviews-hero-meta,
  .social-proof-badges span {
    font-size: 0.75rem;
  }

  /* The escape hatch under the Phorest iframe, promoted from a 13px inline
     link to a button. It matters more on a phone than anywhere else: mobile
     Safari's tracking prevention is the most likely thing to leave that
     embed blank, and when it does this link is the only way to book. */
  .booking-embed-fallback {
    font-size: 0.875rem;
    text-align: center;
  }

  .booking-embed-fallback a {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 48px;
    margin-top: 0.6rem;
    padding: 0.75rem 1.25rem;
    border: 1px solid var(--gold-fill);
    color: var(--gold-deep);
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-decoration: none;
  }

  /* Two labels sit above the floor's specificity and so were still rendering
     at 10–11px on a phone: the FAQ eyebrow is set by a descendant selector,
     and .trust-label carries its own declaration. Restated at matching weight
     rather than loosened, so the floor stays a floor. */
  .faq-block .section-label,
  .trust-bar .trust-label {
    font-size: 0.75rem;
  }

  .footer-tagline { font-size: 0.8125rem; }
}

/* Desktop: only the genuinely-too-small body copy moves. Label scale is
   part of the visual identity and stays as designed. */
@media (min-width: 901px) {
  .service-desc,
  .service-item-desc,
  .service-card p,
  .team-card-bio,
  .blog-card-excerpt,
  .location-detail,
  .loc-card-detail,
  .area-desc,
  .tip-desc,
  .why-desc,
  .expect-desc,
  .pillar-desc,
  .cred-desc,
  .credential,
  .related-card p,
  .footer-contact,
  .footer-contact-info,
  .footer-links a,
  .hours-day,
  .hours-time,
  .map-address,
  .appt-notice p,
  .contact-text p,
  .review-name,
  .testimonial-name {
    font-size: 0.9rem;
  }

  .prose,
  .article-content {
    font-size: 1rem;
    line-height: 1.8;
  }
}

/* ==========================================================================
   7. CLASSES LIFTED OUT OF INLINE STYLES
   ========================================================================== */

/* These replace ~650 repeated `style` attributes. Inline styles outrank every
   stylesheet rule, so none of the responsive work below could reach them
   while they stayed inline. */

.link-gold {
  color: var(--gold-deep);
  text-decoration: none;
  font-size: 0.9rem;
}

.link-caps {
  color: var(--gold-deep);
  text-decoration: none;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 500;
}

.link-arrow {
  display: inline-block;
  margin-top: 1rem;
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold-deep);
  text-decoration: none;
  border-bottom: 1px solid rgba(138, 103, 57, 0.35);
  padding-bottom: 2px;
  font-weight: 500;
}

.link-gold:hover,
.link-caps:hover,
.link-arrow:hover {
  color: var(--ink);
}

.h-card {
  font-family: 'Cormorant Garamond', serif;
  font-size: 1.2rem;
  font-weight: 400;
  margin-bottom: 1rem;
  color: var(--ink);
}

.tag-pill {
  display: inline-block;
  background: var(--gold-fill);
  color: #1A2440;
  padding: 0.4rem 0.8rem;
  font-size: 0.65rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 500;
  margin-right: 0.5rem;
}

.wrap-1200 { max-width: 1200px; margin-left: auto; margin-right: auto; }
.wrap-650  { max-width: 650px;  margin-left: auto; margin-right: auto; }

.plain-list { list-style: none; line-height: 2.2; }
.muted-list { font-size: 0.9rem; color: var(--mid); }

.split-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3rem;
  margin-top: 1.5rem;
}

.panel-light {
  background: var(--paper-warm);
  padding: 4rem;
}

/* Fallbacks only — zero specificity, so any page that defines these itself
   still wins. */
:where(.btn-dark) {
  display: inline-block;
  background: var(--ink);
  color: #fbf9f5;
  padding: 0.9rem 2.5rem;
  text-decoration: none;
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 500;
}

:where(.cta-actions) {
  display: flex;
  gap: 1rem;
  justify-content: center;
  flex-wrap: wrap;
}

/* The two-column specialties grid on every stylist page was hard-coded and
   never stacked; 4rem of panel padding left 247px of content at 375px. */
@media (max-width: 700px) {
  .split-grid {
    grid-template-columns: 1fr;
    gap: 1.25rem;
  }
}

@media (max-width: 900px) {
  .panel-light { padding: 3rem 1.5rem; }
  .plain-list { line-height: 2; }
  .muted-list { font-size: 1rem; }
  .link-gold { font-size: 1rem; }
  .link-caps,
  .link-arrow { font-size: 0.8125rem; }
  .tag-pill {
    font-size: 0.75rem;
    padding: 0.5rem 0.9rem;
    margin-bottom: 0.4rem;
  }
  .h-card { font-size: 1.35rem; }
}

@media (max-width: 600px) {
  .panel-light { padding: 2.5rem 1.25rem; }
}

/* ==========================================================================
   8. TOUCH TARGETS
   ========================================================================== */

@media (max-width: 900px) {
  .btn-primary,
  .btn-dark,
  .btn-ghost,
  .btn-outline,
  .btn-outline-dark,
  .location-cta,
  .nav-book,
  .filter-btn,
  .article-cta a,
  .service-card a,
  .service-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding-top: 0.7rem;
    padding-bottom: 0.7rem;
  }

  /* Stacked link lists need real vertical room between rows. */
  .footer-links li { margin-bottom: 0; }

  .footer-links a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0.35rem 0;
  }

  /* Phone and email are the primary conversion actions on a salon site. */
  .footer-contact a,
  .nap-box a,
  .info-value a,
  .map-address a,
  a[href^='tel:'],
  a[href^='mailto:'] {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  /* ...but not when they're mid-sentence inside running prose, where a 44px
     inline-flex box would break the line box it sits in. The NAP block is
     deliberately not exempt: its phone number is on its own line and is one
     of the two things a phone visitor came to tap. */
  .prose a[href^='tel:'],
  .prose a[href^='mailto:'],
  .article-content a[href^='tel:'],
  .article-content a[href^='mailto:'] {
    display: inline;
    min-height: 0;
  }

  .faq-question {
    min-height: 44px;
    padding: 0.85rem 0;
    font-size: 1.05rem;
  }

  .breadcrumb a,
  .breadcrumb-bar a,
  .link-arrow,
  .link-caps,
  .plain-list a,
  .team-card a,
  .blog-card a,
  .related-card a,
  .xlinks-grid a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  /* The breadcrumb row would otherwise grow by the full 44px of its links. */
  .breadcrumb,
  .breadcrumb-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
  }

  .link-arrow { margin-top: 0.5rem; }
}

/* Buttons keep their generous hit area on desktop too. */
.btn-primary,
.btn-dark,
.btn-outline,
.btn-outline-dark,
.location-cta,
.filter-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ==========================================================================
   9. CTA PROMINENCE (MOBILE)
   ========================================================================== */

@media (max-width: 900px) {
  /* Primary CTAs go full-width so they land under the thumb, not beside it. */
  .hero-actions,
  .cta-actions,
  .article-cta {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.85rem;
    width: 100%;
  }

  .hero-actions .btn-primary,
  .hero-actions .btn-ghost,
  .cta-actions .btn-dark,
  .cta-actions .btn-outline-dark {
    width: 100%;
    text-align: center;
  }

  .hero-actions .btn-ghost {
    border-bottom: 0;
    border: 1px solid rgba(26, 36, 64, 0.28);
  }

  .book-cta .btn-dark,
  .book-cta .btn-primary {
    width: 100%;
    max-width: 380px;
  }
}

@media (max-width: 480px) {
  .location-cta { width: 100%; }
}

/* ==========================================================================
   10. LAYOUT / GRID STACKS
   ========================================================================== */

/* Everything collapses to a single column on phones. */
@media (max-width: 600px) {
  .services-grid,
  .service-grid,
  .team-grid,
  .locations-grid,
  .testimonials-grid,
  .reviews-grid,
  .related-grid,
  .tips-grid,
  .why-grid,
  .expect-grid,
  .pillars-grid,
  .areas-grid,
  .maps-grid,
  .hero-stat-grid,
  .social-proof-badges,
  .footer-inner,
  .specialties-section,
  .about,
  .hero,
  .derek-hero,
  .location-detail,
  .lead {
    grid-template-columns: 1fr;
  }

  .footer-inner { gap: 2rem; }

  /* Day/time rows read better stacked than squeezed into two columns. */
  .hours-grid {
    grid-template-columns: 1fr;
    gap: 0.25rem 0;
  }

  .hours-day { font-weight: 500; }
  .hours-time { margin-bottom: 0.6rem; opacity: 0.85; }

  .gallery-item-wide { grid-column: span 1; }
  .gallery-item-tall { grid-row: span 1; }
}

/* Tablet: two columns where the content supports it. */
@media (min-width: 601px) and (max-width: 900px) {
  .footer-inner { grid-template-columns: 1fr 1fr; }
  .service-grid,
  .services-grid,
  .team-grid,
  .related-grid { grid-template-columns: repeat(2, 1fr); }
}

/* A gallery is the one grid that stays two-up on phones — 15 stacked
   full-width photos is an unusable scroll. */
@media (max-width: 600px) {
  .gallery-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 6px;
  }
}

@media (max-width: 360px) {
  .gallery-grid { grid-template-columns: 1fr; }
}

/* Filter rows scroll horizontally instead of wrapping into a tall block. */
@media (max-width: 600px) {
  /* These wrap rather than scroll sideways. As a single nowrap row the last
     two filters sat past the right edge of a 390px screen with nothing to
     signal they were there — a horizontal scroller inside a vertically
     scrolling page is a gesture almost nobody goes looking for. Five short
     chips cost one extra row. */
  .gallery-filters,
  .filter-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    padding-bottom: 0.25rem;
  }

  .filter-btn {
    flex: 0 0 auto;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
}

/* Header rows that pair a headline with a link stack instead of squashing. */
@media (max-width: 900px) {
  .services-header,
  .gallery-header,
  .team-header,
  .pillars-header,
  .maps-header,
  .footer-bottom {
    flex-direction: column;
    align-items: flex-start;
    gap: 1rem;
  }

  .footer-bottom { text-align: left; }
}

/* ==========================================================================
   11. SECTION RHYTHM & SPACING
   ========================================================================== */

/* The fixed nav is 64-68px tall; every page's first section must clear it. */
.hero-page,
.page-hero {
  padding-top: 10rem;
}

@media (max-width: 900px) {
  .hero-page,
  .page-hero {
    padding: 7.5rem 1.5rem 3rem;
  }

  .hero-text { padding: 7.5rem 1.5rem 2.5rem; }

  .content-section,
  .about-section,
  .specialties-section,
  .services,
  .locations,
  .testimonials,
  .gallery-preview,
  .faq,
  .faq-section,
  .team-section,
  .areas,
  .book-cta,
  .cta-section,
  .related-posts,
  .contact-strip,
  .philosophy,
  .pillars,
  .maps-section,
  .booking-locations,
  .expect,
  .reviews-main,
  .gallery-main,
  .services-main,
  .blog-main,
  .brands,
  .why-us {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
  }
}

@media (max-width: 600px) {
  .hero-page,
  .page-hero {
    padding: 6.75rem 1.25rem 2.5rem;
  }

  .hero-text { padding: 6.75rem 1.25rem 2.25rem; }

  .content-section,
  .about-section,
  .specialties-section,
  .services,
  .locations,
  .testimonials,
  .gallery-preview,
  .faq,
  .faq-section,
  .team-section,
  .areas,
  .book-cta,
  .cta-section,
  .related-posts,
  .contact-strip,
  .philosophy,
  .pillars,
  .maps-section,
  .booking-locations,
  .expect,
  .reviews-main,
  .gallery-main,
  .services-main,
  .blog-main,
  .brands,
  .why-us {
    padding-top: 3rem;
    padding-bottom: 3rem;
    padding-left: 1.25rem;
    padding-right: 1.25rem;
  }

  .about-content,
  .lead-content,
  .location-card,
  .testimonial-card,
  .review-card,
  .service-card,
  .team-card-content,
  .nap-box,
  .tip-card,
  .expect-card,
  .article-cta {
    padding: 1.5rem 1.25rem;
  }

  footer { padding: 2.5rem 1.25rem; }
}

@media (max-width: 380px) {
  .hero-page,
  .page-hero,
  .content-section,
  .services,
  .locations,
  .testimonials,
  .gallery-preview,
  .faq,
  .cta-section,
  .book-cta,
  .booking-locations,
  .expect,
  .reviews-main,
  .gallery-main,
  .services-main,
  .blog-main,
  .maps-section,
  .contact-strip,
  .faq-block,
  .xlinks,
  footer {
    padding-left: 1rem;
    padding-right: 1rem;
  }

  .hero-text { padding-left: 1rem; padding-right: 1rem; }
}

/* ==========================================================================
   12. HERO / MEDIA PANELS
   ========================================================================== */

@media (max-width: 900px) {
  .hero,
  .derek-hero { min-height: 0; }

  .hero-image-panel,
  .hero-image,
  .about-image,
  .lead-image {
    height: auto;
    aspect-ratio: 4 / 3;
    max-height: 60vh;
  }

  .hero-image-panel img,
  .hero-image img,
  .about-image img,
  .lead-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* The left-to-right scrim is built for a side-by-side hero; on a stacked
     layout it just tints one edge. */
  .hero-image-overlay {
    background: linear-gradient(to bottom, rgba(251, 249, 245, 0.7) 0%, rgba(251, 249, 245, 0) 40%);
  }

  .hero-locations {
    position: static;
    margin-top: 2rem;
    gap: 0.65rem;
  }

  .about-image-badge {
    bottom: 1rem;
    right: 1rem;
    padding: 0.75rem 1rem;
  }

  .badge-num { font-size: 1.9rem; }
}

/* Headline scale that actually fits a 320px screen. */
@media (max-width: 600px) {
  .hero-headline { font-size: clamp(2.1rem, 10vw, 2.9rem); }
  .page-headline,
  .hero-page h1,
  .page-hero h1,
  .name,
  .derek-name { font-size: clamp(1.9rem, 8.5vw, 2.6rem); }
  .section-headline { font-size: clamp(1.65rem, 7vw, 2.2rem); }
  .cta-headline { font-size: clamp(1.9rem, 8vw, 2.6rem); }
  .book-cta h2 { font-size: clamp(1.7rem, 7.5vw, 2.2rem); }
}

@media (max-width: 380px) {
  .hero-headline { font-size: 1.95rem; }
  .page-headline,
  .hero-page h1,
  .page-hero h1 { font-size: 1.8rem; }
}

/* ==========================================================================
   13. FAQ ACCORDION
   ========================================================================== */

/* Two defects here, both pre-existing and both visible on the deployed site.

   1. The reveal animated `max-height` from 0 to a fixed ceiling. The page's
      own handler clears `.open` from every item and re-adds it to one in the
      same task, so the before/after styles are snapshotted without a recalc
      between them and the transition never starts — the answer stays at 0px
      and the accordion appears dead. The reveal is now instant: `max-height:
      none` cannot be interpolated, which is precisely what makes it reliable.

   2. The ceiling itself (300px on the homepage, 500px on /faq/) truncated
      longer answers once they reflowed into a narrow column. `none` removes
      the clamp entirely.

   Normalising the closed state at all widths also fixes /faq/, where the
   collapse was scoped to `@media (max-width: 600px)` and every answer sat
   permanently expanded on desktop. */
.faq-answer {
  max-height: 0;
  overflow: hidden;
  transition: none;
}

.faq-item.open .faq-answer {
  max-height: none;
}

.faq-question {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  user-select: none;
}

.faq-item {
  border-top-color: var(--rule);
}

/* ==========================================================================
   14. DESKTOP WIDTH & POLISH
   ========================================================================== */

@media (min-width: 901px) {
  /* Any grid that was allowed to run edge-to-edge gets a readable ceiling. */
  .service-grid,
  .team-grid,
  .gallery-grid,
  .related-grid,
  .reviews-grid,
  .tips-grid,
  .why-grid,
  .maps-grid,
  .nap-box,
  .contact-strip,
  .breadcrumb-bar,
  .services-main,
  .page-hero-inner {
    max-width: 1200px;
    margin-left: auto;
    margin-right: auto;
  }

  .prose,
  .article-content {
    max-width: 72ch;
  }

  /* Comfortable gutters between cards rather than hairline seams. */
  .team-grid { gap: 1.5rem; }
  .service-grid { gap: 1.5rem; }
  .related-grid { gap: 1.5rem; }

  .services { padding: 6rem 3rem; }
  .gallery-preview { padding: 6rem 3rem; }
}

/* Very wide screens: cap the measure inside full-bleed split panels so the
   copy doesn't stretch to 1200px of running text. */
@media (min-width: 1600px) {
  .hero-text > *,
  .about-content > *,
  .lead-content > * {
    max-width: 44rem;
  }

  .hero-text { padding-left: 8vw; }
  .about-content { padding-left: 6rem; padding-right: 6rem; }

  .content-section { padding-left: 3rem; padding-right: 3rem; }
}

/* ==========================================================================
   15. HOVER / MOTION
   ========================================================================== */

/* Hover effects only where a pointer can actually hover — on touch these
   otherwise stick after a tap. */
@media (hover: hover) and (pointer: fine) {
  .service-card:hover,
  .team-card:hover,
  .blog-card:hover,
  .related-card:hover,
  .review-card:hover,
  .tip-card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
  }

  .gallery-item:hover img {
    transform: scale(1.04);
  }

  .footer-links a:hover,
  .footer-contact a:hover {
    color: #ffffff;
  }

  .filter-btn:hover {
    border-color: var(--gold);
    color: var(--gold-deep);
  }
}

@media (hover: none) {
  .gallery-item:hover img { transform: none; }
  .service-card:hover .service-arrow { transform: none; }
}

.service-card,
.team-card,
.blog-card,
.related-card,
.gallery-item img,
.btn-primary,
.btn-dark,
.location-cta,
.filter-btn {
  transition-duration: 0.2s;
  transition-property: background-color, color, border-color, box-shadow, transform;
}

/* ==========================================================================
   10. TEAM CARDS
   ========================================================================== */

/* The stylist photos are square crops, framed on each sitter's own face so the
   head sits at the same height and the same scale across all thirty-nine. The
   card has to honor that or the work is thrown away at the last step: a
   fixed-height well re-crops the square to a letterbox band and puts the
   frame back where the CSS wants it rather than where the face is. A square
   well shows the crop exactly as cut. */
@media (max-width: 600px) {
  .team-card-image {
    height: auto;
    aspect-ratio: 1 / 1;
  }
}

/* Equal cards. The bio was the only thing that varied — two, three or four
   lines of it, which is where the 465 / 493 / 521px card heights came from —
   so it is the only thing that needs pinning. Four lines is the length of the
   longest bio on the page, so this pads the short ones out rather than
   truncating anyone; the clamp is insurance for narrower columns. */
.team-card-bio {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
  min-height: calc(4 * 1.75em);   /* four lines at the 1.75 line-height */
}

/* The salon number wherever it appears in running copy. It reads as part of
   the sentence and dials on tap; before this it was plain text, which on a
   phone means selecting and copying a number to place a call.

   Written as `a.tel-link` to outrank the site-wide `a[href^='tel:']` rule,
   which turns tel links into 44px inline-flex boxes. That is right for the
   footer and the NAP block, where the number stands alone, and wrong here:
   mid-sentence it would blow out the line box it sits in. The hit area comes
   back as block padding instead — padding on an inline box grows the tap
   target without moving a single line of type. */
a.tel-link {
  display: inline;
  min-height: 0;
  padding: 0.4rem 0.1rem;
  margin: 0 -0.1rem;
  color: inherit;
  white-space: nowrap;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: rgba(176, 141, 87, 0.75);
}

a.tel-link:hover,
a.tel-link:focus {
  color: var(--gold-deep);
  text-decoration-color: currentColor;
}

/* On the ink sections the deep-gold hover would be unreadable. */
.cta-section a.tel-link:hover,
.cta-section a.tel-link:focus,
.locations a.tel-link:hover,
.locations a.tel-link:focus,
footer a.tel-link:hover,
footer a.tel-link:focus {
  color: var(--gold-light);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .strip-inner { animation: none; transform: none; }
}

/* The trust band's labels are set in wide-tracked uppercase in four equal
   columns, so anything longer than a couple of words wraps. Left to itself the
   wrap goes ragged — "Pittsburgh-area studios" broke 118px/56px on a phone.
   Balancing evens the lines out so a two- or three-line label reads as a
   deliberate block rather than an overflow. */
.trust-label {
  text-wrap: balance;
}

/* The award badge on /derek-piekarski carried a 2.5rem bottom margin to clear
   the booking button that used to sit under it. With that button gone the
   margin is trailing: 88px of dead space under the badge on a phone against
   the 48px the padding intends, and a 20px upward shift of the whole block
   where the hero centers it vertically. Scoped to :last-child so the spacing
   comes back on its own if anything is ever placed after it again. */
.award-badge:last-child {
  margin-bottom: 0;
}

/* One cell of the four-across trust band links out; the other three do not.
   Inheriting the label's size and tracking keeps the row's rhythm, and the
   gold plus a resting underline is what marks it as a link rather than a
   stray tappable area. Only the words are the target — making the whole
   cell clickable next to three inert ones reads as a bug, not an affordance. */
.trust-link {
  color: var(--gold-deep);
  text-decoration: underline;
  text-decoration-color: rgba(184,154,106,0.45);
  text-underline-offset: 0.28em;
  text-decoration-thickness: 1px;
  transition: color 0.2s, text-decoration-color 0.2s;
}

.trust-link:hover,
.trust-link:focus-visible {
  color: var(--gold);
  text-decoration-color: currentColor;
}

/* The homepage hero slot changes orientation across the breakpoints: portrait
   beside the headline on desktop (roughly 0.64–0.80 depending on window
   height), landscape 4:3 once the two columns stack at 900px. The photograph
   is a 2:3 portrait, so desktop needs almost no crop and simply loses empty
   floor off the bottom — but the stacked 4:3 slot keeps only half the frame,
   and anchored at the top that half is all ceiling trusses. Dropping the
   anchor to 45% moves the window to 22%–72% of the frame, which is where the
   chairs, mirrors and the artwork at the far end actually are. */
@media (max-width: 900px) {
  .hero-image-panel img {
    object-position: center 45%;
  }
}

/* ==========================================================================
   18. REVIEWS — POINTING AT THE SOURCE
   ========================================================================== */

/* The testimonials that used to sit here were not real and have been removed.
   Until genuine ones are copied across, both places send the reader to the
   Google listing, which is where the actual reviews are. These rules do not
   touch .review-card or .testimonial-card, so restoring real cards needs no
   CSS work. */

.reviews-source {
  background: var(--paper-warm);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  padding: 5rem 2rem;
}

.reviews-source-inner {
  max-width: 640px;
  margin: 0 auto;
  text-align: center;
}

.reviews-source-copy {
  margin: 1.5rem 0 2.5rem;
  font-size: 0.92rem;
  line-height: 1.9;
  font-weight: 300;
  color: var(--mid);
  text-wrap: pretty;
}

.testimonials-source {
  max-width: 560px;
  margin: 1.5rem auto 2rem;
  font-size: 0.92rem;
  line-height: 1.9;
  font-weight: 300;
  color: var(--mid);
  text-align: center;
  text-wrap: pretty;
}

/* The homepage section centers its heading already; the link follows it. */
/* The rating is the one genuine piece of proof either block has, so it does
   the visual work the cards used to. */
.reviews-source-proof {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.9rem;
  margin: 0 0 2.5rem;
}

.reviews-source-stars {
  color: var(--gold-deep);
  font-size: 1rem;
  letter-spacing: 0.18em;
}

.reviews-source-figure {
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--mid);
}

.testimonials-inner > .btn-primary,
.testimonials-inner > .btn-ghost {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

@media (max-width: 600px) {
  .reviews-source { padding: 3.5rem 1.25rem; }
  .reviews-source-copy { margin-bottom: 2rem; }
}

/* ============================================================== 19
   LOCATION STUDIO PHOTOGRAPHS + LIGHTBOX

   The location pages are a two-column block: contact details and hours down
   the left, the map top right. The map is 4:3 and the left column is taller,
   so the right column always ends with dead space. This fills it with a row of
   small studio photographs, each opening full size.

   Built as a reusable component, not a North Hills special: any location page
   gets the same row by wrapping its .map-embed in .loc-media and adding a
   .loc-gallery beside it. Canonsburg has no photographs yet, so it has none.

   The thumbnails are 4:3 to rhyme with the map above them, and they are
   deliberately small — around 160px in the desktop column. The photographs
   are landscape and portrait mixed, so object-fit does the cropping rather
   than shipping a second set of crops.
   ------------------------------------------------------------------------ */

.loc-media {
  display: flex;
  flex-direction: column;
  gap: 2.25rem;
  min-width: 0;
}

.loc-gallery .info-label {
  margin-bottom: 0.9rem;
}

.loc-shots {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.75rem;
}

.loc-shots li {
  margin: 0;
}

.loc-shot {
  display: block;
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--rule);
  background: var(--paper);
  cursor: zoom-in;
}

.loc-shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.35s ease;
}

.loc-shot:hover img,
.loc-shot:focus-visible img {
  transform: scale(1.06);
}

.loc-shot:focus-visible {
  outline: 2px solid var(--gold-deep);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .loc-shot img { transition: none; }
  .loc-shot:hover img,
  .loc-shot:focus-visible img { transform: none; }
}

/* Under ~520px three across leaves ~96px thumbnails, which is too small to
   read a room in. Two across gives back half the width again. */
@media (max-width: 520px) {
  .loc-shots { grid-template-columns: repeat(2, 1fr); }
}

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

/* A <dialog> rather than a hand-rolled overlay: showModal() gives the focus
   trap, the inert background and Escape-to-close for free, and the ::backdrop
   pseudo-element means no extra scrim element in the markup. */

.lightbox {
  border: none;
  padding: 0;
  background: transparent;
  /* The UA centers a modal dialog with margin:auto against inset:0. The site's
     reset zeroes margins on everything, which pins it to the top-left corner
     instead, so the centring is restored explicitly here. */
  margin: auto;
  max-width: min(94vw, 1200px);
  max-height: 94vh;
  overflow: visible;
  color: var(--paper);
}

.lightbox::backdrop {
  background: rgba(12, 14, 22, 0.9);
}

.lightbox img {
  display: block;
  margin: 0 auto;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 88vh;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
}

.lightbox-close {
  position: absolute;
  top: -2.75rem;
  right: 0;
  width: 2.25rem;
  height: 2.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(247, 244, 239, 0.35);
  background: transparent;
  color: rgba(247, 244, 239, 0.85);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.2s, color 0.2s;
}

.lightbox-close:hover,
.lightbox-close:focus-visible {
  border-color: var(--gold);
  color: var(--gold);
}

/* On a phone there is no room above the image for the close control, so it
   sits inside the top-right corner of the frame instead. */
@media (max-width: 600px) {
  .lightbox-close {
    top: 0.5rem;
    right: 0.5rem;
    background: rgba(12, 14, 22, 0.65);
  }
}

/* ============================================================== 20
   HOMEPAGE LOCATION CARDS — PARITY

   The two cards were already identical in treatment, but the front page only
   ever showed one of the two rooms: every photograph on it was North Hills.
   Each card now carries a photograph of its own studio and a link through to
   its own location page, which neither had.

   Every selector here is scoped to .locations-grid on purpose. The bare
   .location-card class is shared with the "Also serving ..." block at the
   bottom of both location pages, which has a different internal structure and
   must not pick these up.

   Parity is the whole point of this section, so the photograph sits in a fixed
   16:9 box with object-fit rather than flowing at its own ratio. The two
   photographs are both 3:2 today, but a future replacement of a different
   shape must not make one card taller than the other.

   What is deliberately NOT equalised: Canonsburg keeps "By appointment only"
   and a tel: call-to-action, because it is genuinely appointment-only and a
   Phorest link would send people to the wrong booking system.
   ------------------------------------------------------------------------ */

.locations-grid .location-shot {
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  margin-bottom: 2.25rem;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(184, 154, 106, 0.15);
}

.locations-grid .location-shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.locations-grid .location-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.5rem;
  margin-top: 2rem;
}

/* The button carries its own top margin in the page's stylesheet; inside the
   flex row that would push it out of line with the link beside it. */
.locations-grid .location-cta {
  margin-top: 0;
}

.locations-grid .location-view {
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--gold);
  text-decoration: none;
  padding-bottom: 0.3rem;
  border-bottom: 1px solid rgba(184, 154, 106, 0.45);
  transition: color 0.2s, border-color 0.2s;
}

.locations-grid .location-view:hover,
.locations-grid .location-view:focus-visible {
  color: var(--gold-light);
  border-bottom-color: var(--gold-light);
}

/* Stacked cards on a phone: the two actions sit on one line if they fit and
   wrap cleanly if they do not, and the photograph loses a little height so the
   card does not become a scroll of its own. */
@media (max-width: 600px) {
  .locations-grid .location-shot {
    aspect-ratio: 3 / 2;
    margin-bottom: 1.75rem;
  }
  .locations-grid .location-actions {
    gap: 1.25rem;
  }
}

/* Below ~380px "North Hills, Pittsburgh" wraps to two lines while "Canonsburg"
   stays on one, and that is the single place the two cards stop matching —
   everything else in them (photograph, eyebrow, address block, actions) is
   already identical to the pixel. Reserve the second line on both. */
@media (max-width: 380px) {
  .locations-grid .location-name {
    min-height: 2.45em;
  }
}

/* ============================================================== 21
   MEET THE TEAM — WHICH STUDIO EACH STYLIST WORKS AT

   Every card states, beside the stylist's name, where that stylist works. One
   of exactly three strings:

       North Hills only
       Canonsburg only
       North Hills / Canonsburg

   This replaced an earlier plan for a gold outline plus a key. Stating the
   fact is better than encoding it in a color: there is no key to have missed,
   nothing to misread if you cannot separate gold from the card edge, nothing
   extra for a screen reader, and — the point the owner actually cared about —
   a stylist who works at both can no longer be mistaken for Canonsburg-only.

   TO ASSIGN A STYLIST: add data-studio to their .team-card in
   meet-the-team/index.html, with one of three values:

       data-studio="north-hills"   ->  North Hills only
       data-studio="canonsburg"    ->  Canonsburg only
       data-studio="both"          ->  North Hills / Canonsburg

   That is the whole edit. The visible string is generated from the attribute,
   so the wording lives here and only here, and nothing has to be kept in step
   across 37 cards.

   EVERY CARD NEEDS ONE. A card with no data-studio renders no label at all —
   it makes no claim, which is correct while the assignments are unknown, but
   it also means the page is unfinished until all 37 carry one. To list what is
   still missing:

     grep -c 'class="team-card"' meet-the-team/index.html   # total
     grep -c 'data-studio'       meet-the-team/index.html   # assigned

   AS OF THIS COMMIT NO CARD IS ASSIGNED. The owner is identifying who works
   where. Do not treat this page as finished until those two counts match.

   Why the text comes from CSS rather than being written into each card: the
   attribute is then the single source of truth and the wording is in one
   place. The cost is that the label is not selectable or machine-translatable,
   and would vanish if the stylesheet failed to load. That trade is worth
   revisiting once the build pass can be run again — at that point optimize.py
   can write the same three strings into the markup from the same attribute,
   and these rules become the fallback rather than the source.
   ------------------------------------------------------------------------ */

/* The label sits AFTER .team-card-role in the source and is placed by CSS.
   That ordering is not cosmetic: TEAM_CARD in optimize.py requires the name
   element to be followed by the role element with only whitespace between
   them, and it builds the roster ItemList off that match. Anything inserted
   between the two — including a wrapper around the name — silently empties the
   roster schema. Leave the source order alone and let the grid do the placing.

   Default is the label on its own line under the name. Beside the name, which
   is where it was asked for, only applies from 1100px up. Below that a card's
   text column is genuinely too narrow to share: at 1024 it is about 170px, and
   putting "North Hills / Canonsburg" next to "Caroline Radziminski" there
   squeezed the name to 42px and six lines. */
.team-card-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "name"
    "studio"
    "role"
    "bio"
    "link";
  align-content: center;
}

.team-card-name   { grid-area: name; }
.team-card-studio { grid-area: studio; }
.team-card-role   { grid-area: role; }
.team-card-bio    { grid-area: bio; }
.team-card-content .link-arrow {
  grid-area: link;
  justify-self: start;
}

.team-card-studio {
  margin: 0.15rem 0 0.6rem;
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 400;
  line-height: 1.6;
  color: var(--mid);
}

/* It sits under the name rather than beside it, and that is a deliberate
   climb-down from where it was asked for. The card's text column is 258px at
   1440 and 170px at 1024 — the grid keeps two cards per row down to 900px, so
   the column never gets wider than that. "Caroline Radziminski" alone is about
   190px set at 1.5rem Cormorant. Beside the name, the longest label broke that
   name across three lines at 1440 and six at 1024. One line down, full width,
   it is legible at every size and no name is ever squeezed.

   If the right-hand position matters more than the name setting, the place
   with room is beside .team-card-role — "Stylist" is short — which is a swap
   of two grid-area names, not a rebuild. */


/* The three strings are assembled from four spans that ship on every card, so
   the attribute still drives everything and the visible words are real text —
   selectable, translatable, and present whether or not this stylesheet loads.
   The spacing lives inside the spans (" / ", " only"), so hiding a part hides
   its spacing with it and no stray gaps survive.

       north-hills  ->  North Hills only
       canonsburg   ->  Canonsburg only
       both         ->  North Hills / Canonsburg
*/
.team-card-studio > span { display: none; }

.team-card[data-studio="north-hills"] .studio-nh,
.team-card[data-studio="north-hills"] .studio-only,
.team-card[data-studio="canonsburg"]  .studio-cb,
.team-card[data-studio="canonsburg"]  .studio-only,
.team-card[data-studio="both"]        .studio-nh,
.team-card[data-studio="both"]        .studio-sep,
.team-card[data-studio="both"]        .studio-cb {
  display: inline;
}

/* A card with no data-studio makes no claim and takes no space. Once every
   stylist is assigned this should never match — it is the guard, not a state
   the finished page is meant to be in. */
.team-card:not([data-studio]) .team-card-studio {
  display: none;
}

/* Color is reinforcement here, not the carrier of meaning — the words say it
   outright — so this is purely a legibility question, and both tones clear AA
   for normal text on all three card grounds:

       --ink  #1A2440   15.33:1 on white, 14.57 on off-white, 13.38 on cream
       --gold #866336    5.45:1 on white,  5.18 on off-white,  4.76 on cream

   --gold rather than --gold-fill #b08d57, which is the brand gold for grounds
   and buttons and manages only 3.09:1 as text. The palette already draws that
   line; see the note on the tokens above. The separator and the word "only"
   stay in the label's own --mid (6.38:1), so the two studio names are the only
   colored words and the grammar around them recedes. */
.studio-nh { color: var(--ink); font-weight: 500; }
.studio-cb { color: var(--gold); font-weight: 500; }

/* -------------------------------------------------- the same label, on a
   stylist's own page.

   Same markup, same attribute, same three strings, and — after checking — the
   same colors as the card.

   The trap here: the stylist page's own inline stylesheet says
   .hero { background: var(--black) } with the name in --off-white, which reads
   as a dark panel. It is not one. Section 7 of this file re-points it:

       .hero, .derek-hero { background: var(--paper-warm); }

   and .page-eyebrow is forced to --gold-deep a few lines later. The hero
   actually renders #fbf9f5 with a navy name and a gold title, so the card's
   tones are the correct ones and a light-on-dark treatment would have been
   invisible. Measured on the real ground rather than the declared one:

       --ink  #1A2440  (North Hills)        14.57:1 on #fbf9f5
       --gold #866336  (Canonsburg)          5.18:1
       --mid  #565F75  (slash and "only")    6.07:1

   Those colors come from the shared .studio-nh / .studio-cb rules above, so
   there is nothing to override here — only the block's own placement.

   Position: directly under the name, above the italic .title line, so the hero
   reads name → studio → title and the studio sits in the same relation to the
   name as it does on the roster card. Not beside the name: the name is set at
   clamp(3rem, 5vw, 5.5rem) and several run to two lines, so there is no
   right-hand space to put it in.
   ------------------------------------------------------------------------ */

.page-studio {
  margin: -0.5rem 0 1.25rem;
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 400;
  line-height: 1.6;
  color: var(--mid);
}

.page-studio > span { display: none; }

.hero[data-studio="north-hills"] .studio-nh,
.hero[data-studio="north-hills"] .studio-only,
.hero[data-studio="canonsburg"]  .studio-cb,
.hero[data-studio="canonsburg"]  .studio-only,
.hero[data-studio="both"]        .studio-nh,
.hero[data-studio="both"]        .studio-sep,
.hero[data-studio="both"]        .studio-cb {
  display: inline;
}

@media (max-width: 600px) {
  .page-studio {
    margin: -0.25rem 0 1rem;
    font-size: 0.64rem;
  }
}

/* Caveat under an hours grid. Monday at North Hills runs with limited staff;
   that belongs with the hours but not inside them — a longer string in a
   .hours-time cell reads as a correction to the time rather than a note about
   the day, and the grid is meant to be scannable. Outside the grid it also
   cannot affect the day/time column alignment at any width. */
.hours-note {
  margin: 0.9rem 0 0;
  font-size: 0.75rem;
  line-height: 1.7;
  color: var(--mid);
  font-weight: 300;
}

/* ============================================================== 22
   GALLERY HERO — THE LINK OUT TO INSTAGRAM

   The gallery is a curated set and got a good deal smaller when fourteen
   photographs came out of it. Instagram is where the volume is and where the
   salon actually posts, so the empty half of the hero beside the headline
   earns its keep as a link out rather than being filled with more tiles.

   THE GROUND IS LIGHT, NOT DARK. The page's own stylesheet says
   .page-hero { background: var(--black) } and colours the headline
   --off-white. Section 9 of this file overrides both: the hero renders as a
   cream-to-paper gradient with a navy headline and a --gold-deep italic, and
   the override is !important. Colours here are measured against the real
   ground, top and bottom of the gradient:

       --gold-deep #7a5b31  the mark      5.44:1 / 5.93:1
       --mid       #565F75  the sentence  5.57:1 / 6.07:1
       --gold      #866336  the handle    4.76:1 / 5.18:1

   All clear AA for normal text, and the mark is a graphic rather than text so
   3:1 would have been enough for it.

   THE GLYPH is drawn here rather than pulled from an icon set, in the same
   idiom as the two icons the site already has in the mobile call bar: a
   24-unit grid, no fill, stroke: currentColor, round joins. It is the
   Instagram mark's geometry -- rounded square, concentric circle, offset dot
   -- not a copy of Meta's filled brand file. If exact brand compliance is
   ever wanted, replace the three shapes with the official asset from Meta's
   brand resources and drop the stroke rules; nothing else has to change.
   ------------------------------------------------------------------------ */

/* SCOPED TO .hero-split, AND IT MUST STAY THAT WAY.

   .page-hero-inner is a site-wide class: twenty pages use it, and on
   nineteen of them the breadcrumb, eyebrow, h1 and intro are its direct
   children with no wrapper. Making the bare class a flex row turned those
   four into four narrow columns side by side. It looked far worse than a
   normal flex accident because site.css already sets overflow-wrap: anywhere
   on every h1 and p: `anywhere` (unlike `break-word`) also shrinks an
   element's min-content contribution, so the columns collapsed past the
   longest word and "transformation" broke across two lines mid-word.

   Only the gallery hero has a .page-hero-text wrapper and an .ig-card to sit
   beside it, so only the gallery hero carries .hero-split. Any future hero
   that wants two columns needs the wrapper AND the class -- never the bare
   .page-hero-inner. */

@media (min-width: 901px) {
  .page-hero-inner.hero-split {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 3rem;
  }

  .hero-split .page-hero-text { flex: 1 1 auto; min-width: 0; }

  .hero-split .ig-card {
    flex: 0 0 auto;
    align-items: flex-end;
    text-align: right;
    max-width: 20rem;
    padding-bottom: 0.25rem;
  }
}

.ig-card {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  text-decoration: none;
  margin-top: 2.5rem;
}

/* Large, as asked, but still a step below a headline that runs to 5rem. */
.ig-mark {
  width: 3.5rem;
  height: 3.5rem;
  fill: none;
  stroke: var(--gold-deep);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: stroke 0.2s, transform 0.2s;
}

.ig-mark-dot {
  fill: var(--gold-deep);
  stroke: none;
  transition: fill 0.2s;
}

.ig-copy {
  font-size: 0.85rem;
  line-height: 1.7;
  font-weight: 300;
  color: var(--mid);
}

.ig-handle {
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--gold);
}

.ig-card:hover .ig-mark,
.ig-card:focus-visible .ig-mark {
  stroke: var(--gold);
  transform: translateY(-2px);
}

.ig-card:hover .ig-mark-dot,
.ig-card:focus-visible .ig-mark-dot { fill: var(--gold); }

.ig-card:hover .ig-handle,
.ig-card:focus-visible .ig-handle { color: var(--gold-deep); }

.ig-card:focus-visible {
  outline: 2px solid var(--gold-deep);
  outline-offset: 6px;
}

@media (prefers-reduced-motion: reduce) {
  .ig-mark { transition: stroke 0.2s; }
  .ig-card:hover .ig-mark,
  .ig-card:focus-visible .ig-mark { transform: none; }
}

/* Stacked under the headline on a phone, left-aligned with it, and with room
   above the filter row so the two do not read as one block. */
@media (max-width: 900px) {
  .ig-card {
    align-items: flex-start;
    text-align: left;
    margin-top: 2rem;
    max-width: 22rem;
  }
  .ig-mark { width: 2.75rem; height: 2.75rem; }
}

/* Group headings on /meet-the-team: Hair, Skin, Nails.

   Reuses .section-label rather than introducing a third heading size — the
   page already has one big .section-headline over the whole section, and three
   more at that weight would compete with it, especially above groups of one
   and two. Carried on an h3 so the grouping is in the document outline and not
   only in the type.

   The ItemList on this page is scraped off the rendered cards by TEAM_CARD in
   optimize.py, which runs name -> role -> the next /team/ href. These headings
   sit BETWEEN cards, outside that match, so they do not disturb it — verified
   at 38 matches with the headings in place. Keep any future heading outside a
   .team-card and it stays true. */
.team-group {
  margin: 3.5rem 0 1.25rem;
}

.team-group:first-of-type {
  margin-top: 0;
}

@media (max-width: 600px) {
  .team-group { margin: 2.5rem 0 1rem; }
  .team-group:first-of-type { margin-top: 0; }
}

/* ============================================================== 23
   GALLERY — THE FILTER ROW IS GONE, AND INSTAGRAM IS THE POINT

   1. SPACING. The filter row used to carry 114px of air between the hero and
      the grid: its own 2.5rem top padding, 74px of buttons, then .gallery-main's
      2.5rem. With the row gone only that last 2.5rem remains and the grid rides
      up under the hero. The padding is restored here rather than in the page's
      own stylesheet so that uncommenting the row later means deleting one rule,
      not hunting for a number.
   ------------------------------------------------------------------------ */

.gallery-main {
  padding-top: 7rem;
}

@media (max-width: 900px) {
  .gallery-main { padding-top: 4rem; }
}

/* 2. THE CLOSING BAND.

      The page has two Instagram links now and that is deliberate. The one
      beside the headline is a signpost read before you look at anything; this
      one is the ask, read after. They say different things, which is what
      keeps two from reading as one repeated banner.

      Light --cream rather than dark: the booking CTA further down this page is
      already a dark centred band, and two of those in sequence read as a page
      that has run out of ideas. Cream also steps cleanly out of the white grid
      above and the off-white FAQ below, and lets the mark keep the same
      --gold-deep treatment it has in the hero.

      The mark is 88px here against 56px in the hero -- big enough to be the
      thing you notice on that screen, small enough to sit under a headline the
      page sets at 80px. Restraint is the site's whole character; this is not
      the place to put a 200px logo. */

.ig-band {
  background: var(--cream);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  padding: 6rem 4rem;
  text-align: center;
}

.ig-band-inner {
  max-width: 620px;
  margin: 0 auto;
}

.ig-band-mark {
  width: 5.5rem;
  height: 5.5rem;
  margin: 0 auto 2rem;
  display: block;
  fill: none;
  stroke: var(--gold-deep);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.ig-band .section-label {
  margin-bottom: 0.9rem;
}

.ig-band-headline {
  font-family: 'Cormorant Garamond', serif;
  font-size: clamp(2rem, 3.5vw, 2.9rem);
  font-weight: 300;
  line-height: 1.15;
  color: var(--ink);
  margin: 0 0 1.25rem;
}

.ig-band-headline em {
  font-style: italic;
  color: var(--gold-deep);
}

.ig-band-copy {
  font-size: 0.9rem;
  line-height: 1.85;
  font-weight: 300;
  color: var(--mid);
  margin: 0 0 2.5rem;
}

.ig-band .btn-primary {
  margin-top: 0;
}

/* The handle sits under the button as text, not as a second link: the button
   is the ask, and "@craftcollectivesalongroup" is one unbreakable 26-character
   token that blows past the button's box at 375px if you put it inside the
   control. As a line of its own it can shrink instead of overflowing. */
.ig-band-handle {
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--gold-deep);
  margin: 1.25rem 0 0;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .ig-band { padding: 4.5rem 2rem; }
  .ig-band-mark { width: 4rem; height: 4rem; margin-bottom: 1.5rem; }
}

@media (max-width: 600px) {
  .ig-band { padding: 3.5rem 1.5rem; }
  .ig-band-mark { width: 3.5rem; height: 3.5rem; }
  .ig-band-copy { margin-bottom: 2rem; }
}
