/*
Theme Name: Key Element
Theme URI: https://www.keyelementacupuncture.com/
Author: Hayden DeMars
Description: Block theme for Key Element Acupuncture, Westminster CO. Generated from the hand-built static homepage by wp-theme/build-block-theme.mjs — do not edit these files directly, edit the source and rebuild.
Version: 1.0.0
Requires at least: 6.3
Tested up to: 7.1
Requires PHP: 7.4
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: key-element
*/

/* ===== GENERATED FILE — edit styles/*.css in the repo and rebuild ===== */

/* ---------- tokens.css ---------- */
:root {
  /* Brand — coral is reserved for calls to action only. */
  --coral: #F2A277;
  --coral-deep: #E08A5C;
  --teal: #1ABABA;
  /* --teal is 2.257:1 on --cream and 2.393:1 on --white, so it may only carry
     decoration that is aria-hidden and conveys nothing (.steps__num, the ::before
     quote glyph). Anything that INDICATES something — the +/- accordion state,
     the underline that marks a link as a link — is a non-text UI component under
     WCAG 2.1 SC 1.4.11 and needs 3:1. --teal-deep is the same hue, darkened to
     clear that floor on both grounds: 3.944:1 on --cream, 4.181:1 on --white. */
  --teal-deep: #0F8A8A;
  --ink: #2A2421;
  --navy: #110A2B;
  --slate: #53728C;
  --cream: #FAF8F5;
  --white: #FFFFFF;

  /* Jost stands in for the site's Futura LT, which is licensed to Wix.
     Literata is the reading face: warm, low-contrast, and built for screens.
     A geometric display over a serif text face is the premium-clinical
     pairing; the generic humanist sans it replaces read as "no typeface was
     chosen at all". (Naming that face here would trip the check in check.mjs,
     which greps the whole stylesheet for it — deliberately blunt.) */
  --font-display: "Jost", "Futura", "Century Gothic", sans-serif;
  --font-body: "Literata", Georgia, "Times New Roman", serif;

  /* One easing curve for the whole site. Every transition references this so
     the hand-written `ease` and `cubic-bezier` values cannot drift apart again. */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* A barely perceptible tooth on the cream ground — flat off-white is the
     tell of a template. Sub-1% effective darkening; it should read as paper,
     never as texture. Applied to `body` and `.section--cream` only, because
     `.section--white` is deliberately the flat, clinical ground. */
  --grain: radial-gradient(rgba(42, 36, 33, 0.045) 0.5px, transparent 0.5px);
  --grain-size: 3px 3px;

  --measure: 68ch;
  --radius: 14px;
  --shadow: 0 12px 32px rgba(42, 36, 33, 0.09);
  --shadow-lift: 0 20px 44px rgba(42, 36, 33, 0.14);
  --space-section: clamp(4.5rem, 9vw, 8rem);
  --container: 1180px;
}

/* ---------- base.css ---------- */
*, *::before, *::after { box-sizing: border-box; }

/* The mobile nav panel is `position: fixed` and `translateX(100%)` when closed
   (sections.css, .js-motion .nav__panel). A fixed box parked past the right
   edge still counts toward the document's scrollable width in Chrome: every
   viewport <=900px measured documentElement.scrollWidth at exactly 2x
   innerWidth, and scrollTo(9999, 0) panned a whole screen into blank space.

   BOTH elements have to be listed, and this is the part that has now been got
   wrong twice. CSS propagates the root element's overflow to the viewport and
   leaves the root itself `visible`; if the root is `visible`, the *body's*
   value is propagated instead and body's used value becomes `visible`. So a
   rule on one element alone is always a no-op — whichever one you pick, its
   value is taken away to the viewport and the element itself stops clipping.
   Measured at 360px, scrollWidth against a 360px viewport:

     html          body          scrollWidth
     visible       visible       720   (no rule at all)
     visible       clip          720   <- body alone: no-op
     clip          visible       720   <- html alone: no-op, the original bug
     clip          clip          360   <- this rule

   getComputedStyle reports body as `clip` in the no-op rows, because that is
   the computed value and the propagation happens at used-value time. Do not
   trust it here; measure scrollWidth.

   `clip` rather than `hidden` because `hidden` makes the box a scroll
   container, which would put `position: sticky` descendants at risk;
   `clip` creates no scroll container, and .site-header and .faq__head were
   measured still computing `sticky` with the header pinned at top: 0.
   Needs Chrome 90+, Firefox 81+, Safari 16+ — see README. */
