/* ==========================================================================
   The Conservatory — Design System Implementation
   Implements docs/design-system.md. Prototype/test styles only —
   not the homepage, not committed to production.
   ========================================================================== */

/* Real fonts, self-hosted, added 2026-07-30 per the founder's direct
   approval ("Real fonts decision: Yes"). Files live in fonts/, fetched
   directly from Google's own font CDN (fonts.gstatic.com) with a browser
   user-agent to get woff2 specifically, not proxied through Google's CSS
   or any ongoing external request: once downloaded, the site makes zero
   calls to Google at runtime, preserving the "zero third-party scripts"
   inventory item already confirmed elsewhere in this project. Both fonts
   are SIL Open Font License, self-hosting is fully permitted.

   Only the weights and styles actually used anywhere on the site are
   included (checked by grepping every CSS file for font-weight and
   font-style before downloading anything): Inter at 400/500/600/700
   normal, Cormorant Garamond at 300/400 normal plus 400 italic (used by
   h2, .link-architectural, and .step__number). No bold/italic Inter, no
   500/600/700 Cormorant Garamond exist anywhere in the site's CSS, so
   none were downloaded. Latin subset only (this is an English-copy site);
   Cyrillic/Greek/Vietnamese subsets from Google's CSS were not fetched.

   font-display: swap so text is never invisible while the font loads
   (browser shows the fallback stack immediately, swaps in once ready). */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/inter-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('fonts/inter-500.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('fonts/inter-600.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('fonts/inter-700.woff2') format('woff2');
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('fonts/cormorant-300.woff2') format('woff2');
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/cormorant-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/cormorant-400-italic.woff2') format('woff2');
}

/* Font stacks below already name Cormorant Garamond and Inter first, so
   the @font-face rules above take over automatically with no other
   changes needed. System-font fallbacks stay in place for the instant
   before the real fonts load, and for the no-JS/no-CSS-blocked edge
   case. See docs/design-system.md's Typography section for the reasoning
   behind this specific pairing. */

