/* ==========================================================================
   Hope and Heart Counselling — Stage 2 stylesheet
   Palette, type, layout per the brief's design system + your typography spec.
   See progress-notes.md for the accessibility-contrast decisions behind
   the color values below (some are darkened from the brief's raw brand
   hexes specifically for text/button-label use — see notes there).
   ========================================================================== */

/* ---- Self-hosted fonts (no external font CDN) ------------------------- */
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces/fraunces-latin-500-normal.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces/fraunces-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Karla";
  src: url("../fonts/karla/karla-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Karla";
  src: url("../fonts/karla/karla-latin-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ---- Palette -----------------------------------------------------------
   Raw brand colors (--sage, --terracotta) are for backgrounds, borders and
   large decorative use only. For TEXT — links, button labels, small UI —
   use the "-text" variants: they're darkened versions of the same hue,
   chosen so they clear WCAG AA (4.5:1) on both cream and white.

   Three genuinely distinct text colors, not one dark color reused
   everywhere: --heading (a deep sage/teal), --body-text (warm grey), and
   --terracotta-text (links + CTAs). All checked for contrast below.
   -------------------------------------------------------------------- */
:root {
  --sage: #5DCAA5;
  --sage-text: #2E6552;       /* sage, darkened — 5.89:1 on cream. Also used as --heading. */
  --terracotta: #D85A30;
  --terracotta-text: #A24324; /* terracotta, darkened for accessible links — 5.42:1 on cream, 6.24:1 white-on-it. No longer used for button color (round 5: buttons are neutral grey — see .btn below). */
  --cream: #F1EFE8;
  --charcoal: #2C2C2A;        /* near-black — used sparingly (nav chrome), not for headings or the footer any more */
  --heading: #2E6552;         /* deep sage/teal — headings only. Same value as --sage-text (kept as a separate name for clarity in the rules below). */
  --body-text: #6C675F;       /* warm grey, 4.88:1 on cream — clearly distinct from --heading. Round 5: also now the single neutral color for all button/CTA links. */
  --white: #FFFFFF;
  --band-tint: #EEF4F0;       /* round 5: lightened from #DCEBDF — a paler, less cold/heavy sage tint. Top banner + alternating homepage section bands. 5.03:1 body-text contrast. */
  --footer-bg: #8FA089;       /* muted sage-grey — footer background, not near-black */

  --font-heading: "Fraunces", Georgia, "Times New Roman", serif;
  --font-body: "Karla", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  --fs-body: 18px;
  --lh-body: 1.7;

  --content-max: 56.25rem;   /* Round 18 (item 2): raised from 46rem (900px, was 736px) -- K's deliberate decision, not a reversal of the Round 16/17 width hold (that hold covered this exact variable on purpose, pending this round). Everything that reads from this variable (body text, list items, .faq-item, article images, the footer text, the Contact iframe capped in Round 17) follows automatically -- nothing hardcodes 900px anywhere. */
  /* Round 10 (item 3): raised from 72rem. The container's own
     max-width + margin:auto centering was STACKING with --page-gutter's
     padding below once the viewport got wide enough to exceed 72rem
     (1152px) -- e.g. at 1440px that was 144px of auto-margin *plus*
     ~158px of gutter padding, over 300px total, not the ~164px intended.
     100rem (1600px) is comfortably past ordinary laptop/desktop widths, so
     --page-gutter's clamp() is the only thing setting the inset across
     that whole practical range; max-width only steps in on genuinely
     ultra-wide monitors, same as it always did, just at a higher bar. */
  --page-max: 100rem;
  /* The content column's side gutter. Round 11 (item 3): now applied
     UNCONDITIONALLY at every viewport width, not just desktop -- it used
     to be a flat 1.25rem fixed floor below the 48em breakpoint, with this
     clamp() only kicking in above it. That's exactly why the margin felt
     proportional on desktop (~11.2% of viewport) but cramped on mobile
     (~4.5%, since 1.25rem stayed flat regardless of how narrow the
     viewport got). clamp(1.25rem, 11vw, 10.25rem) already behaves
     correctly at mobile widths on its own (e.g. ~11vw at 390px is well
     above the 1.25rem floor), so removing the old two-tier split and
     using this single value everywhere keeps the gutter at a steady ~11%
     of viewport width continuously from mobile through desktop, only
     flooring at 1.25rem on the very narrowest phones and capping at
     10.25rem (164px) on ultra-wide viewports. */
  --page-gutter: clamp(1.25rem, 11vw, 10.25rem);
}

/* ---- Reset / base -------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--cream);
  color: var(--body-text);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}
img { max-width: 100%; height: auto; display: block; }

/* ---- Sitewide top navigation ---------------------------------------------
   Full-bleed cream bar (not a separate white strip), a subtle bottom
   border instead of a hard edge, logo left, links right, collapsing to a
   hamburger menu on mobile. Auto-inserted on every page by build.py --
   see partials/nav.html.
   -------------------------------------------------------------------- */
.site-nav {
  background: var(--cream);
  border-bottom: 1px solid #DDD8CC;
  box-shadow: 0 1px 6px rgba(44, 44, 42, 0.04);
}
/* Round 17 (item 4): horizontal padding was a fixed 1.25rem, unrelated
   to --page-gutter -- so the logo sat at x=20 and the last nav link
   ended at x=1420, against page content starting at 158.4 and ending at
   1281.6 (1440px viewport). max(1.25rem, calc(var(--page-gutter) - 2.5rem))
   puts the nav bar 40px outside the content edges on both sides
   (deliberately framing the page rather than aligning exactly to it,
   per the fix as specified) -- logo at 118.4, "Contact" ending at
   1321.6. The max() floor keeps mobile unchanged at 20px, since
   --page-gutter is small enough there that the calc() would otherwise
   go negative. Vertical padding (0.75rem) is untouched. */
.site-nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0.75rem max(1.25rem, calc(var(--page-gutter) - 2.5rem));
}
.site-nav-logo {
  display: inline-block;
  line-height: 0;
}
.site-nav-logo img {
  height: 40px;
  width: auto;
}
.site-nav-links {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  margin: 0;
  padding: 0;
}
.site-nav-links a {
  color: var(--charcoal);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  padding-bottom: 3px;
  border-bottom: 2px solid transparent;
}
.site-nav-links a:hover, .site-nav-links a:focus-visible {
  border-bottom-color: var(--terracotta-text);
  color: var(--terracotta-text);
}
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
}
.nav-toggle-bar {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--charcoal);
  margin: 0 auto;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.nav-toggle.is-open .nav-toggle-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle.is-open .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle.is-open .nav-toggle-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 47.99em) {
  .nav-toggle { display: flex; }
  .site-nav-links {
    display: none;
    flex-direction: column;
    width: 100%;
    gap: 0;
    padding: 0.5rem 0 1rem;
  }
  .site-nav-links.is-open { display: flex; }
  .site-nav-links li { width: 100%; text-align: center; }
  .site-nav-links a { display: block; padding: 0.6em 0; }
  /* Round 23 (item 2, K 9 Oct 2026): on phones each menu link is a
     full-width block, so the 2px bottom border ran edge to edge. Here the
     border stays (transparent, so nothing moves) and the underline is
     drawn under the word itself instead. Colour stays terracotta. Desktop
     nav is untouched (border under the word, as before). */
  .site-nav-links a:hover, .site-nav-links a:focus-visible {
    border-bottom-color: transparent;
    text-decoration: underline;
    text-decoration-color: var(--terracotta-text);
    text-decoration-thickness: 2px;
    text-underline-offset: 0.4em;
  }
  .site-nav-inner { flex-wrap: wrap; }
}

/* ---- Headings -------------------------------------------------------------
   Fraunces, medium/semibold only (500/600 — the only weights loaded, so
   there's no thin/light instance available to fall back to accidentally).
   Deep sage/teal color (--heading), distinct from both body text (warm
   grey) and links/CTAs. A clear three-step type scale: each level steps
   down in both size AND weight from the one above it.

   Round 5: the size ratio between H1 and body text was close to 2x
   (and more like 3.5x at the desktop breakpoint) -- brought down to
   roughly 1.5-1.75x across the board, leaning on weight + letter-spacing
   for hierarchy instead of sheer size. Hero-title, .section-heading and
   the FAQ summary sizes (set separately below/further down) were scaled
   down to match.
   -------------------------------------------------------------------- */
