/* rhythm.css — typographic rhythm and vertical spacing, all viewports.

   OWNERSHIP: mine (see the split agreed with Lovable — responsive.css is
   theirs, this and touch.css are mine). Kept out of design.css because that
   file is GENERATED from design-source/ and is overwritten by convert:design.

   ── 1. A character cap must not add a break the markup did not ask for ──
   74 headings across the site set their own line breaks with block-level
   spans — "Children don't complete" / "activities here." / "They think. Make.
   Test." Those same headings also carry a `max-width` in `ch` (29 use 18ch,
   26 use 16ch, 16 use 14ch). The cap was tuned at some viewport and is now
   narrower than the phrases inside it, so every span wraps AGAIN: a heading
   meant to read as four lines renders as six or seven short ones, stacked and
   loose, with the words stretched across a narrow column.

   Where the markup already dictates the breaks, the phrase IS the line, so
   the cap is removed rather than widened. Nothing runs away: each span is a
   fixed phrase and its natural width is its length.

   ── 2. Headings that do wrap keep a sane measure ──
   A cap below 20ch is too tight for display type at these sizes; it is only
   ever reached by an accident of tuning. Raised to a floor, not removed —
   these headings genuinely wrap and need a measure.

   ── 3. One vertical rhythm instead of eleven ──
   Section padding runs 10vh, 11vh, 12vh, 13vh, 14vh, 15vh, 16vh, 20vh, 22vh
   across 205 sections. On a tall desktop 16vh is ~170px of nothing above and
   below every band, which is what reads as "the spacing is really intense".
   vh alone also cannot adapt: it is the same fraction on a 1440-tall monitor
   and a 640-tall laptop, so it is simultaneously too much and too little.

   `clamp()` fixes the middle: a floor so short screens stay legible, a vh
   term so tall screens still breathe, a ceiling so nothing balloons. Heroes
   and the pinned CAPE rail are excluded — they are sized against the viewport
   on purpose and responsive.css already owns the heroes.
*/

/* --- 1. Markup-controlled headings lose the character cap --------------- */
main.page :is(h1, h2, h3, h4):has(> span[style*="display:block"]) {
  max-width: none !important;
}

/* --- 2. Everything else keeps a measure, with a floor ------------------- */
main.page :is(h1, h2, h3, h4)[style*="max-width:14ch"]:not(:has(> span[style*="display:block"])),
main.page :is(h1, h2, h3, h4)[style*="max-width:16ch"]:not(:has(> span[style*="display:block"])),
main.page :is(h1, h2, h3, h4)[style*="max-width:18ch"]:not(:has(> span[style*="display:block"])) {
  max-width: 22ch !important;
}

/* Display type at these sizes wants tighter leading than the pack's 1.04-1.2
   on the larger steps; the looseness is what makes a stacked heading sprawl. */
main.page :is(h1, h2) { line-height: 1.02; }
main.page h3 { line-height: 1.12; }

/* --- 3. One vertical rhythm -------------------------------------------- */
/* 2026-09-03, second thought. The rule that stood here clamped every
   desktop section to 52-116px, and on a 1080-tall screen that put the
   "Overheard in class" quote 40px from the wave above it and the CAPE closer
   hard against its next section. The pack's own 9-22vh reads as generous
   because it IS generous, and on a desktop that is the design. So desktop
   keeps the pack's padding untouched now; the tightening below applies only
   where it was actually needed -- a phone held sideways, and phones. */

/* A short landscape window — a phone on its side, or a laptop with the
   browser chrome taking half the height — cannot afford the same band. */
@media (orientation: landscape) and (max-height: 560px) {
  main.page > section:not([id$="-hero"]):not(#methodPin):not(#home-hero) {
    padding-block: clamp(32px, 7vh, 64px) !important;
  }
}