:root {
  /* Core colors — REVISED 2026-07-12 ("Summer Palette"), see
     docs/design-system.md for the founder feedback driving this change.
     Token NAMES are kept stable so every rule below still makes sense;
     only the VALUES moved lighter and warmer. */
  /* Meadow Green — was #183126, revised to #4A7856 in the Summer Palette,
     then nudged 2 points darker per channel 2026-07-13 (#4A7856 -> #487453):
     the Summer value measured 4.498:1 against Blush Cream, a hair under the
     WCAG AA 4.5:1 minimum for the smaller forest-colored text that sits on
     linen surfaces (architectural links, card headings at mobile sizes).
     This value measures 4.74:1 there and is visually indistinguishable from
     the approved Summer green. */
  --color-forest: #487453;
  --color-forest-rgb: 72, 116, 83;
  --color-ivory: #FDFBF5;         /* Warm Ivory — was #F8F4EC, lightened further */
  --color-linen: #FBEEE8;         /* Blush Cream — was #EFE7D8, now pink-tinted not olive-tinted */
  --color-evergreen: #345C40;     /* Deep Meadow — was #234234; darker sibling of Forest, used for text/hover so body copy still meets contrast even though Forest itself lightened */
  --color-evergreen-rgb: 52, 92, 64;
  --color-sage: #B7C7AE;          /* was #A9B7A0 */
  --color-moss: #7C9C82;          /* was #596E57 */
  --color-gold: #E3A23E;          /* Sun Gold — was #C2A86A, warmed/brightened to echo the approved hero photo's mural */
  --color-bronze: #8B7150;        /* unchanged */
  --color-olive: #7C8262;         /* unchanged */

  /* Cross-touchpoint accent colors — matched to the existing business card
     and Practice Better portal. Signature Pink stays fill-only (contrast
     reasons, unchanged). Pink Deep is NEW 2026-07-12: the founder asked for
     visible pink on subtitles/eyebrows, which the light fill color can't
     do (fails text contrast) — this deeper, derived rose can. */
  --color-signature-pink: #FFADAD;
  /* Pink Deep darkened 2026-07-13 (#C96B7A -> #A85264): the original value
     measured 3.15:1 against Blush Cream and 3.46:1 against Warm Ivory,
     below the WCAG 2.2 AA 4.5:1 minimum for the small (12px) eyebrow text
     it exists to color. This value keeps the founder's requested visible
     pink while measuring 4.56:1 on Blush Cream and 5.0:1 on Warm Ivory. */
  --color-pink-deep: #A85264;
  --color-neutral-gray: #B4B4B4;
  /* Accessible text variants, added 2026-07-13. Sun Gold (#E3A23E) and Sage
     (#B7C7AE) stay available for borders, dots, and decorative marks, but
     both fail WCAG AA as text (gold 2.14:1 on ivory; sage 4.29:1 on the
     evergreen footer). These are the text-safe siblings: same families,
     measured at 5.03:1 (gold-text on ivory) and 4.99:1 (sage-bright on
     evergreen). Use these whenever gold or sage needs to be read, not seen. */
  --color-gold-text: #8F6512;
  --color-sage-bright: #C8D5C0;

  /* Semantic colors */
  --color-success: #4E7A5B;
  --color-warning: #B0894A;
  --color-error: #9A4E47;
  --color-info: #6A847C;
  --color-link: var(--color-evergreen);
  --color-focus: var(--color-evergreen);

  /* Text — body/heading text uses the darker Evergreen token, not the
     lighter Forest token, specifically so paragraph text still clears
     contrast minimums even though the "primary" brand green lightened. */
  --text-primary: var(--color-evergreen);
  /* Secondary text darkened 2026-07-13 (was Moss #7C9C82, which measured
     2.93:1 on ivory and 2.67:1 on linen — well below the 4.5:1 AA minimum
     for the 13px disclaimers, captions, and placeholder notes it colors,
     several of which are legally load-bearing text). #547157 is the same
     green family, measured at 5.23:1 on ivory and 4.77:1 on linen. Moss
     itself remains for decorative strokes (icons, botanical art). */
  --text-secondary: #547157;
  /* Muted alpha raised 2026-07-13 (0.6 measured 2.86:1 on ivory; 0.85
     measures 5.06:1). */
  --text-muted: rgba(var(--color-evergreen-rgb), 0.85);
  --text-on-dark: var(--color-ivory);

  /* Typography */
  --font-serif: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  /* Spacing scale — top end tightened 2026-07-12 per direct founder
     feedback ("too much empty space"). See docs/design-system.md. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 80px;   /* was 96px — now the default section gap */
  --space-10: 96px;  /* was 120px */
  --space-11: 120px; /* was 160px */
  --space-12: 160px; /* was 220px — reserved for rare, large pauses only */

  /* Card padding */
  --card-padding-desktop: 48px;
  --card-padding-tablet: 36px;
  --card-padding-mobile: 24px;

  /* Max widths */
  --width-reading: 680px;
  --width-content: 1200px;

  /* Corners */
  --radius-sharp: 0px;
  --radius-input: 4px;
  --radius-button: 12px;
  --radius-card: 16px;

  /* Borders */
  --border-hairline: 1px solid rgba(var(--color-forest-rgb), 0.12);
  --border-strong: 1px solid rgba(var(--color-forest-rgb), 0.24);
  --border-specimen: 1px solid rgba(142, 137, 126, 0.3);

  /* Shadows */
  --shadow-card: 0 10px 30px rgba(var(--color-forest-rgb), 0.06);
  --shadow-card-hover: 0 14px 36px rgba(var(--color-forest-rgb), 0.09);

  /* Motion */
  --ease-conservatory: cubic-bezier(0.16, 1, 0.3, 1);
  --duration-fast: 250ms;
  --duration-base: 600ms;
  --duration-slow: 1200ms;
}

/* ==========================================================================
   Reset + base
   ========================================================================== */

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

html {
  scroll-behavior: smooth;
}

@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;
    scroll-behavior: auto !important;
  }
}