h1, h2, h3, h4 {
  font-family: var(--font-heading);
  line-height: 1.25;
  color: var(--heading);
  letter-spacing: -0.01em;
  margin: 1.4em 0 0.6em;
  clear: both; /* so a heading never wraps beside a floated photo above it */
}
h1 { font-size: 1.75rem;   font-weight: 700; margin-bottom: 0; }  /* 28px mobile → 34px desktop, ~1.56x → 1.89x body (18px). Round 15 (item 3): margin-bottom zeroed -- see the explicit 32px H1-gap rules further down, which replace whatever this margin used to (inconsistently) collapse or add with per page. */
h2 { font-size: 1.5rem;    font-weight: 700; }  /* 24px → 28px, bumped to 700 so it holds presence at the smaller size */
h3 { font-size: 1.2rem;    font-weight: 600; }  /* ~19px → 21px */
h4 { font-size: 1.125rem;  font-weight: 600; }  /* 18px → 19px, same size as body, weight alone marks it as a heading */

@media (min-width: 48em) {
  h1 { font-size: 2.125rem; } /* 34px */
  h2 { font-size: 1.75rem; }  /* 28px */
  h3 { font-size: 1.3125rem; } /* 21px */
  h4 { font-size: 1.1875rem; } /* 19px */
}

h1:first-child, h2:first-child { margin-top: 0; }

/* Round 15 (item 3): uniform 32px gap between the page's H1 and the
   first content element beneath it, sitewide. Previously ranged from
   20.4px (article/Therapies/FAQ/Contact/Privacy-Policy pages, where a
   plain <p> or similarly margin-top:0 element followed the H1 directly
   -- the gap was just h1's own old 0.6em margin-bottom) up to 40.0px
   (Home, where the gap chained through TWO separate margins: the H1's
   own margin-bottom collapsing with .two-col's 1.75rem margin-top,
   plus .hero-subtitle's own additional margin-top nested inside that)
   and 27-28px (Resources/About, a single collapse against that page's
   first element's own default top margin). h1's own margin-bottom is
   zeroed above so it can never contribute to or collapse with
   whatever follows; each page type's actual first content element
   (verified per-page by rendering, not assumed) gets an explicit
   32px margin-top here instead, so the value no longer depends on
   what that element happens to be. */
.page > h1 + .two-col,
.page > h1 + .faq-item,
.page > h1 + iframe,
.page > h1 + p,
.page > h1 + .link-list,
.hero > h1 + .two-col {
  margin-top: 2rem; /* 32px */
}


.section-heading {
  font-size: 1.5rem;
  font-weight: 700;
}
@media (min-width: 48em) {
  .section-heading { font-size: 1.75rem; }
}

.page > h1:first-child,
.page > h2:first-child,
.page > h3:first-child,
.band .page-inner > h1:first-child,
.band .page-inner > h2:first-child {
  text-align: center;
}

/* Round 6 (item 8): explicit class for headings that need centering but
   aren't the first child of their container -- e.g. "What are the
   outcomes?", which follows the "Who is Karon Ng?" copy in the same band.
   Not :first-child-dependent, so it's robust at every breakpoint. */
.heading-center {
  text-align: center;
}

/* Round 15 (item 5): the "Reference"/"References" heading on article
   pages was rendering at the same 28px size and the same green as the
   34px article H1, reading as near-equal to the article title. Stays a
   real <h2> (markup unchanged, per instruction) -- only a class added
   for this specific styling hook, same pattern as .section-heading/
   .heading-center above. Left-aligned as it already was (not a
   :first-child heading, so the sitewide auto-center rule never applied
   to it). */
.article-reference-heading {
  font-size: 1.25rem; /* ~20px */
  font-weight: 600;
}

/* Round 8: scoped to .band .page-inner (the homepage's single-column
   sections) rather than every .page-inner -- the footer now also uses
   .page-inner for its shared-width container (item 1), and its paragraphs
   must stay left-aligned, not centered.
   Round 18 (item 3): added max-width: none. Without an explicit override
   here, the sitewide `p, li, blockquote { max-width: var(--content-max) }`
   rule (lower specificity, but the only rule that was setting max-width
   for these paragraphs at all) still capped the "What are the outcomes?"
   intro, "How do I start?", and the Featured resource link to the
   reading measure -- narrower than the four sections above them, which
   this override now matches to the full band container width. Deliberately
   scoped to direct-child band paragraphs only -- does not reach
   .two-col-text paragraphs (the Karon bio, the hero intro), which keep
   their own reading-width cap untouched. */
.band .page-inner > p {
  text-align: center;
  max-width: none;
  margin-left: auto;
  margin-right: auto;
}

/* ---- Body text ------------------------------------------------------- */
/* Round 15 revision (item A): p/li/blockquote are capped to the 46rem
   reading measure but were never centered within .page -- they just sat
   flush against .page's left edge, narrower than .page's own content
   width. Meanwhile `.page > h1:first-child` (see the centering rule
   further down) is text-align:center within a box that DOES span
   .page's full content width, so its centered text lands on .page's
   true center -- a different point from the flush-left paragraph's own
   visual center, and the gap between the two widens with viewport width
   (confirmed by rendering: 61px at 1100px, 100px at 1201px, 194px at
   1440px, on Privacy Policy and Therapies). Fix: give p/li/blockquote
   margin-left/right: auto too, so their own (still 46rem-capped, still
   not widened) box is centered within .page instead of flush-left --
   its center then coincides with the h1's already-correct center, since
   both are centered within the same parent. No change needed to the h1
   rule itself; it was never the one that was wrong. Two-col text, the
   footer, and .band .page-inner paragraphs are explicitly exempted
   further down since they have their own intentional alignment. */
p, li, blockquote { max-width: var(--content-max); margin-left: auto; margin-right: auto; }
p { margin: 0 auto 1.2em; }
ul, ol { margin: 0 0 1.2em; padding-left: 1.4em; }
li { margin-bottom: 0.5em; }

/* ---- Two-column photo/text layout (round 7) -------------------------------
   Text in one column, photo(s) in the other, both starting level at the
   top of the row via align-items: start. .two-col-text keeps left-aligned
   text regardless of the section heading's centering. .two-col-photo holds
   one photo -- same class regardless of page/section, with a modifier
   class per photo picking its own fixed aspect-ratio (see below). Drops
   to a single stacked column on mobile/tablet, photo(s) following the
   text in document order.

   Round 10 (item 1) -- ROOT CAUSE FIX: this used to be align-items: stretch
   with the photo column's height derived from the paired text column's
   height (a position:absolute image filling a stretched container). That
   meant every photo's on-screen shape depended on how much text sat
   beside it, which itself depends on viewport width -- so resizing the
   browser silently reflowed each photo's crop, revealing/hiding content
   unpredictably (confirmed: the same photo measured a 1.32 width:height
   ratio at one width and 1.14 at another). Photos now get a genuinely
   FIXED CSS aspect-ratio instead (set per photo via a modifier class,
   below) that has nothing to do with the sibling text's height -- the
   shape is constant at every viewport width, only the absolute size
   scales. align-items: start replaces stretch so each column just sizes
   to its own natural content and both start at the same top edge (this
   is also the item 4 fix -- previously "stretch" plus a taller text
   column, e.g. About's intro text with a stacked photo appended below
   it, could pull the row height taller than intended in ways that read
   as the photo starting lower than the text; start-aligned, fixed-height
   boxes can't drift like that).
   -------------------------------------------------------------------- */
.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem 2.5rem;
  align-items: start;
  margin: 1.75rem 0;
}
/* Round 8: hero's .two-col sits directly inside .hero, which (unlike
   .page-inner and .page) has no side padding of its own -- only .hero's
   direct p/h1/h2/h3 children get centered via max-width+margin:auto
   (see .hero rules further down), and a grid div doesn't match that
   selector. That's what let this row run edge-to-edge. Giving .hero
   .two-col the same max-width/margin/padding recipe as .page-inner fixes
   it without touching every other .two-col usage (those already sit
   inside an already-padded .page-inner or .page). */
.hero .two-col {
  max-width: var(--page-max);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--page-gutter);
  padding-right: var(--page-gutter);
}
.two-col-text {
  text-align: left;
}
.two-col-text p, .two-col-text li, .two-col-text blockquote {
  max-width: none;
  margin-left: 0;
  margin-right: 0;
}
/* A photo that stacks below the text inside the SAME .two-col-text column
   (About page intro section) rather than sitting in the paired photo
   column. Round 10 (item 1): now also gets a fixed aspect-ratio via a
   modifier class -- see .stacked-photo--room-wide below -- instead of
   rendering at whatever its own intrinsic size happened to be. */
.two-col-text .stacked-photo {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 0.75rem;
  margin-top: 0.75rem;
  object-fit: cover;
}
/* Round 10 (item 1): fixed aspect-ratio, not height-matched to sibling
   text -- see the .two-col comment above for the full root-cause
   explanation. This base rule is just the shared crop/rounding
   mechanics; each modifier below sets the actual aspect-ratio and any
   object-position bias for its specific photo. */
