/* ═══════════════════════════════════════════════════════════════════════════
   PRIVATE MENTORSHIP — SERVICE PAGE DESIGN SYSTEM
   Extracted from childcare.html on 2026-09-06 and shared by all four service
   pages, because Caleb's complaint was that they disagree with each other:
   "these service pages … is all different colours and design."

   They could disagree because each page carried its own full copy of the same
   rules, free to drift. Education, Life Skills and Personal Support each held
   27 distinct colour literals; childcare held 55. One shared sheet ends that
   by construction — there is now nowhere for a fifth colour to come from.

   LOAD ORDER MATTERS. This must be linked AFTER each page's inline <style>.
   The pages still carry their own historical rules; this sheet wins on equal
   specificity only by loading later. Move the link above the <style> block and
   the old palettes come back silently.

   Page-specific sections (#edu-rules, .efaq, the .tile grid) are deliberately
   NOT defined here — they stay in their own page and inherit these tokens.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════
     CHILDCARE — design-system rebuild, 2026-09-06

     Caleb: "this page is all different colours and design … needs a thorough
     premium upgrade … make it firm and consistent."

     He was describing something measurable. The page carried FOUR unrelated
     accent families at once — teal #0E7C82, coral #e56a45 / amber #E68A3D,
     pink #D9548A, and indigo #5B5BF0 / blue #007AFF — plus SEVEN greys doing
     the work of three (#123b42 #3c4657 #5a6572 #6b7684 #8a94a3 #0E1721
     #8fabae) and SIX near-identical off-whites (#FAFCFB #F1F8F6 #E7F4F1
     #F0F8F5 #E9F4F0 #FCFEFE). Body copy was #3c4657 in the bands, #5A6572 in
     the cards and #6b7684 in the note — three different "grey" for one job.

     Everything below derives from ONE accent and THREE inks. A colour that is
     derived cannot drift, which is the actual fix for "all different colours":
     the page now cannot disagree with itself, or with the chosen Page Colour.

     Removed at the same time: eleven dead rule blocks that were still setting
     colours nothing rendered — the whole video modal (.vm-*), the old eight-
     tile grid (.homegrid/.tile), the page's own nav (.ps-nav*, superseded by
     the shared injected header), .home__badge, .home__foot, .row__watch,
     .row__photo and the hero eyebrow/note. The amber and coral literals lived
     ONLY in that dead code — which is why the page read as more colourful than
     anything actually on screen.
     ═══════════════════════════════════════════════════════════════════════ */
  :root{
    /* ── The one accent. Follows the Page Colour picked on the landing. ── */
    --acc:        var(--pm-skin-accent, #0E7C82);

    /* ── Ink: three steps, biased toward the brand teal-black so the greys
           read as chosen rather than as a default slate. ── */
    --ink:        #123B42;   /* titles, bolded run-in text */
    --ink-2:      #4B5C62;   /* body copy */
    --ink-3:      #7C8C92;   /* leads, captions, meta */
    --ink-deep:   #0F2F34;   /* footer ground */

    /* ── Surfaces. The tinted two carry a TRACE of the accent, so choosing a
           Page Colour moves the whole page, not just its buttons. ── */
    --surf:       #FFFFFF;
    --paper:      color-mix(in srgb, var(--type)  4%, #FCFDFE);

    /* ── The card-icon blue. Caleb picked it off the category-card icons and
           asked the tinted bands to match it: "i think the blue for all those
           green section ones will look better to match the icons".

           It is deliberately NOT --acc. --acc follows the Page Colour picker,
           so a band derived from it swung green under the teal skin — hence
           `.band--blue` rendering mint. This blue is fixed, so the bands and
           the icons stay the same family whatever skin is chosen. ── */
    /* THE ICON CHIPS — they follow the page's TYPE colour.
       Caleb, 2026-09-06: "the icon on top of each service page and the check
       marks can all go to the theme colour of all the service pages — for
       example i think childcare is gold so the icons and check can match."

       So the chip is no longer the constant across the four pages; the type
       colour now runs all the way through the card, chip included. --ic is
       kept as its own name (rather than deleting it and using --type direct)
       because the card's chrome — top edge and hover glow — reads it through
       --cc-ic, and a page could still pin just the chip if that is ever
       wanted. */
    --ic:         var(--type);

    /* ── TYPE COLOUR ────────────────────────────────────────────────────
       One per service page, Pokemon-style. Caleb, 2026-09-06.

       It drives everything the page tints: bands, waves, hero wash, card
       bullets, the hairline under each lead, the corner wash, the top rule,
       hover glows, disclosure chevrons and the rail dots.

       It deliberately does NOT drive the icon chips — "i want them all to
       follow the life skills one we did, just not the icons". The chips stay
       --ic (blue) on all four pages, so the icon row is the constant that
       ties the set together while the tint tells you which page you are on.

       Because the chips are the only place white sits on the accent, the
       type colour carries no white text and is free to be richer than a
       strict luminance match would allow.

       Each page overrides this in its own <style> after the shared sheets. */
    /* Default only — every service page overrides this in its own <style>.
       Stated as a literal rather than var(--ic) so the page TINT can never be
       silently dragged along by a change to the chip colour. */
    --type:       #1E90DE;

    /* Midnight navy. Caleb, 2026-09-06, as the counterpoint to the blue:
       the blue carries the SURFACES (bands, waves, card icons, hairlines),
       navy carries the things you READ and CLICK (titles, run-in labels,
       tick circles, video links, both Waiting List buttons). Two roles, so
       the page has a hierarchy instead of one flat wash of blue. */
    --navy:       #3C4A78;

    /* Mixed into a NEUTRAL off-white and at 10%, not 6% into a blue-biased
       one. That earlier pairing was the bug that made these bands read mint:
       at 6% the base decides the hue. With four different type colours now
       feeding this, the base has to stay out of the way and the share has to
       be high enough for green / amber / violet to actually show. */
    --band:       color-mix(in srgb, var(--type) 10%, #FBFDFE);

    /* ── Hairlines + shadows, all from ink so they never fight the accent. ── */
    --line:       color-mix(in srgb, var(--ink) 13%, transparent);
    --line-soft:  color-mix(in srgb, var(--ink)  8%, transparent);
    --sh-1: 0 1px 2px color-mix(in srgb, var(--ink)  7%, transparent);
    --sh-2: 0 18px 38px -24px color-mix(in srgb, var(--ink) 42%, transparent);
    --sh-3: 0 34px 72px -44px color-mix(in srgb, var(--ink) 55%, transparent);

    --r-sm:10px; --r:14px; --r-lg:20px; --r-xl:26px;
    --wrap:1160px;

    /* Type roles. The bridge re-asserts these with !important where
       landing-type.css would otherwise flatten every face to one. */
    --font-display: var(--pmt-display, 'Fraunces', Georgia, serif);
    --font-heading: var(--pmt-heading, 'Inter', system-ui, sans-serif);
    --font-body:    var(--pmt-body, 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);

    /* Legacy aliases. .tick and a few inherited rules still say --teal, and
       pm-service-theme.css maps --teal for every service page. Pointing them
       at --acc keeps one source of truth instead of two that must agree. */
    --teal:var(--acc); --grey:var(--ink-2); --label-grey:var(--ink-3);
  }

  *{box-sizing:border-box;}
  html{scroll-behavior:smooth;}
  body{margin:0;background:var(--surf);color:var(--ink);font-family:var(--font-body);
    -webkit-font-smoothing:antialiased;line-height:1.5;}
  img{max-width:100%;display:block;}
  a{color:inherit;}

  /* Keyboard focus was invisible everywhere on this page before today. */
  a:focus-visible, button:focus-visible{
    outline:2px solid var(--acc); outline-offset:3px; border-radius:4px;
  }

  /* ══ HERO ══════════════════════════════════════════════════════════════ */
  .ps-hero{position:relative;text-align:center;overflow:hidden;
    padding:clamp(54px,7.4vw,96px) 24px clamp(30px,3.4vw,46px);
    background:
      radial-gradient(124% 84% at 50% -20%, color-mix(in srgb, var(--acc) 14%, transparent) 0%, transparent 62%),
      linear-gradient(180deg, var(--paper) 0%, var(--surf) 100%);}
  .ps-hero__title{font-family:var(--font-display);font-weight:600;
    font-size:clamp(40px,6.2vw,72px);line-height:1.02;letter-spacing:-.023em;
    color:var(--ink);margin:0;text-wrap:balance;}
  .ps-hero__lead{max-width:60ch;margin:24px auto 0;
    font-size:clamp(16.5px,1.6vw,19px);line-height:1.62;color:var(--ink-2);
    text-wrap:pretty;}

  /* ══ SECTION HEADS ═════════════════════════════════════════════════════ */
  /* The tint peaks in the middle and resolves back to white at BOTH edges.
     It used to end on --paper, which left a faint step against whatever came
     next: a white band on education, or the wave's own white ground on
     childcare (.wave--into-blue{background:var(--surf)}). Ending on --surf
     means this section drops in anywhere without seaming. */
  .home{background:linear-gradient(180deg, var(--surf) 0%, var(--paper) 52%, var(--surf) 100%);
    padding:clamp(56px,6.4vw,92px) 24px;}
  /* The bottom margin lives HERE, not on the grid. It was dropped in the
     2026-09-06 rebuild, and .ccgrid's own top margin hid that on three
     pages — but Personal Support uses the .homegrid tile layout, which has
     no top margin, so its heading sat flush against the cards (measured
     gap: 0px). Owning the spacing on the head fixes every grid type. */
  .home__head{max-width:820px;margin:0 auto clamp(30px,3.4vw,44px);text-align:center;}
  .home__title{font-family:var(--font-display);font-weight:600;
    font-size:clamp(28px,3.5vw,44px);line-height:1.08;letter-spacing:-.019em;
    color:var(--type);margin:0;text-wrap:balance;}

  /* ══ SERVICE CARD ══════════════════════════════════════════════════════
     The card Caleb asked to see done properly. What makes it read as premium
     is not one flourish but the stack: a card that is a real object (contact
     shadow + accent-tinted cast shadow, not one flat blur), a head zone
     separated from the list by a hairline that BLEEDS to both card edges, an
     icon chip with a genuine bevel, and a hover that resolves as one movement
     — lift, border warm, shadow deepen, accent wash in, top rule wipe across.

     The gradient on the chip is deliberately narrow (90% white-mix → accent →
     88% black-mix). A wide gradient on a small shape reads as a SHAPE INSIDE
     the shape rather than as shading — that is exactly the bug that cost five
     attempts on the landing timeline dots. Narrow range, and it reads as a
     bevel. Verified on screen, not from computed values. ══════════════════ */
  .ccgrid{
    /* The whole card component is blue, not the Page Colour. Caleb, 2026-09-06,
       in three steps: first the icon chips, then the top edge and hover border,
       then the bullets — at which point patching one piece at a time was just
       leaving inconsistent leftovers, so the card's own accent IS the blue.
       #1E90DE is the accent the Support-Area briefs on the landing page use,
       so a visitor clicking through from a modal meets the same colour.

       Consequence: these cards no longer follow the Page Colour. Pick Gold and
       the rest of the page warms up while the cards stay blue. To put them back
       on the theme, set --cc-accent to var(--acc) — everything else keys off it. */
    /* TYPE COLOUR. Caleb, 2026-09-06: "you know how pokemon has colours for
       different cards? earth fire etc — i wanna treat life skills like that…
       since the photo is green and it represents outside."

       A page sets --type and its whole card deck follows: icon chip, bullets,
       the hairline under the lead, the corner wash, the top rule and the hover
       glow all trace back here. Unset, it falls back to --ic (the blue), so
       pages without a type keep exactly what they have. */
    --cc-accent:var(--type);
    /* --cc-ic is the CHIP colour, and the card's chrome — the top edge and
       the hover border/glow — tracks it. That was the original intent here
       ("Caleb wanted this top edge to match the icon chips"); it came apart
       when the chip was split off from the type colour, which left Education
       with navy chips under a blue hover. Pointing it at --ic restores the
       pairing and makes it self-maintaining: change a page's chip and its
       hover follows, with no second edit.

       Caleb, 2026-09-06: "the highlight when i hover over the card is blue
       make it midnight navy." */
    --cc-ic:var(--ic);
    max-width:var(--wrap);margin:0 auto;
    display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;}
  @media(max-width:1000px){.ccgrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:18px;}}
  @media(max-width:680px){.ccgrid{grid-template-columns:1fr;}}

  /* subgrid so the icon, title, lead and the hairline under it line up ACROSS
     the row, whatever the title wraps to. Without it a two-line title (e.g.
     "Professional & Business English" at four-across) pushes that card's rule
     below its neighbours' and the row reads as ragged. row-gap:0 because the
     parent's gap is meant for the space BETWEEN cards, not inside them. */
  .cccat{position:relative;display:grid;grid-template-rows:subgrid;grid-row:span 4;
    row-gap:0;isolation:isolate;
    padding:24px 22px 22px;border-radius:var(--r-lg);overflow:hidden;
    background:linear-gradient(180deg,#FFFFFF 0%, color-mix(in srgb, var(--cc-accent) 4%, #FFFFFF) 100%);
    border:1px solid color-mix(in srgb, var(--cc-accent) 15%, #FFFFFF);
    box-shadow:var(--sh-1), 0 16px 34px -22px color-mix(in srgb, var(--cc-accent) 45%, transparent);
    transition:transform .34s cubic-bezier(.22,1,.36,1),
               box-shadow .34s ease, border-color .34s ease;}
  /* the top rule that wipes across on hover */
  .cccat::before{content:"";position:absolute;inset:0 0 auto;height:2px;z-index:2;
    /* keyed to --cc-ic (the blue), not the Page Colour — Caleb wanted this top
       edge to match the icon chips rather than go purple with the theme */
    background:linear-gradient(90deg, var(--cc-ic) 0%,
      color-mix(in srgb, var(--cc-ic) 45%, transparent) 46%, transparent 88%);
    transform:scaleX(0);transform-origin:left;
    transition:transform .46s cubic-bezier(.22,1,.36,1);}
  /* the accent wash — the same treatment Caleb liked on the landing pillars */
  .cccat::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
    background:radial-gradient(122% 92% at 12% 0%,
      color-mix(in srgb, var(--cc-accent) 10%, transparent) 0%, transparent 68%);
    opacity:0;transition:opacity .34s ease;}
  .cccat:hover{transform:translateY(-4px);
    border-color:color-mix(in srgb, var(--cc-ic) 34%, #FFFFFF);
    box-shadow:var(--sh-1), 0 30px 56px -26px color-mix(in srgb, var(--cc-ic) 58%, transparent);}
  .cccat:hover::before{transform:scaleX(1);}
  .cccat:hover::after{opacity:1;}

  .cccat__ic{
    position:relative;display:flex;align-items:center;justify-content:center;
    width:44px;height:44px;margin:0 0 15px;border-radius:13px;color:#FFFFFF;
    background:linear-gradient(145deg,
      color-mix(in srgb, var(--cc-ic) 90%, #FFFFFF) 0%,
      var(--cc-ic) 55%,
      color-mix(in srgb, var(--cc-ic) 88%, #000000) 100%);
    box-shadow:0 6px 14px -6px color-mix(in srgb, var(--cc-ic) 70%, transparent),
               inset 0 1px 0 rgba(255,255,255,.42);
    transition:transform .34s cubic-bezier(.22,1,.36,1), box-shadow .34s ease;}
  /* ── Icon wiggle ────────────────────────────────────────────────────────
     Caleb, 2026-09-06: "bring those icons in purple to life … wiggle or small
     movement."

     Hover-triggered, not ambient. Six chips looping on their own would pull the
     eye away from the copy they are labelling and read as a novelty; firing on
     hover makes the card feel responsive instead of restless.

     The last keyframe lands exactly on the hover transform below, so when the
     animation ends the chip stays put rather than snapping back a pixel. */
  @keyframes cccat-wiggle{
    0%   {transform:rotate(0deg)   translateY(0)    scale(1);}
    22%  {transform:rotate(-8deg)  translateY(-3px) scale(1.06);}
    45%  {transform:rotate(6deg)   translateY(-2px) scale(1.05);}
    68%  {transform:rotate(-4deg)  translateY(-2px) scale(1.04);}
    85%  {transform:rotate(2deg)   translateY(-1px) scale(1.03);}
    100% {transform:rotate(0deg)   translateY(-1px) scale(1.03);}
  }
  .cccat:hover .cccat__ic{transform:translateY(-1px) scale(1.03);
    animation:cccat-wiggle .62s cubic-bezier(.22,1,.36,1);
    box-shadow:0 11px 22px -7px color-mix(in srgb, var(--cc-ic) 78%, transparent),
               inset 0 1px 0 rgba(255,255,255,.5);}
  .cccat__ic svg{width:21px;height:21px;}

  .cccat__t{margin:0 0 5px;font-family:var(--font-heading);
    font-size:17px;font-weight:700;letter-spacing:-.017em;line-height:1.24;
    color:var(--ink);text-wrap:balance;}
  /* full-bleed hairline: negative inline margin puts the rule on the card
     edges while the text stays on the text column */
  .cccat__lead{margin:0 0 14px;padding:0 22px 14px;margin-inline:-22px;
    border-bottom:1px solid color-mix(in srgb, var(--cc-accent) 16%, transparent);
    font-size:13.5px;line-height:1.45;color:var(--ink-3);}
  .cccat__list{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:9px;}
  .cccat__list li{position:relative;padding-left:17px;
    font-size:14px;line-height:1.46;color:var(--ink-2);}
  .cccat__list li::before{content:"";position:absolute;left:1px;top:.58em;
    width:5px;height:5px;border-radius:50%;background:var(--cc-accent);opacity:.55;}

  /* the "good to know" note, now a real panel instead of loose centred text */
  .home__honest{max-width:780px;margin:clamp(28px,3vw,40px) auto 0;
    padding:16px 24px;border-radius:var(--r);
    background:color-mix(in srgb, var(--acc) 4%, var(--surf));
    border:1px solid color-mix(in srgb, var(--acc) 14%, transparent);
    text-align:center;font-size:13.5px;line-height:1.62;color:var(--ink-2);}
  .home__honest b{color:var(--ink);}

  /* ══ ALTERNATING BANDS ═════════════════════════════════════════════════ */
  .band{padding:clamp(56px,6.4vw,92px) 24px;}
  .band--blue{background:var(--band);}
  .row{max-width:var(--wrap);margin:0 auto;display:grid;
    grid-template-columns:1.02fr .98fr;gap:clamp(34px,5vw,72px);align-items:center;}
  .row--flip .row__text{order:2;}
  .row--flip .row__media{order:1;}
  /* ── Bands on mobile ────────────────────────────────────────────────────
     Caleb, 2026-09-06: "go clean up the mobile service cards … make sure they
     are organized and laid out properly."

     The old rule only un-flipped the columns, so EVERY band on every page
     stacked identically: heading, then a wall of five to eight bullets, then
     the photo right at the bottom where it did no work. Five of those in a row
     read as one undifferentiated column of text — that is the "weird" part.

     Desktop alternates the photo left and right to give the page rhythm. The
     mobile equivalent is not alternation (which would bury half the headings);
     it is interleaving — title, one-line lead, PHOTO, then the detail. Every
     band still leads with its name so the page stays scannable, and the photo
     breaks the text instead of trailing it.

     display:contents on .row__text dissolves the wrapper so its children
     become grid items alongside .row__media, which is what makes the photo
     sit BETWEEN the lead and the bullets with no markup change. .row__media
     keeps the photo and its "View real session" link together as one unit. */
  @media(max-width:860px){
    .row{grid-template-columns:1fr;gap:0;}
    .row__text{display:contents;}
    .row__title{order:1;margin:0 0 8px;font-size:clamp(24px,6.4vw,30px);}
    .row__lead{order:2;margin:0 0 18px;font-size:16px;}
    .row__media{order:3;margin:0 0 20px;}
    .row__list{order:4;gap:12px;}
    .row__proof{order:5;margin-top:16px;}
    /* The desktop flip rule `.row--flip .row__media{order:1}` lives OUTSIDE this
       media query and is (0,2,0), so it beats the (0,1,0) `.row__media` above at
       every width — flipped rows kept throwing the photo above the lead. Being
       inside a media query buys no specificity. Restate it at matching
       specificity so mobile wins. (`.row__text` needs nothing: display:contents
       removes it from the grid, so its order is inert.) */
    .row--flip .row__media{order:3;}
    .band{padding:clamp(40px,9vw,56px) 20px;}
    /* Photo geometry on mobile. Caleb, 2026-09-06, comparing against
       adventurenannies.com: "nicer corners on the photos, mine are too round …
       theirs look longer horizontally."

       Both true, and measurable. Ours ran 4/3.2 (1.25 — nearly square) with a
       20px radius; theirs measure ~1.47 with roughly a 9pt radius. A wide,
       shallow frame reads as editorial; a near-square one with heavy rounding
       reads like an app tile. Desktop keeps 4/3.2 — it has the column width to
       carry a taller frame, and its photos sit beside text rather than under it. */
    /* Scoped through .row so these are (0,2,0). The base `.row__photo` and
       `.mediapanel` rules sit ~10k chars LATER in this file at (0,1,0), and on
       a specificity tie the later rule wins — being inside a media query counts
       for nothing. At equal specificity mobile silently lost. */
    /* radius is 5px at every width now (Caleb, 2026-09-06 — matched to the
       reference, then dialled to 5px by Caleb on his phone); only the
       aspect ratio changes on mobile, to the wider 3/2 editorial frame */
    .row .row__photo,.row .mediapanel{aspect-ratio:3/2;}
    /* NOT 3/2. ps-elderly.jpg is 900x1020 PORTRAIT — a stacked two-pane video
       call — and the desktop rule already gives it its own ratio so both faces
       fit. The blanket mobile rule here used to force 3/2 over that, which
       cropped ~40% of the height and cut the woman's head off (Caleb, phone,
       2026-09-06). It keeps its own aspect on mobile too; it is simply a
       taller photo than its neighbours, which is correct for this image. */
    .row .row__photo--stack{aspect-ratio:900/1020;max-width:none;}
    .row .mediapanel__medal{width:38%;max-width:150px;}
    .row__list li{font-size:15px;line-height:1.55;}
  }
  .row__title{font-family:var(--font-heading);font-weight:700;
    font-size:clamp(26px,3vw,37px);line-height:1.12;letter-spacing:-.018em;
    color:var(--ink);margin:0 0 12px;text-wrap:balance;}
  .row__lead{font-size:16.5px;font-weight:600;color:var(--ink);line-height:1.5;margin:0 0 20px;}
  .row__list{list-style:none;margin:0;padding:0;display:grid;gap:13px;}
  .row__list li{display:flex;gap:13px;align-items:flex-start;
    font-size:15px;line-height:1.58;color:var(--ink-2);}
  .row__list li b{color:var(--ink);font-weight:650;}
  /* flat fill, never a gradient — a gradient on a 22px circle reads as a
     shape sitting inside the circle rather than as shading */
  /* ── The tick circle ───────────────────────────────────────────────────
     Repainted from scratch, 2026-09-06. Caleb, three times over: "i see a
     green circle behind it" → "i see a lighter basic green dot in the back"
     → "the top of the circle shows it's poking out still… just remove
     anything related and repaint the new premium one."

     He was right every time, and it was TWO different things:

       1. an outer glow (--acc at 68%, 8px blur) painting a saturated disc
          wider than the 22px circle; and
       2. an inset white highlight, which lit the TOP RIM a paler green — the
          "poking out at the top". Diagnosed by rendering the tick at 7x with
          each shadow layer isolated: only the variant with NO shadows at all
          had a clean edge.

     So the circle now carries NO box-shadow of any kind. Every bit of depth
     comes from the sheen sweeping across it, which is clipped inside the
     circle (verified by painting the pseudo-element solid red at 9x — it fills
     the circle exactly and never escapes). One flat disc, one moving
     highlight, nothing behind it. */
  .tick{
    flex:none;width:22px;height:22px;border-radius:50%;margin-top:1px;
    display:flex;align-items:center;justify-content:center;
    background:var(--type);
    position:relative;overflow:hidden;isolation:isolate;
    box-shadow:none;
  }
  .tick svg{width:11px;height:11px;stroke:#fff;stroke-width:2.8;fill:none;
    stroke-linecap:round;stroke-linejoin:round;}
  .row__proof{margin:18px 0 0;font-size:13.5px;font-style:italic;line-height:1.55;color:var(--ink-3);}

  /* ══ MEDIA PANEL ═══════════════════════════════════════════════════════
     Was a giant 34%-wide line icon floating in a flat pink box, five times
     over — the least premium thing on the page, and pink agreed with nothing
     else. Now an accent-lit ground with the icon carried in a glass medallion,
     so it reads as a composed object and moves with the Page Colour. ═════ */
  .mediapanel{position:relative;border-radius:5px;aspect-ratio:4/3.2;
    display:flex;align-items:center;justify-content:center;overflow:hidden;
    background:
      radial-gradient(86% 72% at 16% 8%,  color-mix(in srgb, var(--acc) 26%, transparent) 0%, transparent 60%),
      radial-gradient(84% 74% at 90% 96%, color-mix(in srgb, var(--ink) 15%, transparent) 0%, transparent 62%),
      linear-gradient(155deg, #FFFFFF 0%, color-mix(in srgb, var(--acc) 12%, #FFFFFF) 100%);
    box-shadow:var(--sh-3), inset 0 0 0 1px color-mix(in srgb, var(--ink) 7%, transparent);}
  .mediapanel__medal{position:relative;display:flex;align-items:center;justify-content:center;
    width:46%;max-width:190px;aspect-ratio:1;border-radius:50%;
    background:linear-gradient(160deg, #FFFFFF 0%,
      color-mix(in srgb, var(--acc) 7%, #FFFFFF) 100%);
    box-shadow:0 26px 50px -24px color-mix(in srgb, var(--ink) 62%, transparent),
               0 2px 6px -2px color-mix(in srgb, var(--ink) 26%, transparent),
               inset 0 0 0 1.5px color-mix(in srgb, var(--acc) 28%, transparent);}
  .mediapanel__medal svg{width:53%;height:auto;stroke:var(--acc);stroke-width:1.6;
    fill:none;stroke-linecap:round;stroke-linejoin:round;}
  /* the newborn photo — real alpha, so it stands on the panel's own ground.
     Re-editable cutout: _image-originals-2026-08-03/cc-newborn-cutout.png.
     contain + bottom = nothing cropped and she stands on the panel floor;
     cover would slice the top of her head (photo 0.96 square, panel 4/3.2). */
  .mediapanel__photo{position:relative;z-index:1;width:100%;height:100%;
    object-fit:contain;object-position:center bottom;display:block;}

  /* ══ WAVES ═════════════════════════════════════════════════════════════
     The fills were hardcoded #EAF6FC / #ffffff in the SVG markup, so the
     moment the bands started following the Page Colour the waves would have
     stayed the old blue and torn a seam across every section change. They
     inherit now: each wave's `color` IS the surface it transitions into. ══ */
  .wave{position:relative;height:clamp(52px,6.5vw,86px);line-height:0;}
  .wave svg{position:absolute;left:0;bottom:-1px;width:100%;height:100%;}
  .wave svg path{fill:currentColor;}
  .wave--into-blue{background:var(--surf);color:var(--band);}
  .wave--outof-blue{background:var(--band);color:var(--surf);}

  /* ══ CLOSING CTA ═══════════════════════════════════════════════════════ */
  .ps-cta{position:relative;text-align:center;overflow:hidden;
    padding:clamp(66px,8.4vw,112px) 24px clamp(70px,9vw,120px);
    background:
      radial-gradient(92% 122% at 50% 104%, color-mix(in srgb, var(--acc) 13%, transparent) 0%, transparent 64%),
      linear-gradient(180deg, var(--surf) 0%, var(--paper) 100%);}
  .ps-cta__title{font-family:var(--font-display);font-weight:600;
    font-size:clamp(30px,4.2vw,50px);line-height:1.06;letter-spacing:-.021em;
    color:var(--ink);margin:0 auto 28px;max-width:min(34ch,100%);text-wrap:balance;}
  /* 16ch used to force a wrap: the longest title, "Need a big brother or big
     sister?", is 33 characters, so it always broke across two lines. 34ch fits
     every one of the four on a single line on desktop, and the min() keeps it
     from overflowing narrow screens, where wrapping is correct anyway. */
  .ps-cta__btn{display:inline-block;background:var(--acc);color:#fff;
    font-size:16.5px;font-weight:700;padding:16px 42px;border-radius:var(--r);
    text-decoration:none;
    box-shadow:0 16px 34px -16px color-mix(in srgb, var(--acc) 72%, transparent);
    transition:background .18s ease, transform .18s ease, box-shadow .18s ease;}
  .ps-cta__btn:hover{transform:translateY(-2px);
    background:color-mix(in srgb, var(--acc) 88%, #000);
    box-shadow:0 24px 46px -16px color-mix(in srgb, var(--acc) 80%, transparent);}
  .ps-cta__sub{margin:24px auto 0;max-width:540px;font-size:14.5px;line-height:1.6;color:var(--ink-2);}
  .ps-cta__sub b{color:var(--ink);}

  /* ══ FOOTER ══════════════════════════════════════════════════════════════
     Caleb, 2026-09-06: "i dont like the dark footer — make it a lighter purple
     or connect it to the theme colour button."

     It is now a light tint of the chosen Page Colour, so it moves with the
     theme like everything else on the page instead of sitting under a fixed
     #0F2F34 slab. EVERY colour is restated here, not just the background: the
     old rules live in each page's own <style>, and a property this sheet does
     not declare keeps the dark value — which would leave white text on a pale
     ground. That is the same trap the footer logo's filter fell into. */
  footer{background:color-mix(in srgb, var(--acc) 11%, #FFFFFF);
    color:var(--ink-2);
    border-top:1px solid color-mix(in srgb, var(--acc) 20%, transparent);
    padding:clamp(44px,5vw,68px) clamp(20px,5vw,64px) 30px;}
  .footer-top{max-width:var(--wrap);margin:0 auto;display:grid;
    grid-template-columns:1.4fr 1fr 1fr 1fr;gap:32px;}
  @media(max-width:820px){.footer-top{grid-template-columns:1fr 1fr;gap:28px;}}
  @media(max-width:480px){.footer-top{grid-template-columns:1fr;}}
  .footer-brand img{height:38px;width:auto;margin-bottom:14px;filter:none;}
  .footer-brand p{font-size:14px;line-height:1.6;color:var(--ink-3);max-width:34ch;margin:0;}
  .footer-col h4{font-size:13px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;
    color:var(--ink);margin:0 0 14px;}
  .footer-col ul{list-style:none;margin:0;padding:0;display:grid;gap:10px;}
  .footer-col a{font-size:14.5px;color:var(--ink-2);text-decoration:none;
    transition:color .15s ease;}
  .footer-col a:hover{color:var(--acc);}
  .footer-bottom{max-width:var(--wrap);margin:34px auto 0;padding-top:20px;
    border-top:1px solid color-mix(in srgb, var(--ink) 12%, transparent);
    display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;
    font-size:13px;color:var(--ink-3);}

  @media (prefers-reduced-motion: reduce){
    html{scroll-behavior:auto;}
    .cccat,.cccat__ic,.cccat::before,.cccat::after,.ps-cta__btn{transition:none;}
    .cccat:hover .cccat__ic{animation:none;}
    .cccat:hover{transform:none;}
    .cccat:hover::before{transform:scaleX(1);}
  }

  /* ── Photo frames ───────────────────────────────────────────────────────
     Education, Life Skills and Personal Support carry real photos where
     childcare carries icon medallions (15 photo frames across the three).
     They were on their own radius and a hardcoded rgba(18,59,66,.5) shadow;
     tokenised here so a photo row and an icon row sit on the same frame. */
  .row__photo{border-radius:5px;aspect-ratio:4/3.2;overflow:hidden;
    box-shadow:var(--sh-3), inset 0 0 0 1px color-mix(in srgb, var(--ink) 7%, transparent);}
  .row__photo img{width:100%;height:100%;object-fit:cover;display:block;}
  /* taller frame for the stacked two-person video-call photo, so both fit */
  .row__photo--stack{aspect-ratio:900/1020;max-width:440px;margin-inline:auto;}
  /* low-key "watch the real session" link under a photo */
  .row__watch{display:flex;justify-content:center;align-items:center;gap:7px;
    margin:13px 0 0;color:var(--acc);font-size:12.5px;font-weight:600;
    text-decoration:none;opacity:.82;transition:opacity .15s ease;}
  .row__watch:hover{opacity:1;text-decoration:underline;}
  .row__watch svg{width:15px;height:15px;flex:none;}

  /* Exactly four categories (Education) run as ONE horizontal row rather than
     2×2. Caleb, 2026-09-06: "try putting this horizontal instead of 2:2, its
     too big vertically." Four across at the full container is ~265px a card,
     so the gap tightens and the padding comes in a little to buy line width.

     Every step below has to repeat the :has() selector: `.ccgrid:has(…)` beats
     a plain `.ccgrid` on specificity, so a media query written against the
     bare class would never take effect against this rule. */
  .ccgrid:has(> :nth-child(4)):not(:has(> :nth-child(5))){
    grid-template-columns:repeat(4,minmax(0,1fr));
    gap:14px;
  }
  .ccgrid:has(> :nth-child(4)):not(:has(> :nth-child(5))) .cccat{padding:20px 17px 18px;}
  .ccgrid:has(> :nth-child(4)):not(:has(> :nth-child(5))) .cccat__lead{
    padding-inline:17px;margin-inline:-17px;}
  @media(max-width:1080px){
    .ccgrid:has(> :nth-child(4)):not(:has(> :nth-child(5))){
      grid-template-columns:repeat(2,minmax(0,1fr));gap:18px;}
  }
  @media(max-width:680px){
    .ccgrid:has(> :nth-child(4)):not(:has(> :nth-child(5))){grid-template-columns:1fr;}
  }



  /* ── Boxed hero description ─────────────────────────────────────────────
     Caleb, 2026-09-06: "try putting this in a thin box … its a description."
     A hairline frame, not a panel: the border carries a trace of the accent so
     it belongs to the theme, and the fill is a translucent white that lets the
     hero's own gradient show through rather than punching a flat card into it.
     Wider than the unboxed lead so it reads as a thin band rather than a
     block — the same words wrap to fewer lines inside it. */
  .ps-hero__lead--box{
    max-width:min(860px,100%);
    margin-top:26px;
    padding:18px clamp(20px,3vw,32px);
    border-radius:var(--r-lg);
    border:1px solid color-mix(in srgb, var(--acc) 20%, transparent);
    background:color-mix(in srgb, #FFFFFF 72%, transparent);
    box-shadow:var(--sh-1);
    text-wrap:pretty;
  }
  @media(max-width:600px){
    .ps-hero__lead--box{padding:16px 18px;border-radius:var(--r);}
  }

  /* The box can hold more than one paragraph (Life Skills carries a second
     one about why children look forward to sessions). Margins are handled
     here so the box stays a <div> wrapper without inheriting stray <p> gaps. */
  .ps-hero__lead--box > p{margin:0;}
  .ps-hero__lead--box > p + p{margin-top:13px;}
  .ps-hero__lead--box em{font-style:italic;}

  /* ── Hero description, as two disclosure rows ───────────────────────────
     Caleb, 2026-09-06: "maybe like we had the faq type thing we can add them
     into 2 … 1 can automatically be expanded … not all big and bulky."

     The single boxed description had grown to 102 words / 9 lines and was
     centred, which is what made it read as a notice rather than a hero: past
     about three lines, centring leaves both edges ragged and every line starts
     somewhere different. So the copy is left-aligned in here, and only one row
     is open at a time (row 1 ships open), which caps the hero's height no
     matter how much either row holds.

     ONE outer hairline with rows divided inside — not a border per row. Nested
     boxes are exactly the bulk he was reacting to. */
  .ps-hero__disc{
    max-width:min(760px,100%);
    margin:26px auto 0;
    text-align:left;
    border:1px solid color-mix(in srgb, var(--acc) 20%, transparent);
    border-radius:var(--r-lg);
    background:color-mix(in srgb, #FFFFFF 72%, transparent);
    box-shadow:var(--sh-1);
    overflow:hidden;
  }
  .hdisc__item + .hdisc__item{border-top:1px solid color-mix(in srgb, var(--acc) 14%, transparent);}
  /* the open row carries a faint ground so its header and body read as one
     block rather than a heading with loose text beneath it */
  .hdisc__item[open]{background:color-mix(in srgb, var(--acc) 4%, transparent);}
  .hdisc__q{
    list-style:none;cursor:pointer;display:flex;align-items:center;
    justify-content:space-between;gap:14px;padding:15px 20px;
    font-family:var(--font-heading);font-size:15.5px;font-weight:700;
    color:var(--ink);transition:background .15s ease;
  }
  .hdisc__q::-webkit-details-marker{display:none;}
  .hdisc__q:hover{background:color-mix(in srgb, var(--acc) 5%, transparent);}
  /* :focus-visible, NOT :focus-within — the earlier rule drew a heavy accent
     box around the header on every mouse click, which is what made the open
     row look broken. Keyboard users still get a ring; mouse users do not. */
  .hdisc__q:focus-visible{outline:2px solid var(--acc);outline-offset:-3px;border-radius:6px;}
  /* A chevron, not a +/−. Caleb, 2026-09-06: "the + - looks weird, maybe just
     V or something more natural for description like this." He is right about
     the semantics: +/− reads as add/remove, which suits a FAQ where each row is
     a discrete question. A chevron reads as show-more, which is what a
     description that continues actually does.

     Drawn from two borders on a square rotated 45°, so it scales with the type
     and takes the accent without an asset. translateY nudges each state onto
     the optical centre — a rotated square's bounding box shifts as it turns,
     so without it the mark appears to drift up when opened. */
  .hdisc__ic{flex:none;width:18px;height:18px;position:relative;}
  .hdisc__ic::before{content:'';position:absolute;left:4px;top:4px;width:9px;height:9px;
    border-right:2px solid var(--acc);border-bottom:2px solid var(--acc);border-radius:1.5px;
    transform:rotate(45deg) translateY(-1px);transform-origin:center;
    transition:transform .3s cubic-bezier(.22,1,.36,1);}
  .hdisc__item[open] .hdisc__ic::before{transform:rotate(-135deg) translateY(-1px);}
  .hdisc__a{padding:2px 20px 19px;}
  .hdisc__a > p{margin:0;font-size:15px;line-height:1.62;color:var(--ink-2);text-wrap:pretty;}
  @media(max-width:600px){
    .hdisc__q{padding:14px 16px;font-size:15px;}
    .hdisc__a{padding:0 16px 15px;}
  }

  /* ── Where sessions happen ──────────────────────────────────────────────
     Caleb, 2026-09-06: add online, "make sure this is nicely and
     professionally laid out."

     This was a sentence wrapped in curly quotes and set in italics, which read
     as a testimonial nobody actually said. It is not a quote — it is the answer
     to a question every family asks, so it is now three labelled options a
     reader can take in at a glance instead of a line they have to parse.
     The tooltip stays on the one option that carries a condition. */
  /* A plain list, no icons. Caleb, 2026-09-06: "dont put icons in there …
     this looks weird with icons." He is right — three icon chips for three
     locations was decoration doing no work: the labels already say everything,
     and the chips made a short list look like a toolbar. Same small accent
     bullet the category cards use, so it belongs to the page's own vocabulary. */
  .ps-where{margin:0;}
  .ps-where__list{list-style:none;margin:0;padding:0;
    display:flex;flex-direction:column;gap:7px;}
  .ps-where__item{position:relative;padding-left:16px;
    font-size:15px;line-height:1.55;color:var(--ink-2);}
  .ps-where__item::before{content:"";position:absolute;left:1px;top:.6em;
    width:5px;height:5px;border-radius:50%;background:var(--acc);opacity:.55;}
  .ps-where__note{margin:13px 0 0;font-size:13.5px;color:var(--ink-3);}

  /* The "something not on the list?" line under the cards. Personal Support is
     the only page that carries it. Its own inline rule styles the paragraph but
     not a link inside it, so the new "Email us" anchor inherited body ink and
     did not read as clickable. */
  .home__foot{max-width:820px;margin:clamp(28px,3vw,40px) auto 0;text-align:center;
    font-size:15.5px;line-height:1.6;color:var(--ink-2);}
  .home__foot b{color:var(--ink);}
  .home__foot a{color:var(--acc);font-weight:600;text-decoration:none;
    border-bottom:1px solid color-mix(in srgb, var(--acc) 34%, transparent);
    transition:border-color .15s ease;}
  .home__foot a:hover{border-bottom-color:var(--acc);}

  /* ── Category cards as a swipe rail on phones ───────────────────────────
     Caleb, 2026-09-06: "I want those to horizontally scroll and show 1 at a
     time. Having all of them laid out vertically is too much scrolling."

     Six stacked cards with five-to-eight bullets each is roughly four screens
     of thumb-work before you reach the next section. As a snap rail it is one
     screen with a peek of the next card to signal there is more.

     Deliberately the same mechanics as the landing page's .pmsvc-grid rail
     (flex, x-mandatory snap, centre align, hidden scrollbar, contained
     overscroll) so the site has ONE swipe behaviour, not two that feel
     slightly different. */
  /* The dots only exist for the rail.  NOTE: .ccdots is a SIBLING of .ccgrid,
     not a child, so --cc-accent (declared on .ccgrid) does not reach here —
     these take the root-level --ic, which is the same blue. */
  .ccdots{display:none;justify-content:center;gap:7px;margin-top:18px;}
  .ccdots button{position:relative;overflow:hidden;
    width:7px;height:7px;border-radius:99px;border:0;padding:0;cursor:pointer;
    background:color-mix(in srgb, var(--ink) 18%, transparent);
    transition:width .34s cubic-bezier(.4,0,.2,1), background .34s ease;}
  .ccdots button.is-on{width:26px;
    background:color-mix(in srgb, var(--type) 22%, transparent);}
  /* The fill IS the read-timer — it is what makes the auto-advance feel
     deliberate instead of twitchy, because you can see the move coming.
     Duration comes from the script (--cc-dwell) so the two cannot drift. */
  .ccdots button.is-on::after{content:'';position:absolute;inset:0;
    border-radius:inherit;background:var(--type);
    transform:scaleX(1);transform-origin:left;}
  .ccdots.is-playing button.is-on::after{
    animation:cc-fill var(--cc-dwell,5500ms) linear forwards;}
  @keyframes cc-fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
  @media(prefers-reduced-motion:reduce){
    .ccdots.is-playing button.is-on::after{animation:none;transform:scaleX(1);}
  }
  @media(max-width:680px){
    .ccgrid,
    .ccgrid:has(> :nth-child(4)):not(:has(> :nth-child(5))){
      display:flex;
      grid-template-columns:none;
      gap:14px;
      /* bleed past the section's 24px padding so a card can peek at the edge */
      margin-inline:-24px;
      padding:6px 24px 10px;
      overflow-x:auto;
      scroll-snap-type:x mandatory;
      overscroll-behavior-x:contain;
      -webkit-overflow-scrolling:touch;
      scrollbar-width:none;
    }
    .ccgrid::-webkit-scrollbar{display:none;}
    /* subgrid needs a GRID parent — the rail is flex, so the cards go back to
       being their own flex columns or they collapse */
    .cccat{
      display:flex;flex-direction:column;
      grid-template-rows:none;grid-row:auto;
      flex:0 0 82%;max-width:330px;
      scroll-snap-align:center;
    }
    .ccdots{display:flex;}
  }

  /* ── Video modal: put it ABOVE the site header ──────────────────────────
     Caleb, 2026-09-06, from his phone: "when i open the video i cant see the
     X to exit out so im stuck… i think its behind the header menu part…
     its actually the same with the other videos."

     He was right, and it was every video on every page. The page declares
     .vm-overlay{z-index:1000} while the injected header is z-index:9000
     (its drawer 9100) — so the header always painted over the top of the
     dialog, and the close button lives at top:-15px, i.e. exactly in the
     strip the header covers.

     Escape and a backdrop tap did both work, but neither rescues a phone:
     there is no Escape key, and a 9:16 video at 84vh leaves almost no
     backdrop to hit. So the X was the only real way out, and it was hidden.

     A modal is by definition the top layer — above the header, not under it. */
  .vm-overlay{z-index:9500;}

  @media(max-width:700px){
    /* On a phone the frame can reach the viewport edges, so a button hung
       OUTSIDE its corner is one rounding error from being unreachable.
       Bring it inside the frame, where it cannot be clipped by anything. */
    .vm-close{top:10px;right:10px;width:44px;height:44px;
      background:rgba(255,255,255,.95);
      box-shadow:0 6px 20px rgba(0,0,0,.45), 0 0 0 1px rgba(0,0,0,.06);}
    .vm-close svg{width:21px;height:21px;stroke-width:2.6;}
  }


  /* ── Phone-only hero photo (Private Education) ──────────────────────────
     Caleb, 2026-09-06: "i think mobile might be good with a title and nice
     photo right underneath to look more professional… i wanna see what this
     looks like with a real photo in the same box where the writing is and the
     writing contracted and needing to be clicked."

     So on a phone the hero reads title → photo → one tappable line, and the
     description moves behind that tap (see the script in education.html).
     Desktop is untouched: the photo is display:none and the paragraph stays
     in its box exactly as before.

     Framed like every other photo on the site — 5px corners, the same lift —
     so it reads as part of the set rather than a one-off hero treatment. */
  .ps-hero__shot{
    display:block;
    /* Matched to .ps-hero__disc's max-width so the title, the photo and the
       tappable line stack as ONE centred column with flush edges, rather than
       three elements that happen to be centred at three different widths. */
    max-width:min(760px,100%);
    margin:30px auto 0;             /* also kills the UA's 40px figure margin */
    border-radius:5px;
    overflow:hidden;
    /* Wider crop on desktop: at 760px a 4:3 frame is ~570px tall and pushes
       everything below the fold. 16:9 keeps the hero to one screen.

       Overridable per page, because the right frame depends on the SOURCE
       photo: ed-grading.jpg is landscape and takes 16:9 happily, while
       ls-activities.jpg is portrait (1040x1387) and a 16:9 crop of it keeps
       only ~42% of the height — a thin band that cuts the people out. Set
       --shot-a / --shot-a-m on the figure to suit the photo. */
    aspect-ratio:var(--shot-a, 16/9);
    box-shadow:var(--sh-3), inset 0 0 0 1px color-mix(in srgb, var(--ink) 7%, transparent);
  }
  .ps-hero__shot img{
    display:block;width:100%;height:100%;
    /* 45% keeps the two heads and the marked-up worksheets in frame at every
       crop — the subject sits below centre in the source photo. */
    object-fit:cover;object-position:center 45%;
  }

  @media(max-width:700px){
    /* A phone is narrow enough that 16:9 becomes a letterbox strip, so the
       photo goes back to a portrait-ish crop and spans the full column. */
    .ps-hero__shot{max-width:none;margin:22px 0 0;aspect-ratio:var(--shot-a-m, 4/3.2);}
    .ps-hero__disc--lead{margin-top:18px;}
  }


  /* ── Navy role: what you read and click ────────────────────────────────
     Caleb, 2026-09-06: "i want all the check mark circles to stay the
     midnight navi colour … all the video text to follow the midnight navi
     colour as well … [row title, lead and the run-in labels] to follow the
     midnight navi colour as well … but not this part: 'parks, sports,
     events …' those are grey they can stay like that."

     So the split is deliberate and narrow: the run-in LABEL goes navy, the
     descriptive clause after the dash stays --ink-2 grey. That is what makes
     the bullets scannable — the label is the thing you read first. */
  /* The ticks are markers, not controls — the same job the card bullets do,
     and those already follow --type. (The colour itself is set in the single
     .tick rule above; this note is kept for the reasoning.) */
  .row__watch{color:var(--navy);}
  /* Row TITLES take the page's type colour — Caleb pointed at "Toddlers" on
     Childcare: "now do all the titles for each of them, make it match it."
     The lead and the run-in labels stay navy: they are reading text, and a
     whole paragraph set in amber or green stops being a heading accent and
     starts being hard to read. The heading is the accent moment. */
  .row__title{color:var(--type);}
  /* The bold run-in LABEL of each bullet follows the type too — Caleb,
     2026-09-06: "make these parts that are midnight follow the same theme …
     just those single parts of the bulletins". The descriptive clause after
     the dash stays --ink-2 grey, which is what keeps the list scannable.
     The row LEAD stays navy: it is a full sentence of reading text. */
  .row__list li b{color:var(--type);}
  /* The row LEAD sits on --ink — Caleb, 2026-09-06: "make those subtitles
     whatever this colour is: 'Good to know:'", which is --ink #123B42.

     It is also the right call on readability: the lead is 16.5px/600, just
     under the 18.66px bold cutoff, so it counts as normal text and needs
     4.5:1. In the type colour it measured 3.00:1 on Childcare's band; on
     --ink it is 10.5:1. The title above it stays the page colour, so the row
     still reads as coloured — the accent is the heading, not the paragraph. */
  .row__lead{color:var(--ink);}
  /* The inline cross-links inside a row ("… the Private Education support").
     --ink, matching the closing CTA title — Caleb, 2026-09-06: "make Private
     Education the same colour text as 'Need a big brother or big sister?'".
     NOTE the live one on life-skills.html also carries an inline style
     attribute, which outranks this rule; both were changed together. */
  .row__text a{color:var(--ink);
    border-bottom-color:color-mix(in srgb, var(--ink) 40%, transparent);}

  /* ── Photo caption — MOBILE ONLY ────────────────────────────────────────
     Caleb, 2026-09-06, on the first attempt (a filled plate): "i dont like the
     bottom of the photo subtitle. i was thinking a very thin border, that's
     it. this is weird. im also thinking fine print, like smaller."

     So: no fill. The caption sits directly under the photo, separated by a
     single hairline, at fine-print size. The wrapper still carries the frame's
     radius and lift so the photo and its line read as one object — that part
     was right; it was the filled slab that made it heavy.

     Markup only exists below 860px (js/pm-service.js builds and tears it
     down), and these rules are scoped to match so nothing leaks to desktop. */
  @media(max-width:860px){
    .row__framed{
      position:relative;
      border-radius:5px;
      overflow:hidden;
      box-shadow:var(--sh-3), inset 0 0 0 1px color-mix(in srgb, var(--ink) 8%, transparent);
    }
    .row .row__framed > .row__photo,
    .row .row__framed > .mediapanel{
      border-radius:0;
      box-shadow:none;
    }
    .row__cap{
      padding:10px 14px 11px;
      background:#FFFFFF;
      border-top:1px solid color-mix(in srgb, var(--ink) 10%, transparent);
    }
    /* fine print: a size step below the bullet text, lighter weight than the
       paragraph it used to be, and no margin — it is a caption now */
    .row .row__cap .row__lead{
      order:0;
      margin:0;
      font-size:12.5px;
      font-weight:500;
      line-height:1.45;
      letter-spacing:.002em;
    }
  }

  /* ── Tick circles: the button's premium treatment, at 22px ──────────────
     Caleb, 2026-09-06: "make the check marks that nice sparkle and super
     premium — like how we did with the waiting list button."

     WHAT IS BORROWED: the same pmMnSheen keyframes the Waiting List button
     uses (landing-sparkle.css, already loaded here), plus the button's inset
     top highlight. So the light travels across a tick exactly the way it
     travels across the button.

     WHAT IS DELIBERATELY NOT BORROWED: the button's gradient fill. The rule
     above already says why — "a gradient on a 22px circle reads as a shape
     sitting inside the circle rather than as shading" — which is the same
     failure that made the chapter-02 timeline dots look broken. At 44px the
     card chips carry a gradient happily; at 22px it becomes an artefact. The
     fill stays flat and the richness comes from the moving highlight instead.

     Nor the four-point sparkle: one on a hero button reads as a flourish,
     twenty of them twinkling down a list reads as a page that will not sit
     still. The sweep is staggered per row instead, so the ticks catch the
     light in sequence — the same trick as the rail's read-timer. */
  /* the checkmark rides above the sweep */
  .tick svg{position:relative;z-index:2;}
  .tick::before{
    content:'';position:absolute;inset:-2px;z-index:1;pointer-events:none;
    background:linear-gradient(102deg,
      rgba(255,255,255,0)   36%,
      rgba(255,255,255,.28) 45%,
      rgba(255,255,255,.60) 50%,
      rgba(255,255,255,.28) 55%,
      rgba(255,255,255,0)   64%);
    transform:translate3d(-140%,0,0);
    animation:pmMnSheen 7.5s cubic-bezier(.5,0,.25,1) infinite;
    will-change:transform;
  }
  /* staggered so the list catches the light one tick at a time */
  .row__list li:nth-child(1) .tick::before{animation-delay:0s;}
  .row__list li:nth-child(2) .tick::before{animation-delay:.28s;}
  .row__list li:nth-child(3) .tick::before{animation-delay:.56s;}
  .row__list li:nth-child(4) .tick::before{animation-delay:.84s;}
  .row__list li:nth-child(5) .tick::before{animation-delay:1.12s;}
  .row__list li:nth-child(6) .tick::before{animation-delay:1.4s;}
  .row__list li:nth-child(7) .tick::before{animation-delay:1.68s;}
  .row__list li:nth-child(8) .tick::before{animation-delay:1.96s;}

  @media (prefers-reduced-motion:reduce){
    .tick::before{animation:none;opacity:0;}
  }

  /* ── Service switcher (floating, bottom-right) ──────────────────────────
     Built by js/pm-service.js. Sits at z-index 8600: above the page, below
     the injected header (9000), its drawer (9100) and the video modal (9500),
     so it can never cover a dialog or trap someone behind it. */
  .pmsw{
    position:fixed;right:20px;bottom:20px;z-index:8600;
    display:flex;flex-direction:column;align-items:flex-end;gap:10px;
  }
  .pmsw__toggle{
    width:54px;height:54px;border-radius:50%;border:0;cursor:pointer;padding:0;
    display:flex;align-items:center;justify-content:center;
    background:var(--sw);color:#fff;
    box-shadow:0 10px 26px -8px color-mix(in srgb, var(--sw) 62%, transparent),
               0 2px 6px -2px color-mix(in srgb, var(--ink) 34%, transparent);
    transition:transform .22s cubic-bezier(.22,1,.36,1), box-shadow .22s ease;
  }
  .pmsw__toggle:hover{transform:translateY(-2px) scale(1.04);}
  .pmsw__toggle:focus-visible{outline:2px solid var(--sw);outline-offset:3px;}
  .pmsw__ic{display:flex;}
  .pmsw__ic svg{width:24px;height:24px;}
  /* the dial turns as it opens, so the button reads as a control not a badge */
  .pmsw.is-open .pmsw__toggle{transform:rotate(45deg);}
  .pmsw.is-open .pmsw__toggle .pmsw__ic{transform:rotate(-45deg);}

  /* THE PANEL MUST HONOUR [hidden]. An author `display:flex` beats the UA's
     `[hidden]{display:none}`, so the script setting menu.hidden did nothing
     and the empty white card stayed on screen after closing (Caleb: "when i
     close it it stays white like that"). This rule is what makes `hidden`
     mean hidden — and it is why the panel also fades on its own below, so
     closing reads as a dismissal rather than the rows vanishing out of a
     box that lingers. */
  .pmsw__menu[hidden]{display:none;}
  .pmsw__menu{
    display:flex;flex-direction:column;gap:7px;
    opacity:0;transform:translateY(8px) scale(.97);transform-origin:100% 100%;
    transition:opacity .18s ease, transform .2s cubic-bezier(.22,1,.36,1);
    padding:9px;border-radius:16px;
    background:color-mix(in srgb, #FFFFFF 92%, transparent);
    -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
    border:1px solid color-mix(in srgb, var(--ink) 9%, transparent);
    box-shadow:0 22px 48px -22px color-mix(in srgb, var(--ink) 55%, transparent);
  }
  .pmsw__item{
    display:flex;align-items:center;gap:10px;
    padding:8px 14px 8px 8px;border-radius:11px;
    text-decoration:none;font-size:14px;font-weight:650;color:var(--ink);
    white-space:nowrap;
    /* each row rises in turn — the stagger is what makes it feel deliberate */
    opacity:0;transform:translateY(6px);
    transition:opacity .22s ease, transform .22s cubic-bezier(.22,1,.36,1), background .15s ease;
  }
  .pmsw.is-open .pmsw__menu{opacity:1;transform:none;}
  .pmsw.is-open .pmsw__item{opacity:1;transform:none;}
  .pmsw.is-open .pmsw__item:nth-child(1){transition-delay:.02s;}
  .pmsw.is-open .pmsw__item:nth-child(2){transition-delay:.06s;}
  .pmsw.is-open .pmsw__item:nth-child(3){transition-delay:.10s;}
  .pmsw.is-open .pmsw__item:nth-child(4){transition-delay:.14s;}
  .pmsw__item:hover{background:color-mix(in srgb, var(--sw) 10%, transparent);}
  .pmsw__item .pmsw__ic{
    width:30px;height:30px;flex:none;border-radius:9px;
    align-items:center;justify-content:center;
    background:var(--sw);color:#fff;
  }
  .pmsw__item .pmsw__ic svg{width:17px;height:17px;}
  /* the page you are on: marked, and not offering to take you where you are */
  .pmsw__item.is-current{
    background:color-mix(in srgb, var(--sw) 12%, transparent);
    pointer-events:none;
  }
  .pmsw__item.is-current .pmsw__name::after{
    content:'';display:inline-block;width:5px;height:5px;margin-left:8px;
    border-radius:50%;background:var(--sw);vertical-align:middle;
  }

  @media(max-width:700px){
    .pmsw{right:14px;bottom:14px;}
    .pmsw__toggle{width:48px;height:48px;}
    .pmsw__ic svg{width:21px;height:21px;}
    .pmsw__item{font-size:13.5px;padding:7px 12px 7px 7px;}
  }
  @media (prefers-reduced-motion:reduce){
    .pmsw__toggle,.pmsw__item,.pmsw__menu{transition:none;}
    .pmsw.is-open .pmsw__toggle{transform:none;}
    .pmsw.is-open .pmsw__toggle .pmsw__ic{transform:none;}
  }