/* ── SECTION AIR: measured from the seam, not from the box ────────────────
   Rewritten 2026-09-15 after measuring all 215 sections across all 32 pages.

   This rule used to read `padding-block: clamp(40px, 6vh, 72px)` — one number
   for every section on the site. That is the bug. Sections are not butted
   edge to edge here: each one is pulled UP over the one before it and cut with
   a curve, so the first thing a visitor sees at the top of a section is not
   its box edge, it is the bottom of a curve some distance below that edge.

   A fixed padding measured from the box therefore produces a DIFFERENT amount
   of visible air on every section, depending entirely on how deep its own seam
   is. Measured at 390px: 51px of padding on all 174 seamed sections, against
   seams 40px to 96px deep — so between 11px of air and MINUS 45px, which is
   text sitting inside the wave. That is the "too close to the wave" this was
   reported as, and it was never one page's problem: it was every page's.

   So the padding is now the seam depth PLUS one constant. The constant is the
   air; the seam term cancels the curve out. Every section on every page ends
   up with the same visible breathing space regardless of which kind of seam it
   carries, which is the consistency that was missing.

     --wps-air     the visible gap, the only number that is a taste decision
     --wps-lift    section-stack.css's curve+overlap, clamp(40px,5vw,72px)
     the homepage  curve of 40px but an overlap of 72–96px, so its top and
                   bottom terms differ and are stated separately below

   Desktop is untouched: the whole block is inside the phone/tablet arm, and
   above it the pack's own generous padding is the design. */
@media (max-width: 900px), (max-width: 1400px) and (pointer: coarse) {
  main.page { --wps-air: 44px; }

  /* Every stacked section on the 31 non-home pages. `--wps-lift` is both the
     curve at its top and the overlap taken out of its bottom, so one term
     serves both sides. The fallback matters: the homepage does not define the
     variable. */
  main.page > section:not([id$="-hero"]):not(#methodPin):not(#home-hero) {
    padding-top: calc(var(--wps-lift, 40px) + var(--wps-air)) !important;
    padding-bottom: calc(var(--wps-lift, 40px) + var(--wps-air)) !important;
  }

  /* THE HOMEPAGE IS THE EXCEPTION, because its two terms are different sizes.
     section-stack.css eases its CURVE down to clamp(40px,5vw,72px) on a phone,
     but the pack's inline `margin-top:-72px` / `-96px` is untouched, so the
     amount of each section that is COVERED stays 72–96px. Clearing the deeper
     of the two is what stops the last line of one section being hidden under
     the next. */
  #page-home > section:not(#home-hero):not(#methodPin) {
    padding-bottom: calc(96px + var(--wps-air)) !important;
  }
  /* The hand-drawn waves are a 96px SVG over a clip-path cut from a taller
     polygon, so their top term is the wave, not the radius. */
  /* The selector is padded out to (2,2,2) — the same score as the generic rule
     above — so that, being written after it in the same file, it wins the tie.
     Written as `#page-home > section[…]` it scored (1,1,1), lost, and the
     waves silently kept the 40px-curve padding. Measured, not assumed. */
  main.page#page-home > section[style*="clip-path:polygon"]:not(#home-hero) {
    padding-top: calc(96px + var(--wps-air)) !important;
  }

  main.page :is(h1, h2, h3, h4) { max-width: none !important; }
}

/* Where a browser has no :has(), the cap stays as authored rather than the
   rule silently applying to everything. Nothing below depends on it. */
@supports not selector(:has(> span)) {
  main.page :is(h1, h2, h3, h4) { max-width: revert-layer; }
}

/* ── The fold has to promise something ────────────────────────────────────
   The homepage hero used to end in a wide empty cream field, with the next
   section's rounded green edge sitting below every common laptop fold. A
   visitor saw a finished-looking screen and no reason to scroll.

   The strongest scroll cue is not an arrow, it is a PEEK: showing that the
   next thing exists beats telling someone it does. So the dark band's curve
   should break the fold by a couple of dozen pixels.

   min-height alone cannot deliver that on a short screen, because the hero's
   CONTENT is what sets its height there — at 1280x800 the photo column and
   the text stack together run past the viewport whatever the section asks
   for. So on short desktops the frame and the padding give up a little
   instead. Phones and tablets already clear it comfortably. */