.two-col-photo {
  border-radius: 0.75rem;
  overflow: hidden;
}
/* Round 13 (item 1): the real bug behind three rounds of "photo sits
   below its paired text" reports. The sitewide `.page img` rule further
   down this file (intended for article-body photos) has the SAME
   specificity as a plain `.two-col-photo img` (one class + one tag
   each) and comes later in the file, so on the About page -- whose
   whole content sits inside <main class="page"> -- it was winning the
   cascade tie-break and adding `margin: 1.6em auto` (28.8px) to these
   images too, regardless of what this rule declared (a same-specificity
   tie is broken by source order, not by which rule "looks" more
   specific to a human reader -- an earlier attempt at this fix added
   margin: 0 here without raising specificity, and .page img still won).
   The WRAPPER (.two-col-photo, which is what every previous round's
   bounding-box measurements checked) stays exactly where the fixed
   aspect-ratio puts it, so those checks kept coming back clean -- but
   the actual <img> inside was rendering 28.8px lower than its wrapper,
   with its own bottom 28.8px clipped off by the wrapper's
   `overflow: hidden`. That's what was actually visible: a photo sitting
   visibly low and slightly more cropped than intended. Fixed by
   qualifying the selector with the outer .two-col wrapper -- every
   .two-col-photo is nested inside a .two-col ancestor (see the two-col
   grid sections above), so this is two classes + a tag, genuinely
   higher specificity than .page img's one class + a tag, and wins
   regardless of source order (not just today's file order). max-width:
   none is the same defensive override already used for
   .stacked-photo--room-wide below, for the same reason. */
.two-col .two-col-photo img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  margin: 0;
  object-fit: cover;
  object-position: center;
}
/* Round 14 (item 2): universal visible-text-alignment nudge for every
   two-col photo -- Home's Karon photo and hero photo never had this
   applied (only About's two photos did, via Round 12's per-page rules
   below, now removed), so at rest a photo's top edge sits 4.00px ABOVE
   the first visible glyph of its paired text (confirmed identical on
   both Home and About, at 1100/1169/1440px, before any nudge -- this is
   a consistent artifact of the grid/line-box metrics, not something
   that varies by page). About's old 0.5em (~9.3px) nudge overshot this
   by roughly double, landing 5px too far down instead of correcting the
   4px gap. Measured directly (Range over the first text node's first
   character vs. the photo wrapper's own top) and confirmed this single
   4px value produces an exact 0.00px diff on Home Karon, About intro,
   and About Karon alike, at every desktop width tested -- one rule, one
   number, no per-page tuning. (Mobile is excluded on purpose: below the
   48em breakpoint the two-col grid collapses to a single stacked
   column, so "photo top vs. text top" isn't a meaningful side-by-side
   comparison there -- see the mobile media query below for the
   stacking/order rules that actually apply at that width.) */
.two-col .two-col-photo {
  /* Round 15 (item 1): the Round 14 measurement (this rule's old 4px
     value) compared the photo's top edge against the FONT-BOX top of
     the paired text -- what getBoundingClientRect() and a plain DOM
     Range both return -- which reads 0.00px even when the photo is
     still visibly high, because a font box sits 5-6px above where the
     letter's actual ink starts (internal leading). Measured properly
     this time via the canvas 2D API (fontBoundingBoxAscent minus
     actualBoundingBoxAscent gives the missed offset) against the real
     deployed build: Home Karon -5.00px, About intro -4.00px, About
     Karon -5.00px (photo still above the ink top by that much, even
     with the old 4px nudge already applied). A single shared value of
     8.7px (4px old + 4.67px, the average of the three deltas) lands
     every pairing within 0.7px of exact -- re-verified after this
     change: Home Karon +0.30px, About intro -0.70px, About Karon
     +0.30px, all under the 1px tolerance. The home hero photo needed
     a much larger correction (-16.00px, roughly 10px beyond the other
     three) and gets its own dedicated rule below rather than being
     folded into this shared value. */
  margin-top: 8.7px;
}
/* Round 15 (item 1): home hero photo needs its own correction --
   -16.00px against ink-top on the deployed build, well beyond the
   ~5px the other three pairings needed, so folding it into the shared
   8.7px above would leave it badly short. New total: 4px (old shared
   value already baked into that -16.00px reading) + 16px = 20px.
   Qualified with .two-col (three classes total: .two-col,
   .two-col--home-hero, .two-col-photo) so it reliably beats the
   two-class shared rule above regardless of file order -- the same
   specificity lesson as Round 13's photo-alignment bug and Round 14's
   article-image bug, applied deliberately this time rather than found
   the hard way again. */
.two-col.two-col--home-hero .two-col-photo {
  margin-top: 9px;
}
/* Hero/corner photo (home page). 4:5 sits just inside the source photo's
   own ~0.78 ratio, so cropping is minimal; still biased down (Round 9's
   crop direction) to favour the side table and sofa over empty wall. */
.two-col-photo--room {
  aspect-ratio: 4 / 5;
}
.two-col-photo--room img {
  object-position: 50% 82%;
}
/* Karon's portrait -- home + About. Round 10 (item 2): the "still cropped
   too tight at the top" complaint kept recurring because the old crop
   amount could vary with paired text height. Fixed differently from the
   other photos here: 3:4 is deliberately NARROWER than the new hi-res
   source photo's own ~0.93 ratio, so object-fit: cover crops WIDTH
   (background left/right) to fill the box and never crops height -- the
   top of her hair and her hands at the bottom are both always fully in
   frame, by construction, at every viewport width. Uses the new hi-res
   source file (karon-profile-hires.jpg, from
   "Karon-Halfbody hands down-cropped-optimised for web.jpeg") in place
   of the old low-res karon-profile-photo.jpg. */
.two-col-photo--karon {
  aspect-ratio: 3 / 4;
}
.two-col-photo--karon img {
  object-position: center;
}
/* About page reading-corner photo (about-content-2.jpg, lamp/sofa/
   artwork). Round 10 (item 1): same fixed-ratio treatment; 3:4 sits just
   inside the source's own ~0.73 ratio, so cropping is minimal. */
.two-col-photo--reading-corner {
  aspect-ratio: 3 / 4;
}
/* About page room-wide photo (door + both sofas + window) -- Round 10
   (items 1 & 4): the previous about-content-1.jpg was cropped so tight
   it excluded the window and the second seating area entirely, even
   though nothing in the CSS was cropping it -- that content simply
   wasn't in the source file itself (confirmed: no CSS crop was applied
   to it at all before this round). Replaced with the same wide shot the
   live site uses (recovered directly from the live site -- none of the
   raw candidate photos on file captured this framing), now sized to its
   own native ~3.3:1 aspect-ratio via this modifier instead of being left
   to render at an unconstrained intrinsic size. */
.stacked-photo--room-wide {
  aspect-ratio: 1280 / 385;
}
/* Round 11 (item 2): about-room-wide.jpg used to be nested inside
   .two-col-text, so it rendered squeezed into that single ~361px-wide
   column -- badly wrong for a 1280x385 panorama. Named grid areas let it
   span BOTH columns on its own row below the text/reading-corner row,
   at the full width the two columns + gap add up to, while the text and
   reading-corner photo keep their normal side-by-side placement above
   it. Mobile collapses to a single column anyway (see the .two-col
   media query below), but still needs its own area list so the named
   areas stay valid; order there matches the original document order
   (text, then the wide photo, then the reading-corner photo). */
.two-col--about-intro {
  grid-template-areas:
    "text photo"
    "wide wide";
}
.two-col--about-intro .two-col-text { grid-area: text; }
.two-col--about-intro .two-col-photo {
  grid-area: photo;
  /* Round 14 (item 2): the visible-text-alignment nudge itself moved to
     the universal .two-col .two-col-photo rule above (applies to every
     page, not just this one) -- see that comment for the corrected
     4px value and how it was measured. */
}
.two-col--about-intro .stacked-photo--room-wide {
  grid-area: wide;
  width: 100%;
  max-width: none;
  margin: 0;
  display: block;
  border-radius: 0.75rem;
  object-fit: cover;
}
@media (max-width: 47.99em) {
  .two-col--about-intro {
    grid-template-columns: 1fr;
    /* Round 14 (item 5): was "text" "wide" "photo" -- reversed the
       reading-corner photo and the wide sofa photo relative to desktop.
       On desktop these sit in one row (text | photo) followed by wide
       below, so the intended reading order is text, then photo
       (reading-corner), then wide. Fixed to match; confirmed via
       rendered y-position at 386/429px that photo now comes before
       wide. */
    grid-template-areas:
      "text"
      "photo"
      "wide";
  }
  /* Round 14 (item 6): the room-wide photo keeps its desktop 1280:385
     (~3.32:1) aspect-ratio at every width by default, which at a ~318px
     mobile content width renders only ~96px tall -- almost nothing of
     the room is visible. Switched to 16:9 below the mobile breakpoint
     only (desktop crop is untouched). Checked the actual source file at
     this exact crop (center object-position, the existing default --
     no override needed): a 16:9 center crop keeps both sofas and the
     full door in frame, plus a partial view of the window, losing only
     the outermost slivers on each side (a little of the left sofa's arm,
     most of the window). 16:9 was chosen over 3:2 specifically because
     it retains more of the original width (53.5% vs. 45.1%), which is
     what keeps both sofas in frame at all -- 3:2 was tested and crops
     too tight to reliably keep both. */
  .stacked-photo--room-wide {
    aspect-ratio: 16 / 9;
  }
}
/* Round 11 (items 4 & 5): Karon's portrait and the home hero's room
   photo both use a genuinely FIXED aspect-ratio (see .two-col-photo--
   karon / --room above), which is correct for avoiding resize-distortion
   (Round 10), but at an even 1fr/1fr column split their fixed-ratio
   height ran well past their paired text -- Karon's photo measured
   103-113% of her bio's height (target: 65%) and the home hero photo
   ended ~250px below its own short intro text. Rather than resurrect
   the height-matching mechanism that caused Round 10's resize bug,
   these modifiers narrow the PHOTO's grid column specifically -- the
   photo's absolute width (and so, at a fixed aspect-ratio, its height)
   shrinks, while the text column keeps its normal width and object-fit:
   cover keeps the crop itself undistorted at every size. */