html, body { overflow-x: clip; }

/* Serifs set optically larger than a humanist sans at the same pixel size, so
   the scale drops from 1/1.125rem to 0.98/1.05rem to hold the same apparent
   x-height. `-webkit-font-smoothing: antialiased` is deliberately NOT set:
   it thins strokes on macOS, which costs a serif the apparent weight it needs
   at text sizes — the one thing this change could not afford to lose. */
body {
  margin: 0;
  background-color: var(--cream);
  background-image: var(--grain);
  background-size: var(--grain-size);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: clamp(0.98rem, 0.3vw + 0.92rem, 1.05rem);
  line-height: 1.68;
  font-optical-sizing: auto;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; height: auto; display: block; }

a { color: inherit; }

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 300;
  line-height: 1.1;
  letter-spacing: -0.015em;
  margin: 0 0 0.5em;
  /* No heading may drop a single orphan word onto its last line. */
  text-wrap: balance;
}

p { margin: 0 0 1.15em; max-width: var(--measure); text-wrap: pretty; }

/* Large geometric type needs more negative tracking than the global -0.015em
   — at 4rem, Jost's default fitting reads loose and unset. */
.display {
  font-size: clamp(2.4rem, 5.2vw, 4.1rem);
  letter-spacing: -0.025em;
}

/* Chrome — eyebrows, nav, buttons, captions — is set in the display face.
   Reading text is the serif. Uppercase at 0.8rem with 0.18em tracking muddies
   in a serif; Jost is drawn for exactly this treatment. 500 rather than 600
   because only Literata 400/500 are loaded and nothing should synthesise. */
.eyebrow {
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--slate);
  margin: 0 0 1rem;
}

/* 1.22em rather than 1.15em: the base dropped, and the lede should hold the
   same absolute size it had before. Larger text carries tighter leading. */
.lede {
  font-size: 1.22em;
  line-height: 1.55;
  color: color-mix(in srgb, var(--ink) 82%, transparent);
}

/* Focus indicator. WCAG 2.1 SC 1.4.11 requires 3:1 for focus indicators, and
   the previous all-teal ring measured 2.257:1 on --cream — it failed against
   the ground it appears on most often. --ink is the load-bearing colour
   (14.431:1 on --cream, 15.298:1 on --white); the teal halo is decoration that
   keeps the ring recognisably this site's. Nothing here transitions. */
:where(a, button, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--teal) 30%, transparent);
  border-radius: 4px;
}

/* The footer ground is --navy, against which --ink is 1.246:1 — the default
   ring would be all but invisible in exactly the place a keyboard user reaches
   last. --cream on --navy is 17.974:1. Only the load-bearing colour is
   swapped; the halo and geometry carry over. */