@media (min-width: 900px) and (max-height: 900px) {
  #home-hero {
    min-height: auto !important;
    padding-top: 92px !important;
    padding-bottom: 20px !important;
  }
  #heroPhotoCol > div[style*="height:min(56vw"] { height: min(56vw, 640px, 40vh) !important; }
  #heroPhotoCol > p:first-of-type { margin-bottom: 10px !important; }
}

/* The headline is what fills a short screen, so its size has to know about
   viewport HEIGHT, not only width. The pack sizes it on width alone
   (min(9.6vw,178px)), which is why a 1366x768 laptop got a headline scaled
   for a 1366-wide desktop and no room left for anything after it.

   Adding a vh term makes that continuous. A hard breakpoint was tried first
   and rejected: it stepped the headline from 147px to 72px across a single
   pixel of viewport height, which is visible and awful if anyone resizes.
   `min()` of all three just picks whichever constraint actually binds. */
@media (min-width: 900px) {
  #heroH1 { font-size: min(9.6vw, 178px, 15vh) !important; }
}
@media (min-width: 900px) and (max-height: 820px) {
  #home-hero h1 + p { font-size: 17px !important; margin-top: 20px !important; max-width: 42ch !important; }
  #home-hero > div[style*="position:relative;z-index:2"] > div:last-child { margin-top: 26px !important; }
}

/* ── 5. Grids that were collapsed to one column when they need not be ──────
   responsive.css collapses EVERY inline grid to a single column under 900px.
   Right for a two-column article layout; wrong for a row of five age buttons
   ("My child is..." on /programs), which becomes five full-width bars and
   1.2 screens of tapping on a phone. Those grids are self-sizing --
   repeat(auto-fit, minmax(140px, 1fr)) -- so they are given back two columns
   on a phone and their own auto-fit on anything wider. Nothing changes
   above 900px. */
@media (max-width: 900px) {
  main.page div[style*="repeat(auto-fit,minmax(140px,1fr))"] {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
}
@media (min-width: 640px) and (max-width: 900px) {
  main.page div[style*="repeat(auto-fit,minmax(140px,1fr))"] {
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)) !important;
  }
}

/* ── 6. A phone held sideways ──────────────────────────────────────────────
   844x390 is not a small desktop, it is a letterbox. Three things break in it
   and nothing else on the site was written for a 390px-tall window:

   - Section heroes reserve 80vh and centre their content, so the first
     screen is a headline and nothing else, and the second is the rest.
   - The overlapping stack on the homepage (the-question -> method-intro ->
     CAPE) uses 72px negative margins so each section tucks under the next.
     At this height the tuck covers the previous section's last line.
   - The pinned CAPE rail sticks a 340vh section to a window it cannot fit
     in; the letters, the rail and the heading land on top of each other.

   Landscape-and-short only; a tablet in landscape is 700px+ tall and keeps
   the designed behaviour. */
@media (orientation: landscape) and (max-height: 500px) {
  main.page > section[id$="-hero"] {
    min-height: 0 !important;
    padding-top: 84px !important;
    padding-bottom: 32px !important;
  }
  #home-method-intro, #home-proof-strip {
    margin-top: -28px !important;
    margin-bottom: -28px !important;
    border-radius: 36px !important;
  }
  #home-the-question { padding-bottom: 72px !important; }
  /* Unpin the CAPE method: the same shape as the pack's own fallback for
     browsers without scroll-driven animation, which already reads correctly
     as four stacked panels. */
  #home-cape-method { height: auto !important; padding-top: 96px !important; clip-path: none !important; }
  #methodPin { position: relative !important; top: 0 !important; height: auto !important; overflow: visible !important; contain: none !important; }
  /* The C -> A -> P -> E rail sits above the panels instead of floating over them. */
  #methodPin > div:first-child { position: relative !important; top: auto !important; margin: 0 0 12px !important; }
  #methodTrack { animation: none !important; transform: none !important; display: block !important; width: auto !important; height: auto !important; }
  #methodTrack article { width: auto !important; height: auto !important; min-height: 0 !important; padding: 40px 6vw 32px !important; }
  #methodTrack .cape-inner { height: auto !important; }
  /* The screen-high watermark letters are sized against a viewport this
     window does not have; stacked panels carry their own step labels. */
  #methodTrack .cape-mark { display: none !important; }
}

