/* ============================================================
   MASTER: law-malmanlaw-static - concept preview by PXLNorth
   Parameterized from the operator-approved claritylawsk.com
   recreation of the malmanlaw blueprint (structure + density,
   scaled honestly to the prospect's real practice).

   TYPE PAIRING: the font custom properties + the Google Fonts
   link are content-driven (content.json `fonts`); the shipped
   default is the source build's pairing (Spectral display serif
   + Jost geometric sans). The tailor pass picks a pairing for
   each prospect's identity and documents the choice in the run.

   COLOUR: every slot below reads the fill-static `pro` palette.
   theme.json should pin the full scale via its `pro` object
   (see template.json note); the prospect's real site scheme
   drives surfaces, logo colors are accents only - no brand
   colour is ever a page canvas. Master-specific slots
   (brandDeep / accentOnDark / ink3 / heroPlate) fall back to derived
   standard keys when unpinned so no var ever renders empty.
   All alpha tints derive from the vars via color-mix, so the
   whole page re-themes from the palette alone.
   ============================================================ */

:root {
  --brand: #38546b;          /* deep brand, AA on white: buttons, links, eyebrows */
  --brand-deep: #2a3f50;  /* hover state of --brand */
  --accent: #407A81;        /* secondary brand accent - CTAs, rules */
  --accent-soft: #dfe3e4;  /* light accent for links/rules ON DARK surfaces */
  --dark: #192D3E;               /* deep slate band: hero, side card, conversion band */
  --dark-deep: #101B25;           /* footer + darkest overlays */

  /* SURFACE TEMPERATURE (presentation axis 2, `$presentation.temperatureMode: "css"`).
     The three canvases are mixed here rather than handed over pre-mixed, so the base
     values stay readable in the built stylesheet and one place owns the arithmetic.
     THE AMOUNT IS NOT A DESIGN CHOICE MADE IN CSS: fillStatic measures every ink this
     master paints on these grounds against 4.5:1 and walks the mix down until they all
     clear, so `--temp-amt` is whatever survived that guard (0% is a legitimate answer and
     is recorded in runs/<domain>/presentation.json with the pair that blocked it).
     Neutral mixes a base with itself, which is a no-op by construction. */
  --canvas-base: #ffffff;
  --canvas-soft-base: #F3F4F5;
  --canvas-sand-base: #EEEFF1;  /* the one warm band */
  --temp-tint: #B08256;
  --temp-amt: 5%;
  --canvas: color-mix(in srgb, var(--temp-tint) var(--temp-amt), var(--canvas-base));
  --canvas-soft: color-mix(in srgb, var(--temp-tint) var(--temp-amt), var(--canvas-soft-base));
  --canvas-sand: color-mix(in srgb, var(--temp-tint) var(--temp-amt), var(--canvas-sand-base));
  /* photo backing plate: paints behind the hero photo while it loads AND is the
     plate colour for composited landscape/group hero cutouts (template.json
     $artDirection). Master-specific extra; unpinned it falls back to the warm
     band surface so it never renders empty. */
  --photo-plate: #EEEFF1;

  --ink: #192124;
  --ink-2: #3a454b;
  /* ink-3 is the small-text grey. Pin it so it clears AA on the WARM band
     (--canvas-sand), the lightest surface it lands on; the source build's
     pin measured 5.09:1 there. Unpinned it falls back to --ink-2. */
  --ink-3: #5f6a70;
  /* Rule strength is the accent-discipline axis made visible on the page's structure:
     a reserved sub-niche gets hairlines, an assertive one gets rules you can see. */
  --line: color-mix(in srgb, var(--brand) 10%, transparent);
  --line-soft: color-mix(in srgb, var(--brand) 5%, transparent);

  --shadow-sm: 0 1px 2px color-mix(in srgb, var(--ink) 6%, transparent), 0 2px 8px color-mix(in srgb, var(--ink) 5%, transparent);
  --shadow-md: 0 14px 34px color-mix(in srgb, var(--ink) 13%, transparent);
  --shadow-lg: 0 26px 64px color-mix(in srgb, var(--ink) 22%, transparent);

  --serif: "Spectral", Georgia, "Times New Roman", serif;
  --sans: "Jost", system-ui, -apple-system, "Segoe UI", sans-serif;

  --wrap: 1240px;
  --gut: clamp(18px, 5vw, 44px);

  /* ---------- SUB-NICHE PRESENTATION MATRIX (TASTE_LEDGER #69) ----------
     Seven axes resolved per sub-niche from templates/variants/lawyer.json by
     orchestrator/src/lib/presentation.ts; the contract is docs/PRESENTATION_MATRIX.md.
     Every value arrives as a finished literal (the resolver does the arithmetic; a
     mustache template cannot). Each carries a fallback so a fill from any older path,
     or a template.json with no $presentation block, renders the page it renders today.

     What this master EXPRESSES: displayRegister (weight/scale/tracking/eyebrow case),
     paletteTemperature (surface temperature arrives already mixed into the palette;
     accent discipline is the eyebrow colour + rule strength below), sectionEmphasis
     (data-emph / data-compact / the variantDrop gates in index.html), ctaVoice (label
     text, no styling), density (rhythm + measure), trustSignal (the proof-band
     treatment). It does NOT express artDirection - the imagery engine does that.       */
  --display-scale: 0.92;
  --display-track: -0.005em;
  --display-weight: 600;
  --eyebrow-case: none;
  --eyebrow-track: 0.02em;
  --eyebrow-color: var(--ink-3);
  /* Rhythm 1 IS the ledger #52 0.6x section rhythm, ported into this master in the same
     edit that made it variable (it had been sitting at the pre-#52 gaps). */
  --rhythm-scale: 1.18;
  --rhythm: calc(clamp(2.1rem, 4.2vw, 3.9rem) * var(--rhythm-scale));
  --measure: 52ch;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  font-family: var(--sans);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.72;
  color: var(--ink-2);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

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

h1, h2, h3, h4 {
  font-family: var(--serif);
  color: var(--ink);
  line-height: 1.16;
  margin: 0 0 0.5em;
  /* Weight and tracking are the displayRegister axis. The weight is CLAMPED by the
     resolver to $presentation.headingWeights (which mirror defaults.fonts.googleHref), so
     it can never land on a face the link does not fetch - that is blueprint-gate's
     faux-bold failure - and never below 500, which is heading-ink's floor. */
  font-weight: var(--display-weight, 600);
  letter-spacing: var(--display-track, -0.005em);
}

p { margin: 0 0 1em; }
figure { margin: 0; }
a { color: var(--brand); }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gut);
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--dark); color: #fff; padding: 12px 18px;
}
.skip-link:focus { left: 12px; top: 12px; }

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