body {
  margin: 0;
  background: var(--color-ivory);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 18px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

/* Subtle paper/linen grain texture — inline SVG noise filter, no image request */
.textured {
  position: relative;
  background-color: var(--color-ivory);
}
.textured--linen { background-color: var(--color-linen); }
.textured::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.025;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

h1, h2, h3 {
  font-family: var(--font-serif);
  color: var(--color-forest);
  margin: 0 0 var(--space-5) 0;
  font-weight: 400;
}

.display {
  font-family: var(--font-serif);
  font-weight: 300;
  font-size: clamp(2.75rem, 5vw, 4.5rem);
  line-height: 1.1;
  margin: 0 0 var(--space-7) 0;
  max-width: 20ch;
}

h1 { font-size: clamp(2rem, 4vw, 3rem); line-height: 1.15; margin-bottom: var(--space-7); }
h2 { font-size: clamp(1.75rem, 3.5vw, 2.75rem); line-height: 1.2; font-style: italic; }
h3 { font-size: clamp(1.375rem, 2vw, 1.625rem); line-height: 1.3; }

p {
  margin: 0 0 var(--space-5) 0;
  max-width: var(--width-reading);
}

.body-large { font-size: clamp(1.125rem, 1.5vw, 1.25rem); line-height: 1.6; }

.eyebrow {
  display: block;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  /* Pink Deep, not text-secondary — 2026-07-12 revision: the founder
     specifically asked for visible pink on subtitles. See
     docs/design-system.md "Cross-touchpoint accent colors". */
  color: var(--color-pink-deep);
  margin-bottom: var(--space-3);
}

.caption {
  font-family: var(--font-sans);
  font-size: 12px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ==========================================================================
   Layout helpers
   ========================================================================== */

/* FIX 2026-07-12: this rule was still pointing at --space-10 (mobile) and
   --space-11 (desktop) — per docs/design-system.md's own spacing table,
   --space-9 is "now the default section gap," --space-10 is reserved for
   sections that specifically need more separation, and --space-11 is
   "reserved for genuinely major transitions only." The spacing SCALE was
   compressed during the Summer Palette revision, but this rule was never
   updated to actually use the new default value — every section on the
   site was still getting the old, generous gap regardless. This is the
   real cause of the "still too much empty space" feedback surviving the
   earlier token-value change. */
.section {
  padding: var(--space-9) var(--space-5);
}
@media (min-width: 1024px) {
  .section { padding: var(--space-9) var(--space-7); }
}

.section--deep {
  background: var(--color-forest);
  color: var(--text-on-dark);
}
.section--deep h1, .section--deep h2, .section--deep h3 { color: var(--text-on-dark); }
/* Eyebrows/captions and body text on the dark Forest background lightened
   2026-07-13: Sage measured 2.87:1 and ivory-at-0.85 measured 4.06:1 on
   Forest — both under the 4.5:1 AA minimum for small text. Full ivory
   measures 4.94:1; 0.95 alpha measures 4.62:1. */
.section--deep .eyebrow, .section--deep .caption { color: var(--color-ivory); }
.section--deep p { color: rgba(253, 251, 245, 0.95); }

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

.container {
  max-width: var(--width-content);
  margin: 0 auto;
}

.split {
  display: grid;
  gap: var(--space-7);
  align-items: center;
}
/* Intermediate tablet treatment, added 2026-07-13: previously .split stayed
   single-column (fully stacked, full-width image) all the way up to 1024px,
   which meant a genuine tablet width like 768px rendered as stretched
   mobile rather than as its own considered layout. A simple, even 1fr 1fr
   split starts here — narrower than the deliberate 7:5 asymmetric desktop
   ratio below, since an asymmetric split gets cramped at tablet widths, but
   still real side-by-side layout with the image column naturally capped to
   roughly half the container instead of running full-bleed. */
@media (min-width: 768px) {
  .split { grid-template-columns: 1fr 1fr; }
  .split--reverse > *:first-child { order: 2; }
}
@media (min-width: 1024px) {
  .split { grid-template-columns: 7fr 5fr; gap: var(--space-9); }
  .split--reverse { grid-template-columns: 5fr 7fr; }
}

.grid-3 {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: 1fr;
}
@media (min-width: 640px) {
  .grid-3 { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1024px) {
  .grid-3 { grid-template-columns: 1fr 1fr 1fr; }
}
/* FIX 2026-07-13: at the 640-1023px tablet range, a 3-item grid-3 (the
   Individual Sessions row is the only real use of this component) left a
   lone third card sitting in column 1 with an empty column 2 beside it —
   an orphaned, unbalanced-looking card, not a deliberate asymmetric choice.
   Centers the third card and spans it across both columns specifically in
   that range, so it reads as an intentional capstone item rather than a
   layout accident. Targets exactly 3-item grids only (:last-child paired
   with :nth-child(3)), so a future 2- or 4-item .grid-3 use isn't affected. */
@media (min-width: 640px) and (max-width: 1023px) {
  .grid-3 > :nth-child(3):last-child {
    grid-column: 1 / -1;
    max-width: 380px;
    margin: 0 auto;
  }
}
/* Same orphaned-card problem, one item later: at 1024px+ (3 columns), a
   4-item grid-3 (404.html's Explore grid, added 2026-07-30) leaves a lone
   4th card alone in column 1 of row 2. Centers it the same way, targeting
   exactly 4-item grids only so 2- or 3-item uses are unaffected. */
@media (min-width: 1024px) {
  .grid-3 > :nth-child(4):last-child {
    grid-column: 1 / -1;
    max-width: 380px;
    margin: 0 auto;
  }
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  border-radius: var(--radius-button);
  padding: 16px 40px;
  transition: background-color var(--duration-base) var(--ease-conservatory),
              color var(--duration-base) var(--ease-conservatory),
              transform var(--duration-base) var(--ease-conservatory);
}

.btn-primary {
  background: var(--color-forest);
  color: var(--color-ivory);
  border: 1px solid var(--color-forest);
}
.btn-primary:hover { background: var(--color-evergreen); border-color: var(--color-evergreen); }
.btn-primary:active { transform: scale(0.98); }

.btn-secondary {
  background: transparent;
  color: var(--color-forest);
  border: var(--border-specimen);
}
.btn-secondary:hover { background: rgba(142, 137, 126, 0.05); }
.btn-secondary .btn-label { display: inline-block; transition: transform var(--duration-base) var(--ease-conservatory); }
.btn-secondary:hover .btn-label { transform: translateY(-2px); }

.btn:focus-visible, a:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible, button:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

.link-architectural {
  position: relative;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 1.05rem;
  color: var(--color-forest);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 1px solid rgba(var(--color-forest-rgb), 0.4);
}
.link-architectural:hover { border-bottom-color: var(--color-forest); }
/* On Blush Cream surfaces the small italic link text drops to Deep Meadow:
   even the darkened Meadow Green sits closer to the 4.5:1 AA line there
   than a link (an interactive element users must notice) should. Deep
   Meadow measures 6.7:1 on linen. (2026-07-13) */
.section--linen .link-architectural,
.card--linen .link-architectural { color: var(--color-evergreen); }

/* Always-visible underline for inline body links (accessibility: not hover-only) */
.prose a {
  color: var(--color-link);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

/* ==========================================================================
   Navigation
   ========================================================================== */

.nav {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-5);
  /* Was 0.92 opacity — found during a 2026-07-12 visual QA pass that this
     let scrolled-under content (button labels, headline text) ghost through
     distractingly on mobile, since the sticky nav sits directly over
     content as the page scrolls beneath it. Raised to fully opaque. */
  background: var(--color-ivory);
  backdrop-filter: none;
  border-bottom: 1px solid transparent;
  transition: border-color var(--duration-fast) ease;
}
.nav.is-scrolled { border-bottom-color: var(--border-hairline); }

.nav__logo {
  font-family: var(--font-serif);
  font-size: 1.25rem;
  color: var(--color-forest);
  text-decoration: none;
}

.nav__links {
  display: none;
  align-items: center;
  gap: var(--space-6);
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav__links a {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-forest);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 2px solid transparent;
}
.nav__links a:hover, .nav__links a[aria-current="page"] {
  border-bottom-color: var(--color-gold);
}
@media (min-width: 1024px) {
  .nav__links { display: flex; }
  .nav__toggle { display: none; }
}

.nav__toggle {
  background: none;
  border: none;
  cursor: pointer;
  padding: var(--space-2);
  color: var(--color-forest);
}

/* The persistent nav CTA only appears once there's room for it alongside
   the full link list (desktop). On mobile it lives inside the full-screen
   menu instead, so the collapsed nav bar never has to fit three items
   (logo + hamburger + button) into a narrow width. */
.nav__cta { display: none; }
@media (min-width: 1024px) {
  .nav__cta { display: inline-flex; padding: 10px 24px; font-size: 12px; }
}

.nav__mobile-panel {
  position: fixed;
  inset: 0;
  background: var(--color-ivory);
  z-index: 30;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-6);
}
.nav__mobile-panel.is-open { display: flex; }
.nav__mobile-panel a {
  font-family: var(--font-serif);
  font-size: 1.75rem;
  color: var(--color-forest);
  text-decoration: none;
}
.nav__mobile-close {
  position: absolute;
  top: var(--space-5);
  right: var(--space-5);
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-forest);
}

/* ==========================================================================
   Cards
   ========================================================================== */

.card {
  background: var(--color-ivory);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--card-padding-mobile);
  transition: box-shadow var(--duration-base) var(--ease-conservatory),
              transform var(--duration-base) var(--ease-conservatory);
}
@media (min-width: 640px) {
  .card { padding: var(--card-padding-tablet); }
}
@media (min-width: 1024px) {
  .card { padding: var(--card-padding-desktop); }
}
.card:hover {
  box-shadow: var(--shadow-card-hover);
  transform: translateY(-2px);
}
/* FIX 2026-07-13: Blush Cream (--color-linen) and Warm Ivory (the default
   .card and .section background) are both very pale, near-white tones —
   close enough in lightness that a linen card sitting on an ivory section
   was reading as barely different, not as a deliberate highlight. Plain
   cards get their definition from --shadow-card alone; card--linen now
   also gets a crisp 1px Pink Deep border, so the extra visual weight is
   real rather than resting on a fill-color difference too subtle to read
   at a glance. Pink Deep (not the lighter Signature Pink) specifically
   because it's the token already established as safe for enough contrast
   to read as text elsewhere — see docs/design-system.md. */