/* Two separate ratios, not one shared class: the home and About Karon
   sections pair the identical photo against different amounts of bio
   text (About: 3 paragraphs: Home: 4, since Home's bio splits an extra
   paragraph out).

   Round 11 tuned all three of these (.two-col--karon-home/-about and
   .two-col--home-hero) to hit exact height-matching targets, but only
   ever measured/verified at a single 1440px desktop viewport. Because
   these are all fr-based (proportional) column splits, the resulting
   photo sizes shrink continuously as the viewport narrows -- at the (more
   realistic, non-maximized) ~1100px width the user was actually viewing
   at, About Karon rendered at just 158x211px and the hero photo at
   125x156px, both looking cramped even though the 1440px numbers looked
   fine. Round 12 re-tuned About Karon and the hero photo for a
   comfortably-sized look across BOTH 1440px and ~1100px (rendered and
   measured at both widths, not estimated) -- 0.65fr for About Karon
   (was 0.24fr) and 0.55fr for the hero photo (was 0.18fr), the latter
   chosen so it also comes out larger than Karon's own home-page photo at
   every width (Karon shouldn't be the bigger of the two, per the brief),
   and so its bottom edge nearly meets the intro text's bottom edge at
   ~1100px, closing the empty space that used to sit above the Contact Us
   row. Home Karon (.two-col--karon-home) is UNCHANGED from Round 11
   (0.30fr, still ~65% of its paired text's height) -- this round's brief
   only flagged the About Karon photo and the hero photo as too small,
   not the home Karon photo. */
.two-col--karon-home {
  grid-template-columns: 0.30fr 1fr;
}
/* Round 24 (item 2, K 9 Oct 2026): "Who is Karon Ng?" ended 106px above
   the bottom of its green band (every other homepage section: 56px). The
   extra 50px was the grid's own 1.75rem bottom margin plus the last
   paragraph's bottom margin, neither of which collapses out of a grid.
   Both set to 0 for this section only, so it ends at the band's 56px like
   the rest. About's two-column sections are untouched. */
.two-col--karon-home { margin-bottom: 0; }
.two-col--karon-home .two-col-text > :last-child { margin-bottom: 0; }
.two-col--karon-about {
  grid-template-columns: 0.65fr 1fr;
}
/* Round 14 (item 2): this page-specific nudge was removed -- Home's
   Karon photo never had an equivalent rule, so the two pages drifted
   out of alignment with each other (About +5px, Home -4px, per Round
   13's own numbers). The visible-text-alignment nudge now lives once,
   universally, on .two-col .two-col-photo above, and applies here too. */
.two-col--home-hero {
  grid-template-columns: 1fr 0.55fr;
}
@media (max-width: 47.99em) {
  .two-col--karon-home,
  .two-col--karon-about,
  .two-col--home-hero {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 47.99em) {
  .two-col {
    grid-template-columns: 1fr;
  }
}

/* ---- Testimonials & outcomes -- shared "accent border" treatment ---------
   Round 5: no background fill or box at all any more -- just a colored
   left-border accent, alternating sage/terracotta card-to-card, with
   generous spacing between entries. Applied identically to both the
   testimonials and the "What are the outcomes?" cards for consistency.
   A subtle hover lift (slight shadow, slight shift) is the only other
   visual change -- everything else stays flat/borderless at rest.
   -------------------------------------------------------------------- */
blockquote {
  position: relative;
  margin: 0;
  padding: 0 0 0 1.4em;
  background: none;
  border: none;
  border-radius: 0;
  color: var(--body-text);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
/* Round 7: accent bar is now a FIXED-height mark, not tied to the
   blockquote's own box height (round 6's inset ::before still scaled
   with quote length, which wasn't the actual ask). Height is one body
   line-height (1.7em, matching --lh-body) regardless of how many lines
   the quote runs -- verified against a 5-line and a 3-line quote
   rendering the exact same bar height. `top: 0.5em` approximates the
   cap-height of the first line's first letter (not the line-box top):
   measured directly against the real Karla font at 18px via
   canvas.measureText -- half-leading (4.3px) + (ascent - cap-height)
   (~5px) ≈ 9.3px ≈ 0.5em from the text's own top edge, which is now the
   blockquote's padding-box top since padding-top is 0. */
blockquote::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.5em;
  height: 1.7em;
  width: 3px;
  border-radius: 2px;
  background: var(--sage-text);
  transition: background-color 0.15s ease;
}
blockquote p:last-child { margin-bottom: 0; }
blockquote:hover, blockquote:focus-within {
  transform: translateX(3px);
  box-shadow: 0 4px 16px rgba(44, 44, 42, 0.07);
}

/* ---- Testimonials grid ---------------------------------------------------
   "What clients say": a 4-column grid on desktop, collapsing to a single
   column on mobile/tablet. Generous gap for breathing room now that
   there's no card box to separate entries visually.
   -------------------------------------------------------------------- */
.testimonials {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.25rem 1.75rem;
  max-width: var(--page-max);
  margin: 0 auto;
  /* Round 23 (item 5, K 9 Oct 2026): 28px under "What clients say". This
     collapses with the heading's own 0.6em bottom margin, so the gap is
     exactly 28px at every width (was 17px, 14px on phones). Side margins
     stay auto. The other homepage section headings keep their 17px. */
  margin-top: 1.75rem;
}
@media (min-width: 48em) {
  .testimonials {
    grid-template-columns: repeat(4, 1fr);
  }
}
.testimonials blockquote {
  max-width: none;
}
.testimonials blockquote:nth-child(even)::before { background: var(--terracotta-text); }
/* Round 22 (item 1, K 8 Oct 2026): from 48em (768px) up, two EQUAL columns
   instead of four (the four were ~114-191px of text, and unequal and
   overflowing at 768-1023px). minmax(0, 1fr) keeps both columns the same
   width whatever the quote lengths. Column gap 3.5rem (56px); the row gap
   (2.25rem) is unchanged. Accent bars run in a checkerboard: row 1
   sage | terracotta, row 2 terracotta | sage, and so on -- the even-child
   rule above still sets items 2, 6...; these two rules flip items 3 and 4
   of every group of four. Below 48em nothing changes: one column, bars
   alternating green/red as before. */
@media (min-width: 48em) {
  .testimonials {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 3.5rem;
  }
  .testimonials blockquote:nth-child(4n+3)::before { background: var(--terracotta-text); }
  .testimonials blockquote:nth-child(4n+4)::before { background: var(--sage-text); }
}

/* ---- Outcomes grid ---------------------------------------------------
   "What are the outcomes?": a 2x2 card grid (1 column on mobile), each
   with a small single-color line icon alongside the text. Same
   border-accent treatment as testimonials, alternating color.
   -------------------------------------------------------------------- */
.outcomes-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem 1.75rem;
  max-width: var(--page-max);
  margin: 0 auto;
}
@media (min-width: 40em) {
  .outcomes-grid { grid-template-columns: repeat(2, 1fr); }
}
/* Round 11 (item 6): the colored left-border accent bar (and its
   1.4em padding-left reservation) is removed -- with the icons now in
   place, the bar read as redundant. Icons remain the one visual accent
   per card. */