/* ---------- section furniture ---------- */
.eyebrow {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: var(--eyebrow-track, 0.2em);
  text-transform: var(--eyebrow-case, uppercase);
  color: var(--eyebrow-color, var(--brand));
  margin: 0 0 14px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.eyebrow::before {
  content: "";
  width: 28px; height: 1px; flex: none;
  background: var(--accent);
}
.eyebrow.on-dark { color: #d8e6f1; } /* gate v2: accent-soft on the dark local band measured 2.6:1; this near-white tint reads on any dark band */
.eyebrow.on-dark::before { background: var(--accent-soft); }

/* SECTION RHYTHM. Two things happened in this one line (2026-08-30). It was
   `clamp(56px, 9vw, 110px)`, the PRE-#52 gap - the operator's TASTE_LEDGER #52 rhythm
   directive was ported into the clinical master and never reached this one. `--rhythm`
   is `clamp(2.1rem, 4.2vw, 3.9rem)` (the approved medical demo's exact figure) times the
   density axis, so rhythm-scale 1 IS #52 and the axis varies around the approved rhythm
   rather than around the old gaps. */
.section { padding: var(--rhythm) 0; }
.section-head { max-width: var(--measure, 60ch); margin-bottom: clamp(28px, 4vw, 50px); }
.section-head h2 { font-size: calc(clamp(1.75rem, 4.6vw, 2.75rem) * var(--display-scale, 1)); }
.section-head p { color: var(--ink-3); font-size: clamp(1rem, 2.4vw, 1.08rem); margin: 0; }

/* ---------- SECTION EMPHASIS (presentation axis 4) ----------
   The renderer the emitted `variantEmphasis`/`variantCompact` never had: authored for 22
   niches since the pack era and read by no master until now. `data-emph` is the section
   this sub-niche LEADS on - more air around it and a larger head; `data-compact` is one
   that recedes without disappearing. Both are relative to whatever rhythm the density
   axis already set, so the two axes compose instead of fighting. Sections that are not
   `.section` (metrics, local, convert) carry the attributes too and get their own rules
   beside their base ones. */
.section[data-emph] { padding: calc(var(--rhythm) * 1.22) 0; }
.section[data-emph] .section-head h2 { font-size: calc(clamp(1.75rem, 4.6vw, 2.75rem) * var(--display-scale, 1) * 1.08); }
.section[data-compact] { padding: calc(var(--rhythm) * 0.74) 0; }
.section[data-compact] .section-head { margin-bottom: clamp(18px, 2.6vw, 30px); }
.section[data-compact] .section-head h2 { font-size: calc(clamp(1.5rem, 3.6vw, 2.1rem) * var(--display-scale, 1)); }
/* The two full-bleed bands set their own padding and never took `.section`, so they need
   their own pair rather than inheriting the rules above. */
.local[data-emph] .local-inner { padding-block: calc(clamp(52px, 8vw, 92px) * 1.15); }
.local[data-compact] .local-inner { padding-block: calc(clamp(52px, 8vw, 92px) * 0.72); }
.convert[data-emph] { padding: calc(clamp(52px, 8vw, 98px) * 1.15) 0; }
.convert[data-compact] { padding: calc(clamp(52px, 8vw, 98px) * 0.78) 0; }

/* ---------- TYPE REGISTER (presentation axis 1) ----------
   Weight, tracking and scale are already custom properties above; these three rules are
   the part a number cannot carry - the SHAPE of the setting. `editorial` is the approved
   build's own setting and is deliberately declared empty, so a page that resolves it
   renders exactly as this master always has.

   WEIGHT CONTRACT: nothing below introduces a weight. The heading weight comes from
   --display-weight, which the resolver clamps to $presentation.headingWeights (serif
   400/600 + sans 300/400/500/600, the weights defaults.fonts.googleHref fetches), so
   blueprint-gate's faux-bold check cannot regress through this layer. */
body[data-register="humanist"] h1,
body[data-register="humanist"] h2,
body[data-register="humanist"] h3,
body[data-register="humanist"] h4 { line-height: 1.28; letter-spacing: 0; }
body[data-register="humanist"] { line-height: 1.78; }
body[data-register="humanist"] .section-head p { max-width: 46ch; }

body[data-register="grotesque"] h1,
body[data-register="grotesque"] h2,
body[data-register="grotesque"] h3,
body[data-register="grotesque"] h4 { font-family: var(--sans); line-height: 1.06; }

/* ---------- PROOF BAND (presentation axis 7, trustSignal) ----------
   trustSignal resolved to the one decision this page can actually paint: whether the
   metrics band shouts or sits quiet. Numbers-led signals (credentials / results / years)
   put the real figures on the dark band where they read as a claim; people-led ones
   (warmth / reviews / availability) leave the band on canvas so the page does not open
   with a scoreboard at a reader who came for a person. It never invents a metric - the
   whole band is still behind the template's own metrics conditional. */
body[data-proof="loud"] .metrics { background: var(--dark); border-bottom: 0; }
body[data-proof="loud"] .metric { background: color-mix(in srgb, #fff 5%, var(--dark)); }
body[data-proof="loud"] .metric b { color: #fff; }
body[data-proof="loud"] .metric span { color: rgba(255, 255, 255, 0.72); }
body[data-proof="loud"] .metrics-grid { background: color-mix(in srgb, #fff 14%, var(--dark)); }

.band-soft { background: var(--canvas-soft); }
.band-sand { background: var(--canvas-sand); }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font-family: var(--sans);
  font-weight: 500;
  font-size: 15px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 15px 26px;
  border-radius: 2px;
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
  min-height: 50px;
}
.btn svg { width: 17px; height: 17px; flex: none; }
.btn-primary { background: var(--brand); color: #fff; }
.btn-primary:hover { background: var(--brand-deep); }
.btn-accent { background: var(--accent); color: #fff; }
.btn-accent:hover { background: var(--brand); }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.btn-ghost:hover { border-color: var(--brand); color: var(--brand); }
.btn-on-dark { background: transparent; color: #fff; border-color: rgba(255,255,255,0.45); }
.btn-on-dark:hover { background: rgba(255,255,255,0.12); }
.btn-light { background: #fff; color: var(--brand); }
.btn-light:hover { background: var(--canvas-sand); }
.btn-block { width: 100%; }

/* ---------- nav ---------- */
.nav {
  position: sticky; top: 0; z-index: 60;
  background: rgba(255,255,255,0.97);
  border-bottom: 1px solid var(--line-soft);
  backdrop-filter: saturate(150%) blur(8px);
}
.nav-inner { display: flex; align-items: center; gap: 18px; min-height: 76px; }
/* flex:none is load bearing: without it the real logo is the first thing the
   flex row crushes when the link list gets long, and it vanished entirely at
   1024px. The mark never shrinks; the link list wraps to the drawer instead. */
.nav-logo { display: flex; align-items: center; text-decoration: none; margin-right: auto; flex: 0 0 auto; }
/* Wide wordmark logos are stepped by viewport so that
   logo + CTA + hamburger always fit a 360px bar without the row overflowing. */
/* Cap, do not pin: .nav-logo is a flex row and a pinned height lets flex-shrink
   squeeze a wide lockup out of ratio (see the light master + gate v3
   logo-aspect). Renders identically whenever the logo already fits. */
.nav-logo img { max-height: 26px; height: auto; width: auto; max-width: 100%; min-width: 0; object-fit: contain; }
@media (min-width: 600px) { .nav-logo img { max-height: 30px; } }
.nav-wordmark { font-family: var(--serif); font-weight: 600; font-size: 22px; color: var(--ink); letter-spacing: .01em; white-space: nowrap; }
.cta-short { display: none; }
@media (max-width: 599px) {
  .cta-long { display: none; }
  .cta-short { display: inline; }
  .nav-inner { gap: 10px; }
  .nav-cta { padding: 11px 14px; font-size: 11.5px; letter-spacing: .05em; }
}
@media (max-width: 419px) {
  .nav-logo img { max-height: 22px; }
  .nav-cta { padding: 10px 12px; font-size: 11px; }
}
@media (max-width: 349px) {
  .nav-logo img { max-height: 19px; }
  .nav-inner { gap: 8px; }
  .nav-toggle { width: 40px; }
}
.nav-links { display: none; }
.nav-tools { display: flex; align-items: center; gap: 10px; }
.nav-phone {
  display: none;
  font-weight: 500; font-size: 15px; color: var(--ink); text-decoration: none;
  white-space: nowrap; letter-spacing: 0.01em;
}
.nav-phone:hover { color: var(--brand); }
.nav-cta { padding: 12px 18px; min-height: 44px; font-size: 12.5px; white-space: nowrap; }

.nav-toggle {
  display: inline-flex; flex-direction: column; justify-content: center; gap: 5px;
  width: 44px; height: 44px; padding: 0 10px;
  background: none; border: 1px solid var(--line); border-radius: 2px; cursor: pointer;
}
.nav-toggle span { display: block; height: 1.5px; background: var(--ink); transition: transform .2s ease, opacity .2s ease; }
.nav-toggle.open span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav-toggle.open span:nth-child(2) { opacity: 0; }
.nav-toggle.open span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* 1180 is measured on the source build: a 7.3:1 wordmark at 30px tall needs
   220px, and the full link list + phone + CTA only clear that above 1180. */
@media (min-width: 1180px) {
  .nav-toggle { display: none; }
  .nav-links { display: flex; align-items: center; gap: clamp(13px, 1.7vw, 26px); margin-right: 20px; }
  .nav-links a {
    font-size: 13px; font-weight: 500; letter-spacing: 0.09em; text-transform: uppercase;
    color: var(--ink-2); text-decoration: none;
    padding: 6px 0; border-bottom: 1px solid transparent; white-space: nowrap;
  }
  .nav-links a:hover, .nav-links a.active { color: var(--brand); border-bottom-color: var(--accent); }
  .nav-phone { display: inline-flex; align-items: center; gap: 7px; }
}
@media (min-width: 1360px) { .nav-logo img { max-height: 34px; } }

@media (max-width: 1179px) {
  .nav-links.open {
    display: flex; flex-direction: column; align-items: stretch; gap: 0;
    position: fixed; inset: 76px 0 auto 0;
    background: #fff;
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow-md);
    padding: 8px var(--gut) 20px;
    max-height: calc(100vh - 76px);
    overflow-y: auto;
  }
  .nav-links.open a {
    padding: 15px 0; font-size: 16px; font-weight: 500; letter-spacing: .06em;
    text-transform: uppercase; color: var(--ink);
    text-decoration: none; border-bottom: 1px solid var(--line-soft);
  }
}

/* ---------- hero ---------- */
.hero {
  background: var(--dark);
  color: rgba(255,255,255,0.85);
  position: relative;
  overflow: hidden;
}
.hero::before {
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(110% 120% at 12% 0%, color-mix(in srgb, var(--accent) 30%, transparent) 0%, color-mix(in srgb, var(--dark) 0%, transparent) 62%);
  pointer-events: none;
}
.hero-inner {
  position: relative;
  display: grid;
  gap: clamp(24px, 3.6vw, 40px);
  padding-top: clamp(30px, 5vw, 66px);
  padding-bottom: clamp(38px, 6vw, 78px);
}
.hero-photo {
  border-radius: 3px;
  overflow: hidden;
  aspect-ratio: 4 / 3;
  background: var(--photo-plate);
  box-shadow: var(--shadow-md);
}
.hero-photo img { width: 100%; height: 100%; object-fit: cover; object-position: 40% 58%; }

/* SUNK-HERO FIX (TASTE_LEDGER #44, 2026-08-28). This was `align-self: center`, which
   centred the copy inside a row whose height is set by whichever column is TALLEST
   (usually the lead-card). The headline then floated down the band while the card's
   heading sat near the top, reading as "not aligned / text too low". Copy starts at the
   row top now; `start` here also has to be explicit because an item's own align-self
   beats the container's align-items. */
.hero-copy { align-self: start; }
.hero h1 {
  color: #fff;
  font-size: calc(clamp(2.05rem, 5.6vw, 3rem) * var(--display-scale, 1));
  line-height: 1.1;
  margin-bottom: 16px;
  text-wrap: balance;
}
.hero-sub {
  color: rgba(255,255,255,0.82);
  font-size: clamp(1rem, 2.5vw, 1.08rem);
  margin-bottom: 24px;
}
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; }
.hero-note {
  display: block;
  margin-top: 20px; padding-top: 18px;
  border-top: 1px solid rgba(255,255,255,0.18);
  font-size: 14px; color: rgba(255,255,255,0.72);
}
.hero-note b { color: #fff; font-weight: 500; }

/* hero lead-capture card (blueprint: the form is IN the hero) */
.lead-card {
  background: #fff;
  color: var(--ink-2);
  border-radius: 3px;
  box-shadow: var(--shadow-lg);
  padding: clamp(22px, 3.4vw, 32px);
  border-top: 3px solid var(--accent);
  width: 100%;
}
.lead-card h2 { font-size: clamp(1.25rem, 3.2vw, 1.5rem); margin-bottom: 6px; }
.lead-card > p { font-size: 14.5px; color: var(--ink-3); margin-bottom: 18px; line-height: 1.6; }

@media (min-width: 760px) and (max-width: 1159px) {
  /* align-items: START, not center (sunk-hero fix, TASTE_LEDGER #44). The photo and the
     copy are different heights, so centring each one independently left both floating in
     the middle of the band. Here the lead-card is on row 2, so row 1 is just photo+copy
     and no extra offset is wanted: both tops sit on the row top. */
  .hero-inner { grid-template-columns: minmax(300px, 0.85fr) minmax(0, 1.15fr); align-items: start; }
  .hero-photo { aspect-ratio: 3 / 4; }
  .hero-photo--wide { aspect-ratio: 4 / 3; }
  .lead-card { grid-column: 1 / -1; max-width: 580px; }
}
@media (min-width: 1160px) {
  .hero-inner {
    /* the photo track has a hard 320px floor: the blueprint ship-gate requires a
       real, loaded photo of at least 300x200 painted in the first viewport. */
    grid-template-columns: minmax(320px, 0.72fr) minmax(0, 1fr) minmax(330px, 0.9fr);
    /* align-items: START, not center (sunk-hero fix, TASTE_LEDGER #44). THREE tracks of
       very different heights (photo 469, copy 596, lead-card 772 on the oracle content):
       centring each independently dropped the headline 88px below the card it is supposed
       to read alongside. */
    align-items: start;
    gap: clamp(26px, 2.8vw, 38px);
    min-height: 620px;
  }
  /* The card's own top border (3px) + padding push its heading 35px below its box top.
     Matching that on the copy column aligns the H1's TEXT with the card's HEADING text
     rather than aligning two boxes whose insets differ - the alignment a reader sees. */
  .hero-copy { padding-top: calc(3px + clamp(22px, 3.4vw, 32px)); }
  .hero-photo { aspect-ratio: 3 / 4.4; }
  /* opt-in landscape crop window (content.json hero.image.wide, see template.json
     $artDirection): a shorter 4/3 window for sources that cannot survive the
     portrait crop. Absent the flag nothing changes. */
  .hero-photo--wide { aspect-ratio: 4 / 3; }
}

/* ---------- forms ---------- */
.field { margin-bottom: 13px; }
.field label {
  display: block; font-size: 11.5px; font-weight: 500; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px;
}
.field input, .field select, .field textarea {
  width: 100%;
  font-family: var(--sans);
  font-size: 16px;
  color: var(--ink);
  background: #fff;
  border: 1px solid color-mix(in srgb, var(--ink) 24%, transparent);
  border-radius: 2px;
  padding: 12px 13px;
  min-height: 48px;
}
.field textarea { min-height: 104px; resize: vertical; line-height: 1.6; }
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--brand); outline: 2px solid color-mix(in srgb, var(--accent) 28%, transparent); outline-offset: 0;
}
.field-row { display: grid; gap: 13px; }
@media (min-width: 480px) { .field-row { grid-template-columns: 1fr 1fr; } }
.form-note { font-size: 12.5px; color: var(--ink-3); margin: 12px 0 0; line-height: 1.55; }
.form-note a { color: var(--brand); }

/* ---------- trust metrics ---------- */
.metrics { border-bottom: 1px solid var(--line); background: var(--canvas); }
.metrics-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--line-soft);
}
/* auto-fit (not a fixed repeat(4)) so the band shrinks honestly to however
   many REAL metrics the prospect has - 2, 3 or 4 equal columns, never an
   empty ghost cell. */
@media (min-width: 880px) { .metrics-grid { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); } }
.metric { background: var(--canvas); padding: clamp(24px, 3.4vw, 38px) clamp(14px, 2.2vw, 26px); }
.metric b {
  display: block;
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(1.9rem, 5.2vw, 2.6rem);
  line-height: 1;
  color: var(--brand);
  margin-bottom: 10px;
  letter-spacing: -0.02em;
}
.metric span { display: block; font-size: 14px; color: var(--ink-3); line-height: 1.5; }
/* The proof band's own emphasis/compact rules: it is not a `.section`, so the generic
   rules above do not reach it. Compact keeps the numbers and takes the air. */
.metrics[data-emph] .metric { padding: calc(clamp(24px, 3.4vw, 38px) * 1.2) clamp(14px, 2.2vw, 26px); }
.metrics[data-compact] .metric { padding: calc(clamp(24px, 3.4vw, 38px) * 0.62) clamp(14px, 2.2vw, 26px); }
.metrics[data-compact] .metric b { font-size: clamp(1.5rem, 3.8vw, 1.95rem); }

/* ---------- practice photo tiles ---------- */
.tiles { display: grid; gap: clamp(14px, 2vw, 20px); grid-template-columns: 1fr; }
@media (min-width: 620px) { .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1060px) { .tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.tile {
  position: relative;
  overflow: hidden;
  border-radius: 3px;
  background: var(--dark);
  color: #fff;
  isolation: isolate;
  min-height: 330px;
}
.tile img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  z-index: -2;
  transition: transform .5s ease;
}
.tile::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  /* Deliberately heavy: tile photos can run from a dark file box to a bright
     white interior, and the label has to read the same on all of them. */
  background: linear-gradient(178deg, color-mix(in srgb, var(--dark-deep) 30%, transparent) 0%, color-mix(in srgb, var(--dark-deep) 74%, transparent) 46%, color-mix(in srgb, var(--dark-deep) 95%, transparent) 100%);
  transition: background .3s ease;
}
/* no-media composure: a service without a staged photo reads as a solid dark
   panel with the same bottom-anchored label composition (the ::after gradient
   still deepens it) - never a white hole behind the overlay. */
.tile.no-media { background: var(--dark); }
.tile:hover img { transform: scale(1.05); }
.tile:hover::after { background: linear-gradient(178deg, color-mix(in srgb, var(--brand) 40%, transparent) 0%, color-mix(in srgb, var(--dark-deep) 80%, transparent) 46%, color-mix(in srgb, var(--dark-deep) 96%, transparent) 100%); }
.tile-body {
  position: relative;
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: 330px;
  padding: clamp(20px, 2.6vw, 26px);
}
.tile-num {
  font-family: var(--sans);
  font-size: 12px; font-weight: 500; letter-spacing: .22em;
  color: rgba(255,255,255,0.66);
  margin: 0 0 auto;
}
.tile h3 { color: #fff; font-size: clamp(1.12rem, 2.4vw, 1.28rem); margin: 0 0 8px; }
.tile p { color: rgba(255,255,255,0.84); font-size: 14.5px; margin: 0; line-height: 1.55; }

/* ---------- editorial trust ---------- */
.editorial { display: grid; gap: clamp(28px, 4vw, 52px); align-items: start; }
@media (min-width: 1000px) {
  .editorial { grid-template-columns: minmax(0, 1.6fr) minmax(300px, 0.9fr); }
}
/* no-rail composure: without a side card the editorial column reads full
   width instead of leaving a half-empty rail track. */
.editorial.no-rail { grid-template-columns: minmax(0, 1fr); max-width: 62rem; }
.editorial-body p { font-size: clamp(1rem, 2.3vw, 1.07rem); color: var(--ink-2); }
.editorial-body p.lead {
  font-size: clamp(1.15rem, 3vw, 1.42rem);
  color: var(--ink); font-family: var(--serif); font-style: italic; line-height: 1.48;
  margin-bottom: 1.1em;
}
/* The aside photo sits under the dark CTA card so the narrow column is not a
   half-empty rail next to a long editorial column. */
.editorial-photo { margin: 22px 0 0; border-radius: 3px; overflow: hidden; }
.editorial-photo img { width: 100%; height: auto; }
.editorial-photo figcaption { font-size: 12.5px; color: var(--ink-3); padding-top: 10px; letter-spacing: .01em; }

.signature {
  display: flex; align-items: center; gap: 15px;
  border-top: 1px solid var(--line); padding-top: 20px; margin-top: 8px;
}
.signature .monogram {
  width: 54px; height: 54px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--brand); color: #fff;
  font-family: var(--sans); font-size: 15px; font-weight: 400; letter-spacing: .12em;
}
.signature b { display: block; font-family: var(--serif); font-size: 17px; color: var(--ink); font-weight: 600; }
.signature span { font-size: 14px; color: var(--ink-3); }

.side-card {
  background: var(--dark);
  color: rgba(255,255,255,0.82);
  border-radius: 3px;
  padding: clamp(24px, 3.2vw, 34px);
}
.side-card h3 { color: #fff; font-size: clamp(1.22rem, 2.9vw, 1.45rem); }
.side-card p { font-size: 15px; }
.side-card .btn { margin-top: 6px; }
.side-card .side-line {
  display: block; margin-top: 18px; padding-top: 18px;
  border-top: 1px solid rgba(255,255,255,0.18);
  font-size: 14px; color: rgba(255,255,255,0.74); line-height: 1.75;
}
.side-card a { color: var(--accent-soft); }
.side-card a.btn-light { color: var(--brand); } /* gate v2: .side-card a out-cascaded .btn-light to accent-soft (px 2.3:1) */
.editorial-rail { align-self: start; }

/* ---------- team member feature ---------- */
.person { display: grid; gap: clamp(28px, 4vw, 54px); align-items: start; }
@media (min-width: 900px) { .person { grid-template-columns: minmax(0, 0.72fr) minmax(0, 1fr); } }
/* no-media composure: a member without a published photo reads as one clean
   column, never a photo-shaped hole. Consecutive members get breathing room. */
.person.no-media { grid-template-columns: minmax(0, 1fr); max-width: 60rem; }
.wrap.person + .wrap.person { margin-top: clamp(40px, 6vw, 80px); }
.person-photo { border-radius: 3px; overflow: hidden; box-shadow: var(--shadow-md); background: #ece7e1; }
.person-photo img { width: 100%; height: auto; }
.person-body h2 { font-size: clamp(1.7rem, 4.2vw, 2.4rem); }
.person-role {
  font-family: var(--sans); font-size: 12px; font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase; color: var(--brand);
  margin: 0 0 18px;
}
.creds { list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 0; }
.creds li {
  /* The label column flexes to the longest label (84px floor) so long creds
     ("UNDERGRADUATE") never clip into the value; the max-width on the b caps
     runaway multi-word labels into a wrap instead of starving the value. */
  display: grid; grid-template-columns: minmax(84px, max-content) minmax(0, 1fr); gap: 16px;
  padding: 13px 0; border-top: 1px solid var(--line-soft);
  font-size: 15px; color: var(--ink-2); line-height: 1.5;
}
.creds li:last-child { border-bottom: 1px solid var(--line-soft); }
.creds li b {
  font-family: var(--sans); font-size: 12px; font-weight: 500; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-3); padding-top: 3px;
  max-width: 12em; overflow-wrap: anywhere;
}

/* ---------- process ---------- */
.process { display: grid; gap: clamp(28px, 4vw, 52px); align-items: center; }
@media (min-width: 900px) { .process { grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr); } }
/* no-media composure: without a process photo the steps read as one bounded
   column instead of leaving an empty grid track. */
.process.no-media { grid-template-columns: minmax(0, 1fr); max-width: 56rem; }
.process-photo { border-radius: 3px; overflow: hidden; box-shadow: var(--shadow-md); }
.process-photo img { width: 100%; height: auto; }
.steps { list-style: none; margin: 0; padding: 0; counter-reset: step; }
.steps li {
  display: grid; grid-template-columns: 46px minmax(0, 1fr); gap: 16px;
  padding: 22px 0;
  border-bottom: 1px solid var(--line-soft);
}
.steps li:last-child { border-bottom: 0; padding-bottom: 0; }
.steps li::before {
  counter-increment: step;
  content: "0" counter(step);
  font-family: var(--sans); font-size: 14px; font-weight: 500; letter-spacing: .12em;
  color: var(--accent);
  padding-top: 6px;
}
.steps h3 { font-size: 1.14rem; margin-bottom: 5px; }
.steps p { margin: 0; font-size: 15.5px; color: var(--ink-3); }

/* ---------- reviews ---------- */
.rating-line {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px;
  margin-bottom: clamp(24px, 3.4vw, 40px);
  font-size: 15px; color: var(--ink-3);
}
/* The rating figure is a DISPLAY numeral, not emphasis, so it declares the
   master's serif display weight (600) explicitly instead of inheriting the
   UA's <b> default of 700. That default was a real defect, not a nicety: the
   tailor authors `fonts.googleHref` per prospect and those hrefs routinely
   request the serif at 400/600 only, so 700 had nothing to render with and the
   browser synthesized it - blueprint-gate's faux-bold check (floor 600) failed
   the build. Weight 600 is what the master itself guarantees: it is in this
   master's own defaults.fonts.googleHref and is the weight .nav-wordmark,
   .signature b and .footer-wordmark already use. See template.json $fontWeights
   for the contract every tailored googleHref has to honour. */
.rating-line b { font-family: var(--serif); font-weight: 600; font-size: 2.1rem; color: var(--ink); line-height: 1; }
.stars { color: #c4923d; letter-spacing: 2px; font-size: 15px; }

.reviews { display: grid; gap: clamp(14px, 2vw, 20px); grid-template-columns: 1fr; }
@media (min-width: 780px) { .reviews { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.review {
  background: #fff;
  border: 1px solid var(--line);
  border-top: 2px solid var(--brand);
  border-radius: 3px;
  padding: clamp(20px, 2.8vw, 28px);
  display: flex; flex-direction: column;
}
.review blockquote {
  margin: 12px 0 18px;
  font-family: var(--serif);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink);
}
.review footer { margin-top: auto; font-size: 13.5px; color: var(--ink-3); }
.review footer b { display: block; color: var(--ink); font-size: 15px; font-family: var(--sans); font-weight: 500; }

/* ---------- local band ---------- */
.local { position: relative; isolation: isolate; overflow: hidden; background: var(--dark); }
.local img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: -2;
}
.local::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(96deg, color-mix(in srgb, var(--dark-deep) 93%, transparent) 0%, color-mix(in srgb, var(--dark-deep) 80%, transparent) 48%, color-mix(in srgb, var(--dark-deep) 42%, transparent) 100%);
}
.local-inner { padding: clamp(52px, 8vw, 92px) 0; max-width: 46rem; color: rgba(255,255,255,0.86); }
.local h2 { color: #fff; font-size: clamp(1.6rem, 4.2vw, 2.35rem); }
.local p { font-size: clamp(1rem, 2.4vw, 1.08rem); }
.local .btn { margin-top: 8px; }

/* ---------- FAQ ---------- */
.faq { display: grid; gap: clamp(4px, 2vw, 40px); grid-template-columns: 1fr; }
@media (min-width: 940px) { .faq { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.faq-item { padding: 22px 0; border-bottom: 1px solid var(--line-soft); }
.faq-item h3 { font-size: clamp(1.05rem, 2.3vw, 1.16rem); margin-bottom: 8px; }
.faq-item p { margin: 0; font-size: 15.5px; color: var(--ink-3); }
.faq-note {
  margin-top: 28px; padding-top: 20px; border-top: 1px solid var(--line);
  font-size: 13.5px; color: var(--ink-3); max-width: 78ch; line-height: 1.65;
}

/* ---------- conversion band + footer ---------- */
.convert { background: var(--dark); color: rgba(255,255,255,0.82); padding: clamp(52px, 8vw, 98px) 0; }
.convert-grid { display: grid; gap: clamp(30px, 5vw, 56px); }
@media (min-width: 1000px) { .convert-grid { grid-template-columns: minmax(0, 1fr) minmax(390px, 0.88fr); align-items: start; } }
.convert h2 { color: #fff; font-size: clamp(1.8rem, 5vw, 2.7rem); }
.convert p { font-size: clamp(1rem, 2.4vw, 1.07rem); }
.convert .lead-card h2 { color: var(--ink); font-size: clamp(1.25rem, 3.2vw, 1.5rem); }
.convert .lead-card > p { color: var(--ink-3); font-size: 14.5px; }
.convert .lead-card .form-note { color: var(--ink-3); font-size: 12.5px; }
.convert .lead-card label { color: var(--ink-3); }

.big-phone {
  display: inline-flex; align-items: center; gap: 12px;
  font-family: var(--serif);
  font-size: clamp(1.7rem, 5.2vw, 2.4rem);
  font-weight: 600;
  color: #fff; text-decoration: none;
  margin: 8px 0 24px;
  border-bottom: 1px solid color-mix(in srgb, var(--accent-soft) 60%, transparent);
  padding-bottom: 5px;
  word-break: break-word;
}
.big-phone:hover { border-bottom-color: var(--accent-soft); }

.office-grid { display: grid; gap: 24px; margin-top: 30px; }
@media (min-width: 560px) { .office-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.office-grid h4 {
  color: var(--accent-soft); font-family: var(--sans); font-size: 11.5px; font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase; margin-bottom: 10px;
}
.office-grid p, .office-grid ul { font-size: 15px; margin: 0; color: rgba(255,255,255,0.8); line-height: 1.7; }
.office-grid ul { list-style: none; padding: 0; }
.office-grid li { display: flex; justify-content: space-between; gap: 14px; padding: 2px 0; }
.office-grid li span:last-child { text-align: right; }
.office-grid a { color: #fff; text-decoration: underline; text-underline-offset: 3px; }

.map {
  position: relative;
  margin-top: 30px;
  border-radius: 3px; overflow: hidden;
  border: 1px solid rgba(255,255,255,0.16);
  line-height: 0;
  min-height: 250px;
  background: var(--dark-deep);
}
.map-fallback {
  position: absolute; inset: 0; z-index: 0;
  display: flex; flex-direction: column; justify-content: center; gap: 10px;
  padding: 24px;
  line-height: 1.55;
  color: rgba(255,255,255,0.82);
  font-size: 15px;
}
/* Same reason as .rating-line b: declare the guaranteed serif weight rather
   than inherit <b>'s 700, which no tailored googleHref is obliged to fetch. */
.map-fallback b { color: #fff; font-family: var(--serif); font-weight: 600; font-size: 1.12rem; }
.map-fallback a { color: var(--accent-soft); }
.map iframe {
  position: relative; z-index: 1;
  width: 100%; height: 250px; border: 0; display: block;
  filter: grayscale(0.3);
}

.site-footer { background: var(--dark-deep); color: rgba(255,255,255,0.62); padding: 46px 0 34px; font-size: 14px; }
.footer-top { display: grid; gap: 28px; padding-bottom: 28px; border-bottom: 1px solid rgba(255,255,255,0.12); }
@media (min-width: 840px) { .footer-top { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr); } }
.site-footer .footer-logo img { height: 30px; width: auto; margin-bottom: 18px; }
.footer-wordmark { display: block; font-family: var(--serif); font-weight: 600; font-size: 20px; color: #fff; margin-bottom: 18px; }
.site-footer h4 { color: #fff; font-family: var(--sans); font-size: 11.5px; font-weight: 500; letter-spacing: .18em; text-transform: uppercase; margin-bottom: 12px; }
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li { padding: 4px 0; line-height: 1.6; }
.site-footer a { color: rgba(255,255,255,0.72); text-decoration: none; }
.site-footer a:hover { color: #fff; }
.footer-bottom { padding-top: 22px; display: flex; flex-wrap: wrap; gap: 10px 24px; justify-content: space-between; font-size: 13px; }
/* Page-level photo colophon: one deduped attribution line for every credited
   photo on the page. Google Place photos are user-submitted and the licence
   requires the returned author attribution to be DISPLAYED wherever the photo
   is displayed (see runs/<domain>/place-photos/manifest.json `usage`); Street
   View keeps its "(c) Google" notice. Before this existed the master had no
   credit surface at all, so a prospect's own Google photos could only go in a
   slot that happened to render a caption - every other slot was closed to them.
   `flex-basis: 100%` drops the line onto its own row under the copyright row.
   Renders ONLY when an image carries a `credit`: fillStatic leaves
   `photoCredits` UNSET (never []) on an uncredited build, so this element does
   not exist and the page is byte-identical to before. */
.photo-colophon {
  flex: 1 0 100%;
  color: rgba(255,255,255,0.62);
  line-height: 1.6;
  /* The fixed PXLNorth preview badge parks over the last ~48px of the viewport
     and this line is the last thing on the page. An attribution the chrome
     covers is not a displayed attribution, so the colophon reserves its own
     clearance. Costs an uncredited build nothing - the element is not there. */
  padding-bottom: 3.5rem;
}
.photo-colophon a { color: #fff; text-decoration: underline; text-underline-offset: 3px; }

/* ---------- modal (mailto confirmation) ---------- */
.modal-overlay {
  display: none;
  position: fixed; inset: 0; z-index: 120;
  background: color-mix(in srgb, var(--ink) 62%, transparent);
  padding: 24px;
  align-items: center; justify-content: center;
}
.modal-overlay.open { display: flex; }
.modal {
  background: #fff; border-radius: 3px; padding: 30px;
  max-width: 470px; width: 100%; box-shadow: var(--shadow-lg);
  border-top: 3px solid var(--accent);
}
.modal h3 { font-size: 1.3rem; }
.modal p { font-size: 15px; color: var(--ink-3); }

/* ---------- back to top ---------- */
.back-to-top {
  position: fixed; right: 18px; bottom: 78px; z-index: 55;
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--brand); color: #fff; border: 0; cursor: pointer;
  opacity: 0; pointer-events: none; transition: opacity .25s ease;
  font-size: 18px; line-height: 1;
}
.back-to-top.visible { opacity: 1; pointer-events: auto; }

/* ---------- scroll reveal ---------- */
.js-anim .fade-up { opacity: 0; transform: translateY(16px); transition: opacity .6s ease, transform .6s ease; }
.js-anim .fade-up.visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js-anim .fade-up { opacity: 1; transform: none; transition: none; }
}

/* ---------- preview badge (PXLNorth disclosure) ---------- */
/**
 * ONE PILL, NEVER TWO ROWS — measured 2026-08-12.
 *
 * This shipped as two separate pills with `flex-wrap: wrap`, so at 390px they did not fit
 * on one line and the badge became 81px tall — against 34px for the sibling
 * clinical-ivyrehab-static master, which has always used a single unwrappable container.
 * That extra 47px is the whole reason hero-cta-reachable fails on law builds and not on
 * clinical ones: a badge twice as tall reaches twice as far up into the fold and lands on
 * the client's Book/Call button.
 *
 * Not a new design — this adopts the treatment the clinical master already ships and the
 * operator already has in production. CSS only: the rendered HTML is unchanged, so the
 * master oracle (which compares normalized HTML, not pixels) is unaffected.
 *
 * Existing builds keep their own copy until they are refilled; this fixes what the master
 * PRODUCES, which is where a class like this belongs.
 */
.preview-badge {
  position: fixed; left: 12px; bottom: 12px; z-index: 130;
  display: inline-flex; align-items: stretch; gap: 1px;
  border-radius: 999px; overflow: hidden;
  box-shadow: var(--shadow-sm);
  max-width: calc(100vw - 24px);
}
.preview-badge a {
  font-family: var(--sans); font-size: 12px; font-weight: 500;
  text-decoration: none; padding: 8px 14px; white-space: nowrap;
}
@media (max-width: 620px) {
  /* Same size-down the clinical master uses, so a long business name cannot re-wrap it. */
  .preview-badge a { font-size: 11px; padding: 7px 11px; }
}
.preview-badge-info { background: color-mix(in srgb, var(--dark-deep) 90%, transparent); color: #fff; }
.preview-badge-cta { background: var(--accent); color: #fff; }