.site-footer :where(a, button, summary, [tabindex]):focus-visible {
  outline-color: var(--cream);
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* The skip link is the page's FIRST tab stop, and it carries .visually-hidden.
   Without this rule the focus ring is painted — around the clipped 1x1px box
   at top: -1, left: -1 — so the very first thing a keyboard user reaches has
   no visible focus indicator at all (WCAG 2.1 SC 2.4.7, AA).
   Every clipping declaration above has to be undone, not just `width`/`height`:
   `clip` and `clip-path` would still collapse it to nothing.
   z-index sits above .site-header's 100 (sections.css) so the link is not
   painted underneath the sticky header it is meant to skip past. */
.visually-hidden:focus-visible {
  position: fixed; top: 0.75rem; left: 0.75rem;
  width: auto; height: auto; margin: 0;
  padding: 0.75rem 1.25rem; overflow: visible;
  clip: auto; clip-path: none;
  background: var(--cream); color: var(--ink);
  border-radius: var(--radius); z-index: 200;
}

/* ---------- layout.css ---------- */
.container {
  width: min(100% - 2.5rem, var(--container));
  margin-inline: auto;
}

.section { padding-block: var(--space-section); }

/* A section background paints over the body's, so the grain has to be
   restated here or it would vanish inside every .section--cream band. */
.section--cream {
  background-color: var(--cream);
  background-image: var(--grain);
  background-size: var(--grain-size);
}
.section--white { background: var(--white); }

/* Buttons — text on coral is --ink. White would fail WCAG AA at ~1.8:1. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.95rem 1.9rem;
  border: 2px solid transparent;
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 200ms var(--ease), border-color 200ms var(--ease),
              transform 200ms var(--ease), box-shadow 200ms var(--ease);
}

.btn--primary { background: var(--coral); color: var(--ink); }
.btn--primary:hover { background: var(--coral-deep); transform: translateY(-2px); box-shadow: var(--shadow); }

.btn--ghost { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--cream); transform: translateY(-2px); }

.card {
  background: var(--white);
  border: 1px solid color-mix(in srgb, var(--slate) 22%, transparent);
  border-radius: var(--radius);
  padding: clamp(1.5rem, 3vw, 2.25rem);
  transition: transform 260ms var(--ease), box-shadow 260ms var(--ease);
}

/* ---------- sections.css ---------- */
/* sections.css — per-section styles. Populated by later tasks. */

/* ---------- Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: color-mix(in srgb, var(--cream) 92%, transparent);
  backdrop-filter: blur(10px);
  transition: box-shadow 260ms var(--ease);
  padding-block: 1.25rem;
}

.site-header.is-stuck {
  padding-block: 0.65rem;
  box-shadow: 0 1px 0 color-mix(in srgb, var(--slate) 28%, transparent), var(--shadow);
}

.site-header__inner { display: flex; align-items: center; gap: 1.5rem; }
.site-header__brand { margin-right: auto; }
.site-header__brand img { width: 150px; height: auto; }

.nav__panel { display: flex; align-items: center; gap: 1.75rem; }
.nav__list {
  display: flex; gap: 1.5rem;
  list-style: none; margin: 0; padding: 0;
}
/* Navigation is chrome, not reading text — it stays in the display face so the
   serif is reserved for prose. */
.nav__list a {
  font-family: var(--font-display);
  text-decoration: none;
  font-size: 0.98rem;
  letter-spacing: 0.005em;
  position: relative;
  padding-block: 0.25rem;
}
.nav__list a::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 100%; height: 2px; background: var(--teal);
  transform: scaleX(0); transform-origin: left;
  transition: transform 240ms var(--ease);
}
.nav__list a:hover::after { transform: scaleX(1); }