.outcome-card {
  position: relative;
  display: flex;
  gap: 0.9rem;
  align-items: flex-start;
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.outcome-card:hover, .outcome-card:focus-within {
  transform: translateX(3px);
  box-shadow: 0 4px 16px rgba(44, 44, 42, 0.07);
}
.outcome-icon {
  flex: none;
  width: 30px;
  height: 30px;
  color: var(--sage-text);
}
.outcome-card p {
  margin: 0;
  max-width: none;
}

/* ---- Links -------------------------------------------------------------
   Distinguished by more than color: underline is always present (not
   only on hover), plus a weight bump on hover/focus.
   -------------------------------------------------------------------- */
a {
  color: var(--terracotta-text);
  text-decoration: underline;
  text-underline-offset: 0.15em;
  text-decoration-thickness: 0.08em;
}
/* Round 20 (item 1, K's final decision): body links go from terracotta
   to charcoal on hover/focus, with NO underline thickening (Round 19's
   0.12em thickening is gone). No font-weight change either (Round 19 item
   4: the old bold re-wrapped lines on phones). Links with their own hover
   rules are unaffected and stay exactly as they were: nav (charcoal ->
   terracotta), the .btn links (Contact us pill / Facebook / Return home,
   neutral grey), and the footer (charcoal + 0.12em underline). The focus
   outline rule underneath is unchanged. Charcoal is 12.16:1 on cream and
   12.55:1 on the tint. */
a:hover, a:focus-visible {
  color: var(--charcoal);
}
a:focus-visible {
  outline: 2px solid var(--terracotta-text);
  outline-offset: 2px;
}

/* ---- "Button" links (Contact Us, Facebook, Return home, hero CTA) --------
   Plain text links, not button boxes: no underline at rest, underline
   appears on hover only, followed by a small arrow. Round 5: all three
   (Contact Us, Facebook, and the 404 "Return home" link) now share one
   single neutral color -- the same muted grey the Facebook link already
   used -- instead of Contact Us/hero-CTA being terracotta. There's no
   ".btn-secondary" color distinction left to make (kept as a class for
   the weight difference only, in case a future round wants it back).
   -------------------------------------------------------------------- */
.btn, button {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 1rem;
  color: var(--body-text);
  background: none;
  border: none;
  padding: 0.2em 0;
  text-decoration: none;
  cursor: pointer;
}
.btn::after {
  content: "\2192"; /* → */
  font-weight: 400;
  transition: transform 0.15s ease;
}
.btn:hover, .btn:focus-visible, button:hover, button:focus-visible {
  text-decoration: underline;
  text-underline-offset: 0.15em;
  color: var(--body-text);
}
.btn:hover::after { transform: translateX(3px); }
.btn:focus-visible, button:focus-visible {
  outline: 2px solid var(--body-text);
  outline-offset: 2px;
}
/* Round 6: removed .btn-secondary's font-weight:500 override -- Contact Us
   and Facebook now both use .btn's 600 weight with no distinction. Class
   kept on the Facebook link's markup only as a hook, not styled here. */
.icon-facebook { flex: none; }

/* Round 12 (item 8): Contact Us gets a pill-shaped outlined button
   treatment everywhere the Contact Us / Facebook pair appears (hero CTA
   and every page's closing row, since both render from the one
   partials/bottom-buttons.html) -- Facebook is untouched, still the
   plain text link styled above. Text color is deliberately left as the
   inherited .btn color (var(--body-text)) -- unchanged, per the brief.
   Border color is an explicit rgba (not a var()) at the user's own
   specified value, checked against WCAG 1.4.11's 3:1 non-text-contrast
   requirement for UI component boundaries: rgba(95,94,90,0.75) measures
   3.33:1 on the cream background -- do not lighten the opacity further,
   55% was checked and fails at 2.30:1. */
.btn-primary {
  border-radius: 999px;
  border: 1px solid rgba(95, 94, 90, 0.75);
  padding: 0.75rem 1.875rem; /* ~12px vertical, ~30px horizontal */
  text-decoration: none;
  min-height: 44px;
  box-sizing: border-box;
  transition: border-color 0.15s ease;
}
.btn-primary:hover,
.btn-primary:focus-visible {
  text-decoration: none;
  border-color: rgba(95, 94, 90, 1);
}
.btn-primary:focus-visible {
  outline: 2px solid var(--body-text);
  outline-offset: 3px;
}
/* Mobile: guarantee a 44x44 touch target even though the pill itself is
   already tall enough via padding+min-height -- min-width covers the
   case of a narrow viewport where flex-wrap could otherwise let the
   pill shrink-wrap tighter than 44px on very short label text. */
@media (max-width: 47.99em) {
  .btn-primary {
    min-width: 44px;
  }
}

/* ---- Layout ----------------------------------------------------------
   Centered/hero-style per the brief: the page is a centered column,
   hero-ish intro sections are center-aligned; long-form article
   paragraphs stay left-aligned for readability.
   -------------------------------------------------------------------- */
.page {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 2rem var(--page-gutter) 4rem;
}

/* Full-bleed alternating section "bands" on the homepage, each with its
   own inner max-width container (.page-inner), so the tint spans the
   whole viewport width rather than stopping at the content column.
   Round 5 to Round 20: soft curved seams between bands. Round 21: straight
   edges again (K, 7 Oct 2026) -- see .band-tint below.
   -------------------------------------------------------------------- */
.band {
  padding: 3.5rem 0;
  position: relative;
}
/* Round 21 (item 3, K 7 Oct 2026): homepage bands have straight top and
   bottom edges at every width. The curved edges (50% / min(32px or 56px,
   5%), Rounds 15-17) are gone, and with them the Round 18 :last-child
   rule that squared only the last band's bottom corners. */
.band-tint {
  background: var(--band-tint);
}
.page-inner {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 var(--page-gutter);
}

/* ---- Homepage hero -------------------------------------------------------
   Headline, subheading, a single primary CTA link, on the warm cream
   background, with extra breathing room below the nav.
   -------------------------------------------------------------------- */
.hero {
  background: var(--cream);
  text-align: center;
  max-width: 100%;
  padding-top: 2.5rem;
  padding-bottom: 1.5rem;
}
.hero p, .hero h1, .hero h2, .hero h3 {
  max-width: var(--page-max);
  margin-left: auto;
  margin-right: auto;
}
/* Round 17 (item 3): .hero-title had no side padding of its own, so its
   box ran the full viewport width while every other element on the page
   (including the body text right below it) respects --page-gutter --
   the only heading on the site that didn't. Measured at 390px: headline
   ink ran 27.9 to 362.1, body text 42.9 to 347.1 -- a real, visible
   inset difference, worse narrower still (at 360px the headline came
   within 12.9px of the screen edge against the body text's 39.6px). K
   has confirmed "Counselling in Singapore" wrapping to two lines on the
   narrowest phones as a result of this padding is expected, not a
   regression. */
.hero-title {
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-top: 0;
  padding-left: var(--page-gutter);
  padding-right: var(--page-gutter);
}
/* Round 12 (item 5) switched this from Fraunces/heading-weight to the
   plain body font, to stop it reading as a second headline competing
   with .hero-title above it -- overshot into looking like plain body
   text. Round 13 (item 3) stepped back to Fraunces at 21-22px/600 to
   sit visually between the H1 and body text -- fixed the visual read,
   but it was still an <h2> in the markup, and Round 14 (item 1) retags
   it to a <p> (see index.html) because a forty-word sentence marked as
   a section heading is wrong structurally, independent of how it looks.
   Sized down slightly to read clearly as a styled lead paragraph, not a
   heading that happens to be a <p> -- 19-20px/500, versus the H1's
   28-36px/700 above and the plain body paragraph's 18px/400 below.
   Still Fraunces and still --body-text color, so the visual family
   resemblance to the rest of the page is unchanged; only the weight and
   size moved down a step to match its new, non-heading role. */
.hero-subtitle {
  /* Round 15 (item 2): reversal of Round 13/14's sizing-only fixes --
     those kept the tagline in Fraunces (the heading font), which is
     why it kept reading as a second headline regardless of size/weight
     tuning. The serif itself was the problem. Switched to Karla (the
     body font) at 18px/700, matching the lead-in style already used on
     the resource articles (e.g. "Feeling restless and edgy..." on
     a-brief-explanation-of-ifs-and-parts) -- same body text color,
     same line-height as body copy. Still a <p>, not a heading (see
     Round 14 item 1); wording unchanged. margin-top removed -- this
     element is no longer measured against the H1 on its own (see the
     Round 15 item 3 sitewide H1-gap rule below, which targets the
     .two-col wrapper this paragraph sits inside instead). */
  font-family: var(--font-body);
  font-size: 1.125rem;
  font-weight: 700;
  line-height: var(--lh-body);
  color: var(--body-text);
}
@media (min-width: 48em) {
  .hero-title { font-size: 2.25rem; }
}
.hero-cta {
  padding-top: 1.5rem;
  justify-content: center;
}

/* ---- Homepage hero photo (item 1, round 6) --------------------------------
   A close, warm glimpse of the therapy room -- a portrait crop -- sitting
   centered below the hero's CTA, before the "Who is Karon Ng?" band.
   Deliberately smaller/framed rather than full-bleed, per the "close-detail
   hero shot" brief (distinct from .photo-break's full-width strip further
   down the page).
   -------------------------------------------------------------------- */
.hero-photo {
  margin: 2.25rem auto 0;
  max-width: 300px;
}
.hero-photo img {
  width: 100%;
  border-radius: 0.75rem;
  box-shadow: 0 10px 28px rgba(44, 44, 42, 0.14);
}
@media (min-width: 48em) {
  .hero-photo { max-width: 360px; }
}
.page-404 {
  padding-top: 4rem;
  padding-bottom: 6rem;
}
/* Round 22 (item 3, K 8 Oct 2026): the 404 page now has the standard footer.
   When the page is shorter than the window, the footer is pinned to the
   bottom, so there is no empty cream band under it on tall screens. Scoped
   to the 404 page only (class on its <body>), so no other page can change.
   width: 100% keeps the main area exactly as wide as it was as a plain
   block (in a flex column, its auto side margins would otherwise shrink it
   to fit its content). */
.page-404-body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.page-404-body > * { flex-shrink: 0; }
.page-404-body > main { flex: 1 0 auto; width: 100%; }

/* .photo-break rules removed (Round 9, item 3) -- the succulents strip is gone from home.html; the room photo stays in the hero via .two-col-photo instead. */

/* ---- Top banner (capacity/closure banner) --------------------------------
   Light sage-tinted background with a subtle bottom border, not a solid
   dark bar. Content, on/off, and resume-date are config-driven -- see
   data/banner-config.json and partials/top-banner.html.
   -------------------------------------------------------------------- */
.top-banner {
  background: var(--band-tint);
  border-bottom: 1px solid #C9DBCE;
  color: var(--charcoal);
  text-align: center;
  padding: 0.6em 1rem;
  font-size: 0.95rem;
}
.top-banner p { margin: 0; max-width: none; }
.top-banner a { color: var(--terracotta-text); }
/* Round 20 (item 1): the banner's "Contact us" link keeps exactly its
   Round 19 hover/focus look (stays terracotta, underline thickens to
   0.12em). Without this line it would have lost all hover feedback: the
   rule above out-ranks the new sitewide charcoal hover by source order,
   and the sitewide rule no longer thickens the underline. */
/* Round 21 (item 4, K 7 Oct 2026): now behaves like every other body
   link -- terracotta to charcoal on hover and focus, no underline
   thickening. Still needs its own rule: .top-banner a (above) would
   otherwise out-rank the sitewide a:hover colour. Focus outline unchanged
   (sitewide a:focus-visible). */
.top-banner a:hover, .top-banner a:focus-visible { color: var(--charcoal); }
/* Round 21 (item 7): bigger tap area, no visual change. Vertical padding on
   an inline link grows its clickable box (18px -> 24px tall) without
   changing the line height, the wrapping or where the text sits. */
.top-banner a { padding: 3px 0; }
/* Round 22 (item 4a): keep "Contact us" on one line -- at about 445-479px it
   used to split into "Contact" / "us". The whole link now moves to the next
   line instead. Hover/focus colours and the 24px tap area are unchanged. */
.top-banner a { white-space: nowrap; }

/* ---- Bottom buttons (the Contact Us / Facebook link row) ------------------ */
.bottom-buttons {
  text-align: center;
  padding: 2.5rem 1.25rem 1rem;
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  justify-content: center;
  /* Round 13 (item 2): flex defaults align-items to stretch, so with the
     Contact Us pill (53px tall, via padding) and the plain Facebook link
     (34px tall) sharing this row, both were stretched/pinned to the same
     top edge, leaving the button's own text sitting visibly lower than
     Facebook's. Center on the cross-axis instead so both sit on a shared
     visual center regardless of their own height. */
  align-items: center;
}
.bottom-buttons p { margin: 0; max-width: none; }

/* ---- Featured-article / "Blog highlight" module ---------------------------
   Round 7: reverted to a real <h2> (see build.py's render_featured_article)
   that matches every other section heading in size/font/color -- round 5's
   separate muted-label treatment is gone. The heading is centered by the
   existing :first-child rule (it's the first child of its own .page-inner);
   .featured-link is centered by the sitewide `.page-inner > p` rule. Only
   the link's own size is bumped slightly for a bit of presence.
   -------------------------------------------------------------------- */
.featured-link {
  font-size: 1.15rem;
}
/* Round 6: removed font-weight:600 -- link now uses the sitewide default
   link styling (color + underline only), no bold. */

/* ---- FAQ accordion ---------------------------------------------------
   Native <details>/<summary> -- content stays in the DOM (readable by
   search engines) even while visually collapsed, no JS required.
   Round 5: the +/- indicator now sits right after the question text with
   fixed, modest spacing, rather than pinned to the far right edge of the
   row -- summary is a flex row instead of relying on absolute
   positioning.
   -------------------------------------------------------------------- */
/* Round 15 revision #2 (items 1+2): .faq-item spanned the full .page
   content width (no max-width of its own), while its own answer <p>
   (and every other page's body text, since item A) is capped to
   content-max and centered -- so the accordion rows read wider than a
   normal paragraph, and any sibling <p> that follows the list (the
   closing "if you have more questions" note) sits centered in its own
   narrower, indented box, jogging right of the accordion above it by
   the same 61px/194px (1100px/1440px) gap item A fixed for h1-vs-body
   text. Root-caused the same way as item A: cap .faq-item itself to
   content-max and center it, so the whole accordion (questions,
   answers, and the note after it) share one consistent reading-column
   width and left edge -- confirmed by rendering, 0px jog remains. */
.faq-item {
  max-width: var(--content-max);
  margin-left: auto;
  margin-right: auto;
  border-bottom: 1px solid #E4E0D4;
  padding: 0.4rem 0;
}
/* Item 2: the closing note directly after the FAQ list had no top
   margin of its own, so it sat flush against the last item's bottom
   border with 0px gap -- confirmed by rendering. Same 32px pattern as
   the h1-to-content rule above. */
.faq-item + p {
  margin-top: 2rem; /* 32px */
}
.faq-item summary {
  display: flex;
  align-items: baseline;
  font-family: var(--font-heading);
  color: var(--heading);
  font-weight: 700;
  font-size: 1.15rem;
  cursor: pointer;
  padding: 0.7em 0;
  list-style: none;
}
@media (min-width: 48em) {
  .faq-item summary { font-size: 1.3rem; }
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "+";
  margin-left: 0.6em;
  font-size: 1.2em;
  font-weight: 400;
  color: var(--terracotta-text);
  flex: none;
}
.faq-item[open] summary::after {
  content: "\2212"; /* − */
}
/* Round 23 (item 3, K 9 Oct 2026): below 900px every "+" / "−" sits at
   the right edge, so one-line and wrapped questions line up. At 900px and
   wider nothing changes: the sign stays right after the question. */
@media (max-width: 56.24em) {
  .faq-item summary { justify-content: space-between; }
}
.faq-item summary:focus-visible {
  outline: 2px solid var(--terracotta-text);
  outline-offset: 2px;
}
.faq-item .faq-answer {
  padding: 0 0 1.2em;
}
/* Round 15 revision (item A follow-up): the sitewide p centering fix
   above centers this paragraph within .faq-item's own box -- but
   .faq-item spans the FULL page width (it's not content-max-capped, see
   .faq-item's own rule further up), so the centered answer text ends up
   indented to the right of its own question, no longer starting flush
   under the summary. Answers should stay flush-left with their
   question, not centered within the wider accordion row -- confirmed
   by rendering with items expanded, which is what surfaced this.
   Corrected selector: the actual markup has no .faq-answer wrapper --
   the answer <p> elements are direct children of .faq-item itself,
   right after <summary> -- .faq-item .faq-answer p never matched
   anything real, so the first attempt at this override was silently a
   no-op (confirmed by re-rendering: the indent was still there). */
.faq-item > p {
  margin-left: 0;
  margin-right: 0;
}
.faq-item > p:last-child { margin-bottom: 0; }
/* Round 22 (item 2, K 8 Oct 2026): an OPEN item gets more bottom space, so
   the answer's last line sits about the same distance above the divider as
   the answer's paragraphs sit from each other (was 7px). Replaces the item's
   0.4rem bottom padding while open; closed items are unchanged. */
.faq-item[open] { padding-bottom: 1.4rem; }

/* ---- Footer -------------------------------------------------------------
   Muted sage-grey (not near-black), clearly distinct from the cream body
   without being visually heavy. Round 5: whole block left-aligned (was
   centered) -- copyright, address, crisis heading, bullets, and the
   Privacy Policy link all read as one left-aligned column now. The
   crisis-support list is also narrower (see .footer-crisis-list) so its
   bullet lines wrap more evenly and don't leave a short orphaned second
   line.
   -------------------------------------------------------------------- */
footer {
  background: var(--footer-bg);
  color: var(--charcoal);
  /* Round 8 (item 1): the Round 7 calc() padding only matched the shared
     content column's position at the one viewport width it was checked
     against -- it wasn't actually the same container, so it drifted at
     other widths. Footer content now lives inside a real .page-inner div
     (see partials/footer.html), which is the exact same class/rule every
     other section uses for its max-width + centering + gutter, so it
     tracks correctly at every breakpoint, not just one. footer itself
     keeps the full-bleed sage background and only vertical padding here;
     .page-inner supplies the horizontal padding. */
  padding: 2.5rem 0;
  /* Round 18 (item 1): was 3rem -- 48px of cream body background between
     the last band and the footer, present since Round 8 and invisible
     the whole time because the last homepage section was always cream.
     Round 16 put a tinted band last, which turned that gap into a
     visible cream stripe between the tinted band and the sage footer,
     reading as the band floating rather than sitting flush above the
     footer. Closed to 0 -- paired with squaring the last band's bottom
     corners below (main .band:last-child), since a curved bottom edge
     with no gap lets a wedge of cream show through at the outer edges,
     putting a third colour into what should be a clean two-colour seam.
     K considered and rejected keeping the curve via a footer-overlap
     (negative margin sized to the deepest possible curve, a stacking
     context, compensating padding, and page-scoping so it doesn't ride
     up over content on pages that don't end in a band) -- squaring is
     one declaration with nothing else that has to stay in step with it. */
  margin-top: 0;
  text-align: left;
  font-size: 0.95rem;
}
/* Round 21 (item 3): the Round 18 "main .band:last-child" rule (squared
   the last band's bottom corners) was removed -- every band edge is now
   straight, so it no longer had anything to do. */
/* The whole footer content block hugs the left edge (padding from
   footer itself) rather than sitting as a centered column -- max-width
   keeps line lengths reasonable, but there's no margin:auto centering it
   any more. */
/* Round 15 revision #2 (item 5): was max-width: 44rem with no centering
   -- a hardcoded value close to but not equal to --content-max (46rem),
   and deliberately flush-left against .page-inner's own left edge
   (Round 5's left-alignment decision, made before item A existed).
   Item A then centered every other page's body-text column within
   .page, so the footer's still-flush-left block drifted out of
   alignment with it by the same 61px/194px (1100px/1440px) gap --
   confirmed by rendering. Root-caused the same way as item A and the
   FAQ fix above: share the exact --content-max value (not a separate
   44rem) and center the box with margin:auto, so its left edge lands
   on the same point as the body-text column above it in the page.
   text-align stays left (inherited from `footer` itself, untouched)
   -- only the block's own position moves, the text inside it does not
   become centered. */
/* Round 18 (item 4): max-width changed from var(--content-max) to none.
   Deliberate, not a reversal of Round 17 item 1's centering fix -- this
   is a different axis. The nav sits just outside the page container's
   own edge (Round 17 item 4), the reading column sits inside it
   (Round 18 item 2/3), and the footer now sits ON the container edge
   itself -- top and bottom frame the page, content sits within the
   frame. The auto side margins from Round 17 are kept here on purpose:
   they simply have no visible effect once the box fills the container
   edge to edge, and removing them would just be churn. */
footer p, footer .footer-crisis-list {
  max-width: none;
  margin-left: auto;
  margin-right: auto;
}
footer p { margin: 0 auto; } /* Round 15 revision #2 (item 5): was `margin: 0` (all sides), which came after the new max-width+margin:auto centering rule above and, at equal specificity (footer p vs footer p), won by source order -- silently zeroing the auto centering right back out. Same pitfall item A hit with the sitewide `p { margin: 0 0 1.2em }` rule; same fix: keep the shorthand but keep auto on the sides that need to stay auto. */
footer .footer-copyright { margin-bottom: 0.15em; }
footer .footer-address { margin-bottom: 1.1em; }
footer .footer-crisis-label { margin-bottom: 0.4em; font-weight: 600; }
/* Round 18 (item 5): above 81.25em (1300px) -- measured: the copyright
   and address lines together need about 1010px, which fits on one line
   at 1300px viewport width and wraps mid-address just below it -- the
   two lines run together with a plain space between them, gated to this
   breakpoint only, everything below stays stacked exactly as before.
   No separator glyph: the full stop after "All rights reserved." already
   marks the boundary between the two, and a bullet/dash would be new
   copy that wasn't asked for. Going inline collapses footer-address's
   own margin-bottom (the vertical gap before "For mental health crisis
   support:"), so that gap is restored explicitly on footer-crisis-label
   instead, in the same query. */
@media (min-width: 81.25em) {
  .footer-copyright, .footer-address { display: inline; }
  .footer-copyright::after { content: " "; }
  .footer-crisis-label { margin-top: 1.1em; }
}
/* Round 9 (item 1): removed the max-width: 24rem that lived here since
   Round 6 (back when the crisis list had no other width constraint and
   needed one of its own to control its wrap). That rule was never taken
   out when the Round 8 container fix landed -- so it sat on top of
   everything else, silently re-narrowing just this one element by ~165px
   versus the address line above it. Now shares the same --content-max
   width as footer p (see the shared rule above) instead of carrying its
   own separate value; text-wrap: pretty is kept for even wrapping at
   that width. (Comment corrected Round 17: this stopped being a
   hardcoded "44rem" two revisions before this note was written -- Round
   15 revision #2 item 5 moved both footer p and this selector onto the
   shared --content-max variable instead.)
   Round 17 (item 1): margin was `0 0 1.1em` -- zero left/right, not
   auto -- which sat after the shared max-width+margin:auto centering
   rule above and, at equal specificity (footer .footer-crisis-list vs
   footer .footer-crisis-list), won by source order and silently zeroed
   the centering back out. Exactly the same pitfall as footer p hit in
   Round 15 revision #2 item 5, on the identical line pattern twelve
   lines above this one -- same fix: keep the shorthand, keep auto on
   the sides that need to stay auto. Confirmed by rendering: copyright/
   address/crisis-label/Privacy-Policy-link and the crisis list itself
   now share one left edge (352px at 1440px, 182px at 1100px), where the
   list previously sat at 158.4px/121px -- flush against .page-inner's
   own edge instead of centered with everything else in the footer. */
footer .footer-crisis-list {
  list-style: none;
  margin: 0 auto 1.1em;
  padding: 0;
  text-align: left;
  font-size: 0.95rem; /* Round 21 (item 5): was 0.8rem (12.8px); now the footer's own size, 15.2px */
  line-height: 1.6;
  text-wrap: pretty;
}
/* Round 18 (item 4): max-width: none added -- these <li> elements were
   otherwise still caught by the sitewide `p, li, blockquote { max-width:
   var(--content-max) }` rule (a real match despite footer .footer-crisis-list
   itself now being max-width: none above -- that rule targets the list
   box, not its individual items), which would have kept each bullet
   line capped to the old reading measure even after the list itself
   went full-width. */
footer .footer-crisis-list li {
  max-width: none;
  margin-bottom: 0.6em;
  margin-left: 0;
  margin-right: 0;
  padding-left: 1.1em;
  position: relative;
}
footer .footer-crisis-list li::before {
  content: "\2022";
  position: absolute;
  left: 0;
}
footer .footer-privacy { margin-top: 0.4em; margin-bottom: 0; font-size: 0.85rem; }
/* Round 21 (item 7): bigger tap area for "Privacy Policy", no visual change
   -- same inline-padding approach as the top banner link (15px -> 25px). */
footer .footer-privacy a { padding: 5px 0; }
footer a { color: var(--charcoal); text-decoration: underline; }
/* Round 19 (item 4, K 7 Oct 2026): footer links no longer turn terracotta
   on hover -- --terracotta-text on the sage footer is only 2.25:1. They
   keep --charcoal (5.04:1 on the footer) and the hover cue is the thicker
   underline, same thickness as every other link. */
footer a:hover, footer a:focus-visible { color: var(--charcoal); text-decoration-thickness: 0.12em; }

/* ---- Images in article body ---------------------------------------------
   Constrained to the same reading measure as the text so a photo doesn't
   suddenly balloon wider than the paragraph above it. Doesn't apply to
   .float-left/.float-right, which set their own width.
   -------------------------------------------------------------------- */
/* Round 17 (item 6): the Contact page's Google Form iframe had no
   width cap of its own -- it spans .page's full content width (1123px
   at 1440px, measured) while the paragraph above it is capped to
   --content-max (736px), landing the iframe and the page's own body
   text on two different edges. Capped to the shared --content-max
   variable (not a fixed pixel value) so it automatically follows
   whatever Round 18 does to that variable, and centered the same way as
   every other capped element on the page. The HTML's own width="100%"
   attribute is overridden by this CSS width, same as any inline
   presentational attribute.
   Flagging honestly, per the standing rule to verify by rendering, not
   assumption: this fix could NOT be visually verified. Neither this
   sandbox nor the Mac's own rendering has live internet access, so the
   Google Form iframe renders blank in both -- there's no way from here
   to see how the form's own internal layout responds to a narrower
   frame. Built as specified; needs an actual look on the deployed
   staging site before anyone calls it fine. */
.page iframe {
  display: block;
  max-width: var(--content-max);
  width: 100%;
  margin-left: auto;
  margin-right: auto;
}
/* Round 19 (item 3): Contact form panel + measured heights.
   - margin-bottom 32px (was 0, so the Privacy Policy link sat against the
     frame), matching the 32px above it.
   - Visible panel: white, soft edge, the site's existing 0.75rem radius,
     so the much shorter post-submit "thank you" state reads as a panel
     rather than a broken page. The edge is a 1px box-shadow ring rather
     than a border on purpose: a border would take 2px off the form's
     width, and the form's own height steps change with width.
   - Round 20 (item 6): allowance raised from ~30px to ~100px over the
     measured heights below. Those were measured signed out of Google; K
     found on her phone (~393px, signed in) that the form adds four account
     lines (email, Switch account, Not shared, draft-saved icon), ~50px,
     which pushed it to/past the Round 19 frame height.
   - Heights: the new form's full content height was measured in a real
     browser at a range of frame widths (Round 19 report has the table),
     then each range below gets the tallest measurement in its range plus
     ~100px allowance (Round 20; was ~30px), so the frame never shows its own scrollbar. The
     frame is min(900px, 78% of the viewport) wide at every size, so each
     viewport range maps to a known frame-width range. Mobile-first. */
.page iframe.contact-form-frame {
  margin-top: 2rem;
  margin-bottom: 2rem;
  background: var(--white);
  border: 0;
  border-radius: 0.75rem;
  box-shadow: 0 0 0 1px rgba(44, 44, 42, 0.14);
  height: 1380px;   /* < 320px viewport (frame < 250px): measured up to 1276px at 218px */
}
@media (min-width: 20em) {      /* 320-359px viewport, frame 250-280px: measured max 1123px */
  .page iframe.contact-form-frame { height: 1225px; }
}
@media (min-width: 22.5em) {    /* 360-479px, frame 281-373px: measured max 1051px */
  .page iframe.contact-form-frame { height: 1155px; }
}
@media (min-width: 30em) {      /* 480-767px, frame 374-598px: measured max 992px */
  .page iframe.contact-form-frame { height: 1095px; }
}
@media (min-width: 48em) {      /* 768-899px, frame 599-701px: measured max 972px */
  .page iframe.contact-form-frame { height: 1075px; }
}
@media (min-width: 56.25em) {   /* 900px+, frame 702-900px: measured 919px */
  .page iframe.contact-form-frame { height: 1020px; }
}

.page img {
  /* Round 14: fixed a pre-existing sitewide mobile bug found while
     rendering this round's item 7 at mobile width (standing
     instruction: verify by rendering) -- max-width: 736px alone doesn't
     clamp to the viewport/container on a narrow screen (736px > most
     phone widths), and the base `img { max-width: 100% }` reset loses
     the cascade tie here because `.page img` (one class + a tag) is
     more specific than a bare `img` (just a tag). Confirmed this was
     already causing horizontal scroll on mobile for any sufficiently
     large existing article image, not just the one touched this round
     -- e.g. protector-parts-in-trauma.jpg (700x700, untouched by this
     round) was already overflowing to a 743px page width on a 390px
     viewport before this fix. min(...) keeps the same 736px reading-
     width cap on desktop (where the container is always wider than
     736px, so min() still resolves to 736px, unchanged) while also
     respecting 100% of the container on narrow screens, where 100% is
     now the binding constraint. */
  max-width: min(var(--content-max), 100%);
  /* Round 17 (item 5): 1.6em (29px) read as tight against the
     surrounding text -- increased to 2.6em (47px). max-width rule above
     is untouched on purpose; that's Round 18 territory (widths). */
  margin: 2.6em auto;
  border-radius: 0.5rem;
}
/* Round 14 (item 7): the replacement behind-every-feeling image is a
   square 1080x1080 source (the quote/artist-credit text is baked into
   the image itself, in the bottom ~24%, so it's used uncropped -- 1:1,
   no object-fit crop needed or applied). Without this override it would
   render at the generic .page img cap (see above), wider than the
   400-700px range the other article images use and wider than actually
   needed for a 1080px source at roughly 2x display density. Capped to
   600px display width here (1080px source = 1.8x, effectively the
   "roughly twice" retina density asked for) -- sits centrally within
   the 400-700px range the other article photos use. Qualified with the
   .page ancestor (two classes) rather than left as a single class, so
   it reliably wins the specificity tie against .page img (one class +
   a tag) regardless of file order -- the same lesson from Round 13's
   photo-alignment bug, applied up front this time instead of found the
   hard way again. On mobile, min(600px, 100%) in practice just means
   100% (matching every other article image's mobile behaviour) since
   600px alone would still be wider than a phone screen. */
.page .article-photo-square {
  max-width: min(37.5rem, 100%);
}

/* ---- Curated link lists (Resources, Therapies) --------------------------
   Round 13 (item 6): built for Resources -- was a plain <ul> -- bullet
   markers plus the sitewide always-on link underline (a deliberate rule
   elsewhere, for links inside body prose) made it read like a reference/
   citation list rather than the deliberately-chosen collection of
   articles it actually is. Bullets and per-item underlines removed;
   more vertical room per entry via padding (not the sitewide li
   margin-bottom, which doesn't give a click target); a divider line
   between entries in place of the bullet as the visual separator;
   underline + a soft background tint + a small indent shift on
   hover/focus, so the interaction is still clearly signalled -- not
   relying on color alone -- without it being visible at rest.
   Round 14 (item 4): renamed from .resource-list to the generic
   .link-list and applied to Therapies too -- the two signposting pages
   (Resources, Therapies) now share one visual treatment instead of
   Therapies still showing raw bulleted/underlined links. Order, count
   and copy untouched on both pages -- restyled only. */
.link-list {
  list-style: none;
  margin: 1.5em 0;
  padding: 0;
}
.link-list li {
  margin-bottom: 0;
  border-bottom: 1px solid #DDD8CC;
}
/* Round 15 (item 9): removed the :last-child exception -- Resources
   (14 entries) already reads as "a divider under every entry" since
   the missing one at the very bottom blends into the page end, but
   Therapies only has 2 entries, so the same missing divider under its
   2nd (last) link was obviously asymmetric: a divider after the 1st
   link, none after the 2nd. Every entry on both lists now gets its
   divider, including the last one on each page. */
.link-list a {
  display: block;
  padding: 0.95em 0.25em;
  text-decoration: none;
  transition: background-color 0.15s ease;
}
/* Round 20 (item 3): the hover/focus padding-left shift (0.25em -> 0.6em)
   is gone -- at 390px it narrowed the line enough to re-wrap "Behind every
   feeling is likely a need" from one line to two on tap. Tint background
   and underline kept; padding-left dropped from the transition too. */
.link-list a:hover,
.link-list a:focus-visible {
  text-decoration: underline;
  background: var(--band-tint);
}

/* ---- Skip link (Round 21, item 6) -----------------------------------------
   "Skip to main content": the first thing a keyboard user tabs to on every
   page (inserted by build.py, see partials/skip-link.html). Kept off-screen
   (not display:none, so it stays focusable) until it has focus; then it
   appears top-left with a cream background, charcoal bold text and the
   site's usual 2px terracotta focus outline. Enter jumps to <main id="main">.
   -------------------------------------------------------------------- */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0.75rem;
  z-index: 1000;
  padding: 0.5em 1em;
  background: var(--cream);
  color: var(--charcoal);
  font-weight: 700;
  border-radius: 0.375rem;
}
.skip-link:focus {
  left: 0.75rem;
  color: var(--charcoal);
  outline: 2px solid var(--terracotta-text);
  outline-offset: 2px;
}
/* <main> takes focus when the skip link is used (tabindex="-1", so it is
   never a Tab stop itself). It is a container, not a control, so it gets
   no focus outline of its own. */
main:focus { outline: none; }

/* Round 22 (item 4b): long links in the page content (e.g. the DOI address
   on the study article) may wrap instead of pushing the page sideways on
   small phones. break-word, not anywhere, so it doesn't change how grid
   columns size. Only affects links that wouldn't otherwise fit.
   Round 23 (item 1): the DOI is now plain text, not a link, so it sits in
   <span class="doi"> and gets the same rule. Scoped to the DOI only, not
   to all paragraphs: "main p" was tried and made the closing full stop
   after the email address drop onto its own line at 320px (Contact and
   Privacy Policy), where the address overhangs its column by 0.4px. */
main a, main .doi { overflow-wrap: break-word; }