/* ── G9 · A line of text has a maximum, not just a minimum ────────────────
   MOBILE_TABLET_AUDIT.md § G9. Phase 3, 2026-09-15.

   This file sets a floor for type size at every width but never a ceiling for
   line LENGTH between the phone breakpoints and the desktop layout. A
   single-column text section at 1180px — a landscape iPad — simply stretches,
   and measured there 73 paragraphs across 14 pages ran past 80 characters a
   line: 20 on /families/faq, 12 on /families/funding, 7 each on /admissions
   and /careers.

   Past about 75 characters the eye starts losing its place on the return
   sweep, which is why 45–75 is the long-standing typographic range and 68ch
   the usual single number for it.

   `max-inline-size`, not `max-width`, and no `margin` here: a centred hero
   paragraph already carries `margin-inline:auto` inline and keeps it, so it
   narrows around its own centre; left-set body text just stops growing. A
   paragraph inside a grid card is already narrower than 68ch, so this is a
   no-op there.

   The band runs 641px to 1280px. Below 641 the phone rules above have already
   put every section into one narrow column, so there is nothing to cap; above
   1280 the pack's own layouts take over and the measure is the designer's
   decision. It reaches down to 641 rather than 901 because a portrait iPad is
   768px and a full-width paragraph there is ~87 characters — the same fault as
   at 1180, just narrower. */
@media (min-width: 641px) and (max-width: 1280px) {
  /* Any paragraph, at any depth. The first version of this rule named
     `section > p` and `section > div > p` and caught 10 of the 73 — the other
     63 sit three, four and five levels down, inside cards, <details> and
     articles. Depth is not a property of a line of text.

     Checked before widening it: all 63 compute `text-align: start` with no
     auto margin, so capping them cannot decentre anything. The exclusion below
     is insurance for a paragraph added later that IS centred without an auto
     margin — capping one of those would leave a narrow left-hugging block of
     centred text. Paragraphs already carrying `margin:0 auto` inline keep it
     and narrow around their own centre, which is correct. */
  main.page p:not([style*="text-align:center"]) {
    max-inline-size: 68ch;
  }
}

/* ── G11 · Wrap and orphan rules for display type ─────────────────────────
   MOBILE_TABLET_AUDIT.md § G11. Phase 5, 2026-09-15.

   `text-wrap: balance` evens out a heading's lines instead of filling each
   one and dropping whatever is left onto the last — which is what produces a
   six-word line above a one-word line. `pretty` does the narrower job for
   body copy: it prevents a single-word last line.

   Both are progressive enhancement. Chrome 114+ and Safari 17.5+ apply them;
   every older browser ignores the declaration and keeps exactly today's
   wrapping, so there is no fallback to write and nothing to guard.

   Scoped to ≤1280px on purpose: the desktop line breaks are the pack's own
   and have been looked at. This is for the widths where the text reflows into
   shapes nobody chose. `balance` is capped at around six lines by spec, so it
   cannot become expensive on a long paragraph.

   `overflow-wrap: break-word` is the safety net for the one thing that can
   still overflow a 344px screen — an unbroken string like a long URL or
   "thewinterparkschool.com" in running text. NOT `hyphens`, and no `<br>` or
   `&nbsp;`: hand-placed breaks are what created the min-content overflow bugs
   this audit started with. */
@media (max-width: 1280px) {
  main.page :is(h1, h2) { text-wrap: balance; }
  main.page p { text-wrap: pretty; overflow-wrap: break-word; }
}