.nav__phone {
  font-family: var(--font-display);
  text-decoration: none;
  font-weight: 500;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.nav__toggle {
  display: none;
  width: 46px; height: 46px;
  background: none; border: 0; cursor: pointer;
  position: relative;
}
.nav__bars, .nav__bars::before, .nav__bars::after {
  position: absolute; left: 11px; width: 24px; height: 2px;
  background: var(--ink); transition: transform 240ms var(--ease), opacity 240ms var(--ease);
}
.nav__bars { top: 22px; }
.nav__bars::before { content: ""; transform: translateY(-7px); left: 0; }
.nav__bars::after  { content: ""; transform: translateY(7px); left: 0; }

.nav__toggle[aria-expanded="true"] .nav__bars { background: transparent; }
.nav__toggle[aria-expanded="true"] .nav__bars::before { transform: rotate(45deg); }
.nav__toggle[aria-expanded="true"] .nav__bars::after  { transform: rotate(-45deg); }

@media (max-width: 900px) {
  .nav__toggle { display: block; }
  .nav__panel {
    flex-direction: column; justify-content: center;
    gap: 2rem; background: var(--cream);
  }
  .nav__list { flex-direction: column; text-align: center; gap: 1.25rem; }
  .nav__list a { font-size: 1.25rem; }

  /* With JS enabled, apply off-canvas overlay and transform animations.
     `visibility` rides along with the transform (delayed on close, instant on
     open) so the panel's links drop out of tab order while off-canvas —
     without it, closed-menu links stay focusable and a keyboard user tabs
     into invisible off-screen targets with no visible focus ring. */
  .js-motion .nav__panel {
    position: fixed; inset: 0;
    transform: translateX(100%);
    visibility: hidden;
    transition: transform 320ms var(--ease), visibility 0s 320ms;
  }
  .js-motion .nav__panel.is-open {
    transform: none;
    visibility: visible;
    transition: transform 320ms var(--ease), visibility 0s;
  }
}

/* ---------- Hero ---------- */
.hero { padding-block: clamp(3rem, 7vw, 6rem) var(--space-section); overflow: hidden; }

.hero__inner {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  align-items: center;
  gap: clamp(2rem, 6vw, 5rem);
}

.hero__copy .lede { max-width: 34ch; }

.hero__actions { display: flex; flex-wrap: wrap; gap: 1rem; margin-top: 2rem; }

/* Shared framed-image treatment. Task 9's .about__media joins this list. */
.hero__media,
.feature__media,
.about__media {
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-lift);
  aspect-ratio: 4 / 5;
}

.hero__media img,
.feature__media img,
.about__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Hero only: oversized so the parallax translation never exposes an edge.
   The 1.12 here is tied to the BUFFER constant in js/parallax.js. */
.hero__media img {
  scale: 1.12;
  will-change: transform;
}

@media (max-width: 860px) {
  .hero__inner { grid-template-columns: 1fr; }
  .hero__media { aspect-ratio: 3 / 2; order: -1; }
}

/* ---------- Trust bar ---------- */
.trust { padding-block: clamp(2.5rem, 5vw, 3.75rem); }

.trust__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
}

.trust__item { display: flex; flex-direction: column; gap: 0.4rem; }

.trust__figure {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 2.6vw, 2.25rem);
  font-weight: 300;
  line-height: 1;
  color: var(--ink);
}

.trust__label {
  font-size: 0.9rem;
  color: var(--slate);
  line-height: 1.45;
}

@media (max-width: 780px) {
  .trust__grid { grid-template-columns: repeat(2, 1fr); }
}

/* ---------- Qualify ----------
   Deliberately NOT cards. Two stacked card grids — qualify, then services — is
   the most templated shape on the modern web; stripping the box here leaves
   cards surviving only in the services grid, where they then read as a choice
   rather than a default. Type and whitespace carry these three instead: a
   larger question in the display face, the answer beneath in --slate, and a
   hairline rule standing in for the border. */
.qualify__head { max-width: 16ch; }

.qualify__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(2.25rem, 4vw, 3.5rem);
  margin-top: clamp(3rem, 6vw, 4.5rem);
}

.qualify__item {
  padding-top: 1.6rem;
  border-top: 1px solid color-mix(in srgb, var(--slate) 32%, transparent);
}

.qualify__item h3 {
  font-size: clamp(1.3rem, 1.9vw, 1.55rem);
  margin-bottom: 0.85rem;
}
.qualify__item p { margin: 0; color: var(--slate); }

.qualify__note { margin-top: clamp(3rem, 6vw, 4.5rem); max-width: 52ch; }

/* ---------- Services ---------- */
.services__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
  margin-top: 3rem;
}

.service-card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  position: relative;
}

.service-card h3 { font-size: 1.3rem; margin-bottom: 0.4rem; }
.service-card p { color: var(--slate); margin: 0 0 1.75rem; }

.service-card__go {
  margin-top: auto;
  color: var(--teal);
  font-size: 1.35rem;
  transition: transform 240ms var(--ease);
}

.service-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lift); }
.service-card:hover .service-card__go { transform: translateX(6px); }