.card--linen { background: var(--color-linen); border: 1px solid var(--color-pink-deep); }
.card h3 { margin-bottom: var(--space-3); }
.card p { margin-bottom: var(--space-4); font-size: 16px; }

/* ==========================================================================
   Form controls
   ========================================================================== */

.field { margin-bottom: var(--space-5); max-width: var(--width-reading); }
.field label {
  display: block;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 14px;
  color: var(--color-forest);
  margin-bottom: var(--space-2);
}
.field input[type="text"],
.field input[type="email"],
.field textarea,
.field select {
  width: 100%;
  min-height: 44px;
  padding: var(--space-3) var(--space-4);
  font-family: var(--font-sans);
  font-size: 18px;
  color: var(--color-forest);
  background: #FFFFFF;
  border: var(--border-hairline);
  border-radius: var(--radius-input);
}
.field textarea { min-height: 120px; resize: vertical; }
.field input:hover, .field textarea:hover, .field select:hover { border-color: var(--border-strong); }

.field--error input, .field--error textarea { border-color: var(--color-error); }
.field__error {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-error);
  font-size: 14px;
  margin-top: var(--space-2);
}

/* The checkbox/radio itself stays visually 20px, but the row it sits in is
   given a 44px minimum height and the label is clickable, so the real
   touch/click target (row + label) meets the 44px accessibility minimum
   without the input graphic itself looking oversized. */