@media (max-width: 900px) {
  .qualify__grid, .services__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .qualify__grid, .services__grid { grid-template-columns: 1fr; }
}

/* ---------- Featured microneedling ---------- */
/* The tint is 5%, not 7%. At 7% the top stop is rgb(234,244,241), against which
   --slate text (the eyebrow, .price-tier__count) measures 4.497:1 — it misses
   WCAG AA by three thousandths. 5% gives rgb(239,245,242) and 4.573:1. The two
   tints are visually indistinguishable; only one of them passes. --slate itself
   cannot be darkened, as check.mjs pins it to #53728C. */
.feature {
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--teal) 5%, var(--cream)) 0%,
      var(--cream) 100%);
}

.feature__inner {
  display: grid;
  grid-template-columns: 1fr 0.85fr;
  gap: clamp(2rem, 6vw, 4.5rem);
  align-items: center;
}

.feature__pricing {
  list-style: none;
  margin: 2.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 0;
  max-width: 30rem;
}

.price-tier {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding-block: 0.9rem;
  border-bottom: 1px solid color-mix(in srgb, var(--slate) 30%, transparent);
}
.price-tier:first-child { border-top: 1px solid color-mix(in srgb, var(--slate) 30%, transparent); }

.price-tier__count { color: var(--slate); font-size: 0.95rem; }
.price-tier__price {
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 300;
  font-variant-numeric: tabular-nums;
}

.feature__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.5rem;
  margin-top: 2.25rem;
}

/* The border-bottom is the sole affordance marking this a link, so it is a
   non-text UI component: --teal-deep, not --teal (2.257:1 on cream). */
.feature__link {
  font-weight: 500;
  text-decoration: none;
  border-bottom: 2px solid var(--teal-deep);
  padding-bottom: 2px;
  transition: border-bottom-color 200ms var(--ease);
}
.feature__link:hover { border-bottom-color: var(--ink); }

@media (max-width: 860px) {
  .feature__inner { grid-template-columns: 1fr; }
  .feature__media { aspect-ratio: 3 / 2; }
}

/* ---------- How it works ---------- */
.steps__line {
  display: block;
  width: 100%;
  height: 60px;
  margin-top: 2.5rem;
  overflow: visible;
}

.steps__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
}

.steps__num {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(3rem, 6vw, 4.75rem);
  font-weight: 300;
  line-height: 1;
  color: color-mix(in srgb, var(--teal) 55%, var(--cream));
  margin-bottom: 0.5rem;
}

.steps__item h3 { font-size: 1.2rem; }
.steps__item p { color: var(--slate); margin: 0; }

@media (max-width: 780px) {
  .steps__grid { grid-template-columns: 1fr; }
  .steps__line { display: none; }
}

/* ---------- About ---------- */
.about__inner {
  display: grid;
  grid-template-columns: 0.85fr 1fr;
  gap: clamp(2rem, 6vw, 4.5rem);
  align-items: center;
}

@media (max-width: 860px) {
  .about__inner { grid-template-columns: 1fr; }
  .about__media { aspect-ratio: 3 / 2; }
}

/* ---------- Testimonials ---------- */
.testimonials__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(2rem, 5vw, 3.5rem);
  margin-top: 3rem;
}

.quote { margin: 0; }

.quote blockquote { margin: 0; position: relative; padding-top: 2.25rem; }

.quote blockquote::before {
  content: "\201C";
  position: absolute;
  top: -0.75rem;
  left: -0.25rem;
  font-family: var(--font-display);
  font-size: 5rem;
  line-height: 1;
  color: color-mix(in srgb, var(--teal) 45%, transparent);
}

.quote blockquote p {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.9vw, 1.6rem);
  font-weight: 300;
  line-height: 1.4;
  margin: 0;
}

.quote figcaption {
  margin-top: 1.5rem;
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--slate);
}
.quote cite { font-style: normal; }

@media (max-width: 860px) {
  .testimonials__grid { grid-template-columns: 1fr; }
}