.checkbox-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  min-height: 44px;
}
.checkbox-row input[type="checkbox"], .checkbox-row input[type="radio"] {
  width: 20px;
  height: 20px;
  margin: 0;
  accent-color: var(--color-forest);
  flex-shrink: 0;
}
.checkbox-row label { font-size: 16px; cursor: pointer; }

/* ==========================================================================
   Icons (line-art, 1.5px stroke)
   ========================================================================== */

.icon {
  width: 24px;
  height: 24px;
  stroke: var(--color-moss);
  fill: none;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: stroke var(--duration-fast) ease;
}
.icon--small { width: 20px; height: 20px; }
a:hover .icon, button:hover .icon { stroke: var(--color-forest); }

/* ==========================================================================
   Botanical accent
   ========================================================================== */

.botanical-accent {
  width: 64px;
  height: 64px;
  opacity: 0.12;
  stroke: var(--color-bronze);
  fill: none;
  stroke-width: 1.2;
}
.botanical-accent--paired { margin-bottom: var(--space-3); }

/* ==========================================================================
   Signature badge — the one place Signature Pink (#FFADAD) is used, matched
   to the existing business card / Practice Better mark. Fill only, dark
   text on top; never used as a text or link color. See docs/design-system.md
   "Cross-touchpoint accent colors" for the contrast reasoning.
   ========================================================================== */