/* ---------- FAQ ---------- */
.faq__inner {
  display: grid;
  grid-template-columns: 0.75fr 1fr;
  gap: clamp(2rem, 6vw, 4.5rem);
  align-items: start;
}

.faq__head { position: sticky; top: 7rem; }

.faq__item { border-bottom: 1px solid color-mix(in srgb, var(--slate) 30%, transparent); }
.faq__item:first-child { border-top: 1px solid color-mix(in srgb, var(--slate) 30%, transparent); }

.faq__item h3 { margin: 0; font-size: inherit; }

.faq__q {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.5rem;
  padding: 1.5rem 0;
  background: none;
  border: 0;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 1.6vw, 1.32rem);
  font-weight: 400;
  color: var(--ink);
}

.faq__icon {
  flex: 0 0 auto;
  width: 16px; height: 16px;
  position: relative;
}
/* The +/- is the graphical indicator of open/closed state, so SC 1.4.11 applies
   at 3:1. --teal was 2.257:1 on cream; --ink is 14.431:1 and reads as the same
   hairline mark. */
.faq__icon::before, .faq__icon::after {
  content: "";
  position: absolute;
  background: var(--ink);
  transition: transform 260ms var(--ease), opacity 260ms var(--ease);
}
.faq__icon::before { top: 7px; left: 0; width: 16px; height: 2px; }
.faq__icon::after  { left: 7px; top: 0; width: 2px; height: 16px; }

.faq__q[aria-expanded="true"] .faq__icon::after { transform: rotate(90deg); opacity: 0; }

/* `overflow: hidden` at height 0 hides the answer visually but leaves it in the
   accessibility tree: measured on the shipped page, #faq1 was height 0px,
   visibility: visible, innerText.length 274 — a screen reader announced all five
   panels collapsed and then read all five answers. `visibility` rides along with
   the height exactly as it does on .nav__panel above: delayed to the end of the
   close so the collapse is still seen, instant on open so the text is exposed
   before it animates in. The class is driven from js/accordion.js alongside
   aria-expanded, so the two can never disagree. */
.faq__a {
  overflow: hidden;
  height: 0;
  visibility: hidden;
  transition: height 300ms var(--ease), visibility 0s 300ms;
}
.faq__a.is-open {
  visibility: visible;
  transition: height 300ms var(--ease), visibility 0s;
}
.faq__a p { padding-bottom: 1.5rem; margin: 0; color: var(--slate); }

/* With JS disabled, every answer is open, readable AND exposed to assistive
   technology — the visibility default above must not survive into the no-JS
   fallback, or the answers would be silently unreadable instead of merely
   un-animated. */
html:not(.js-motion) .faq__a { height: auto; visibility: visible; }

@media (max-width: 860px) {
  .faq__inner { grid-template-columns: 1fr; }
  .faq__head { position: static; }
}

/* ---------- Location ---------- */
.locate__inner {
  display: grid;
  grid-template-columns: 0.85fr 1fr;
  gap: clamp(2rem, 6vw, 4.5rem);
  align-items: center;
}

.locate__address { font-style: normal; line-height: 1.9; margin-bottom: 1.5rem; }
/* Same reasoning as .feature__link: the underline is the only thing marking
   the phone/address links as links, so it must clear 3:1. */
.locate__address a { text-decoration: none; border-bottom: 1px solid var(--teal-deep); }

.locate__hours {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.35rem 1.5rem;
  margin: 0 0 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid color-mix(in srgb, var(--slate) 30%, transparent);
  font-size: 0.95rem;
}
.locate__hours dt { color: var(--slate); }
.locate__hours dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.locate__map {
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
  aspect-ratio: 4 / 3;
}
.locate__map iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ---------- Closing CTA ---------- */
.cta-band { text-align: center; }
.cta-band__inner { display: grid; justify-items: center; }
.cta-band .lede { margin-bottom: 2rem; }

/* ---------- Footer ---------- */
.site-footer {
  background: var(--navy);
  color: color-mix(in srgb, var(--cream) 88%, transparent);
  padding-block: clamp(3rem, 6vw, 4.5rem);
}

.site-footer__inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3rem;
}

.site-footer__name {
  font-family: var(--font-display);
  font-size: 1.4rem;
  margin-bottom: 0.75rem;
}

.site-footer address { font-style: normal; line-height: 1.9; margin-bottom: 1rem; }
.site-footer a { color: inherit; text-decoration: none; }
.site-footer a:hover { color: var(--teal); }

.site-footer__nav ul {
  font-family: var(--font-display);
  list-style: none; margin: 0; padding: 0;
  columns: 2; column-gap: 2rem;
  line-height: 2.1;
}
.site-footer__nav li { break-inside: avoid; }

@media (max-width: 860px) {
  .locate__inner, .site-footer__inner { grid-template-columns: 1fr; }
  .site-footer__nav ul { columns: 1; }
}

/* ---------- Service pages (WordPress page.php) ----------
   Not used by the static homepage. These style the block-editor content that
   the client edits, so service pages inherit the site's measure and rhythm
   instead of the theme defaults. Kept here rather than in a sixth stylesheet
   so the enqueue order in functions.php stays as it is. */
.page-body__head { margin-bottom: clamp(2rem, 4vw, 3rem); }

.page-body__content { max-width: var(--measure); }

.page-body__content > * + * { margin-top: 1.15em; }

.page-body__content h2 {
  font-size: clamp(1.7rem, 3vw, 2.4rem);
  margin-top: 2.5em;
}

.page-body__content h3 {
  font-size: clamp(1.2rem, 1.8vw, 1.45rem);
  margin-top: 2em;
}

.page-body__content ul,
.page-body__content ol { padding-left: 1.35em; }

.page-body__content li + li { margin-top: 0.5em; }

.page-body__content img,
.page-body__content .wp-block-image img {
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.page-body__content blockquote {
  margin: 2em 0;
  padding-left: 1.5em;
  border-left: 3px solid var(--teal);
  font-family: var(--font-display);
  font-size: 1.2em;
  font-weight: 300;
}

/* Wide and full-width blocks escape the measure without escaping the page. */
.page-body__content .alignwide { max-width: min(100%, 68rem); }
.page-body__content .alignfull { max-width: 100%; }

/* ---------- motion.css ---------- */
/* Content is visible by default. The .js-motion class is set by reveal.js,
   so a JavaScript failure leaves everything readable. */
.js-motion [data-reveal] {
  opacity: 0;
  transform: translateY(24px);
}

[data-reveal] {
  transition: opacity 600ms var(--ease),
              transform 600ms var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}

.js-motion [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .js-motion [data-reveal],
  .js-motion [data-reveal].is-revealed {
    opacity: 1;
    transform: none;
    transition: none;
  }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* Line motif — the path length is measured and set in JS. */
.steps__line path {
  transition: stroke-dashoffset 1600ms var(--ease);
}

@media (prefers-reduced-motion: reduce) {
  .steps__line path {
    stroke-dashoffset: 0 !important;
    transition: none;
  }
}


/* ---------- generated: image slots ----------
   The static build used <img data-replace="…">. Block templates cannot build a
   PHP asset URL, so each slot becomes a background here instead. When real
   photography arrives, upload it to the Media Library and swap these four
   url() values for the uploaded URLs — nothing else needs to change. */
.media {
  background-size: cover;
  background-position: center;
  width: 100%;
  height: 100%;
}
.media--hero          { background-image: url(assets/img/hero.svg); }
.media--microneedling { background-image: url(assets/img/microneedling.svg); }
.media--autumn-portrait { background-image: url(assets/img/autumn.svg); }

.site-header__brand .media--logo {
  background-image: url(assets/img/logo.svg);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: left center;
  width: 150px;
  height: 46px;
}

/* The hero slot previously relied on the <img> being oversized; with a
   background there is no element to scale, so the parallax budget comes from
   background-size instead. Keep the 112% in step with BUFFER in js/parallax.js. */
.hero__media .media--hero { background-size: 112% auto; }