.signature-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 88px;
  height: 88px;
  border-radius: 50%;
  background: var(--color-signature-pink);
  flex-shrink: 0;
}
.signature-badge span {
  font-family: var(--font-serif);
  font-size: 1.75rem;
  color: var(--color-forest);
}

/* ==========================================================================
   Images
   ========================================================================== */

.photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--radius-sharp);
}
.photo-frame {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-sharp);
}
/* Color-grade real photography toward the palette using a duotone-style
   overlay. REVISED 2026-07-12: the original overlay (22% dark forest via
   multiply) was tuned for a muted, dark palette — applied to the vibrant
   approved hero photo (colorful mural background), it would visibly mute
   exactly the warmth and color the founder asked for. Reduced to a much
   lighter touch so photography stays vibrant; still a faint nod to
   "photography as part of the brand system," not a strong duotone. */
.photo-frame::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, rgba(74, 120, 86, 0.08), rgba(227, 162, 62, 0.04) 60%);
  mix-blend-mode: multiply;
  pointer-events: none;
}
.photo-frame--ratio-portrait { aspect-ratio: 4 / 5; }
.photo-frame--ratio-landscape { aspect-ratio: 3 / 2; }

/* ==========================================================================
   Motion utility (scroll reveal)
   ========================================================================== */

/* Scoped to html.js (set by design-system.js's first statement) so content
   is only ever hidden when the script that reveals it is actually running.
   Without this gate, any environment where the script doesn't execute —
   JS disabled, a blocked/failed script request, some reader modes — left
   every .reveal section at opacity 0 permanently. Progressive enhancement:
   no JS, no hiding. (2026-07-13) */
.js .reveal {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--duration-slow) var(--ease-conservatory),
              transform var(--duration-slow) var(--ease-conservatory);
}
.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
}

/* ==========================================================================
   Skip link (accessibility)
   ========================================================================== */

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--color-forest);
  color: var(--color-ivory);
  padding: var(--space-3) var(--space-5);
  z-index: 100;
  text-decoration: none;
}
.skip-link:focus {
  left: var(--space-4);
  top: var(--space-4);
}

/* ==========================================================================
   Swatch / scale demo utilities (test page only)
   ========================================================================== */

.demo-block { margin-bottom: var(--space-10); }
.demo-label { font-family: var(--font-sans); font-size: 13px; color: var(--text-secondary); margin-bottom: var(--space-3); text-transform: uppercase; letter-spacing: 0.1em; }

.swatch-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: var(--space-4); }
.swatch {
  border-radius: var(--radius-input);
  overflow: hidden;
  border: var(--border-hairline);
}
.swatch__color { height: 72px; }
.swatch__meta { padding: var(--space-3); background: #fff; font-family: var(--font-sans); font-size: 13px; }
.swatch__meta strong { display: block; font-size: 14px; }

.type-row { display: flex; align-items: baseline; gap: var(--space-5); padding: var(--space-4) 0; border-bottom: var(--border-hairline); }
.type-row__label { width: 140px; flex-shrink: 0; font-family: var(--font-sans); font-size: 12px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.08em; }

.space-row { display: flex; align-items: center; gap: var(--space-4); margin-bottom: var(--space-3); }
.space-row__bar { background: var(--color-forest); height: 12px; }
.space-row__label { width: 90px; flex-shrink: 0; font-family: var(--font-sans); font-size: 13px; color: var(--text-secondary); }

.shadow-demo { display: flex; gap: var(--space-7); flex-wrap: wrap; padding: var(--space-6) 0; }
.shadow-demo__box { width: 160px; height: 100px; background: var(--color-ivory); border-radius: var(--radius-card); display: flex; align-items: center; justify-content: center; font-family: var(--font-sans); font-size: 12px; color: var(--text-secondary); }

footer.section {
  background: var(--color-evergreen);
  color: var(--text-on-dark);
}
/* Sage-bright, not Sage — see the token comment: Sage measures 4.29:1 on
   the evergreen footer, under the 4.5:1 AA minimum for its small text. */
footer.section a { color: var(--color-sage-bright); }
