/* ================================================================
   Music Tuition Studio — the public website, in one stylesheet.

   AQUAMARINE AND GOLD. Every colour the site draws with is named
   here and nowhere else. A component says var(--marine), never a
   hex, so retuning the whole site means editing the block below
   and nothing else.

   This is deliberately NOT the app's palette. The studio app is
   "Engraved Warmth" (warm paper, carbon ink, fired clay, brushed
   gold) and lives in src/theme.css. Two systems, on purpose:
   the app is a working surface Adam stares at for four hours, the
   website is a shop window a parent sees once. See CLAUDE.md.

   ---------------------------------------------------------------
   THE RULES, learned by measuring rather than by eye. Break one
   and the page stops being legible somewhere you will not notice.

   1. AQUA IS THE GROUND, WHITE IS THE PLATE. The page is
      --page. White only appears where something must lift off it.
      Inverting this is what made the first draft read as plain.

   2. GOLD IS NEVER A WORD ON WHITE. --gold on white measures
      2.42 and fails. Readable gold is always --gold-ink.

   3. THE STONE IS NEVER A WORD. --stone measures 1.86 on white.
      It is a fill, a rule, a block. Never type.

   4. A GOLD RULE ON THE GROUND IS --gold-rule, NOT --gold.
      Bright gold on --page measures 2.06, under the 3.0 a divider
      needs to register at all. --gold-rule is 3.03 there and 3.56
      on white. It is only 2.64 on --band and 2.96 on --gold-wash,
      so a rule landing on either of those takes --gold-ink.

   5. EVERY INK WAS SOLVED AGAINST --band, the darkest light
      surface any text can land on — not against white. That is
      why they all work on all four surfaces. If you lighten one,
      re-check it against --band, not against --page.

   There is no black in this palette and no near-black. Body text
   is a cool slate in the stone's own hue family, which is most of
   why the page reads calm rather than corporate.
   ================================================================ */

:root {
  /* --- Surfaces ---------------------------------------------- */
  --page:        #DEF0F2;  /* the ground. The site is this colour */
  --plate:       #FFFFFF;  /* a card, lifted off the ground */
  --plate-2:     #EFF7F8;  /* an inset, or a second-rank card */
  --band:        #C3E4E8;  /* a deeper feature band */
  --stone:       #80CAD0;  /* the gem. A block or a rule, never type */
  --line:        #A9D8DD;  /* hairline on the ground. DECORATIVE RULES ONLY */
  /* A form control's edge is not decoration: SC 1.4.11 wants 3.0 from it, and
     --line is 1.43 against the field's own fill and 1.55 against the white card,
     so the inputs had essentially no boundary. This is the lightest colour on
     --line's own hue that clears 3.0 on the field fill (3.03) and the card (3.29). */
  --line-field:  #419AA4;
  --line-soft:   #D3EBEE;  /* hairline inside a white plate */

  /* --- Ink. All solved against --band, the worst case --------- */
  --ink:         #1F3943;  /* body text */
  --ink-muted:   #4C6672;  /* second-rank text, captions */
  --marine:      #165D6D;  /* headings and structure */
  --marine-deep: #134251;  /* the top bar, the footer, the big heading */
  --aqua-ink:    #1B6C76;  /* the ONE primary action, and links */

  /* --- Gold, six roles. One value cannot do all of them ------- */
  --gold:        #C9A227;  /* the metal: fills, badges, the mark */
  --gold-rule:   #A48420;  /* a divider on the ground (3.03) or white (3.56) */
  --gold-ink:    #765F17;  /* gold as readable words */
  --gold-lift:   #E3C877;  /* gold on a marine fill, and the button's hover */
  --gold-pale:   #F5E9C8;  /* small gold text on dark aqua */
  --gold-wash:   #F3EACD;  /* the one warm panel */

  /* --- Ink on a dark ground. These four were raw hex in components --------- */
  --on-dark:      #E7F4F6;  /* body ink on --marine / --marine-deep */
  --on-dark-soft: #9FC9D1;  /* fine print on --marine-deep */
  --line-dark:    #2A6274;  /* hairline on --marine-deep */

  /* --- Elevation, radii, motion ------------------------------- */
  --elev:      0 1px 2px #12414E14, 0 6px 20px #12414E1A;
  --elev-2:    0 2px 6px #12414E1A, 0 18px 44px #12414E26;
  --r-sm:      6px;
  --r:         12px;
  --r-pill:    999px;
  --ease:      cubic-bezier(0.2, 0, 0, 1);
  --dur:       180ms;

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

  /* --- Measure ------------------------------------------------ */
  --wrap: 1080px;
  /* The page's side margin. One value, so nothing can drift out of line with
     the rest of the page — which is exactly what happened when .hero .inner's
     `padding: 44px 0 52px` shorthand quietly reset .wrap's side padding to 0
     and threw the whole hero hard against the edge of the phone. Floors at
     22px so a small phone still breathes, opens out to 34px on a laptop. */
  --gutter: clamp(22px, 4vw, 34px);
  /* The sticky header's height, so scroll-padding-top cannot drift from it.
     Re-measure this if the brand mark's size changes: the mark is the tallest
     thing in the bar, so it sets the height. */
  --masthead: 96px;
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur: 0ms; }
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ================================================================
   Reset and base
   ================================================================ */

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

/* scroll-padding-top exists because .masthead is sticky. Without it, anything
   the browser scrolls to — a Shift+Tab back up the page, or the skip link
   landing on #main — comes to rest underneath the header and is invisible.
   That is WCAG 2.2 SC 2.4.11 Focus Not Obscured. */
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%;
       scroll-padding-top: calc(var(--masthead) + 12px); }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-ui);
  /* 1.0625rem, not 17px. An absolute px body size ignores a reader who has
     raised their browser's default font size, and every other size on the site
     is already rem against that root. 17/16 renders identically today. */
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { max-width: 100%; height: auto; display: block; }
/* The UA default is `margin: 1em 40px`. Left unreset, every photo on the site
   sat 40px inside the text beside it and read as a mistake. */
figure { margin: 0; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 400;
  text-wrap: balance;
  letter-spacing: 0.005em;
  color: var(--marine-deep);
  /* Headings carry their own bottom margin. Setting margin:0 here and relying on
     each block to add spacing meant any h1 outside .hero sat flush against the
     paragraph under it. */
  margin: 0 0 0.55em;
}
h1 { font-size: clamp(2.5rem, 6vw, 4rem); line-height: 1.03; }
h2 { font-size: clamp(1.9rem, 4vw, 2.7rem); line-height: 1.12; }
h3 { font-size: 1.4rem; line-height: 1.25; color: var(--marine); }
h4 { font-size: 1.16rem; line-height: 1.3; color: var(--marine); }

p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

a { color: var(--aqua-ink); text-underline-offset: 2px; text-decoration-thickness: 1px;
    transition: color var(--dur) var(--ease), text-decoration-color var(--dur) var(--ease),
                text-decoration-thickness var(--dur) var(--ease); }
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  outline: 3px solid var(--gold-rule);
  outline-offset: 2px;
}
/* An outline follows the element's own border-radius. Bare links and <summary>
   have none, so they need one here — but it has to carry ZERO specificity.
   Written plainly, `a:focus-visible` is (0,1,1) and beats `.btn` (0,1,0), so
   every button's corners snapped from 6px to 3px the instant it took keyboard
   focus and the ring was drawn to the wrong curve. `.skip` and `.nav-toggle`
   had the same problem, and the skip link is only ever seen while focused, so
   it was wrong 100% of the time it was visible. :where() drops this to (0,0,0),
   which lets anything declaring its own radius keep it. */
:where(a:focus-visible, button:focus-visible, input:focus-visible,
       select:focus-visible, textarea:focus-visible, summary:focus-visible) {
  border-radius: 3px;
}

strong { font-weight: 600; }
:where(ul, ol) { padding-left: 1.2em; }
li { margin-bottom: 0.4em; }

/* Screen-reader only, used for the skip link and form hints */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip {
  position: absolute; left: 8px; top: -60px; z-index: 100;
  background: var(--marine-deep); color: #FFFFFF; padding: 10px 18px;
  border-radius: var(--r-sm); font-size: 0.9rem; font-weight: 600;
  transition: top var(--dur) var(--ease);
}
.skip:focus { top: 8px; color: #FFFFFF; }

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

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 var(--gutter); }
.wrap-narrow { max-width: 760px; }

section { padding: 60px 0; }
@media (min-width: 760px) { section { padding: 76px 0; } }

.band     { background: var(--band); }
.plate-bg { background: var(--plate); }
.tint-bg  { background: var(--plate-2); }

.eyebrow {
  font-size: 0.72rem; font-weight: 600; letter-spacing: 0.17em;
  text-transform: uppercase; color: var(--gold-ink); margin: 0 0 14px;
}
.lede { font-size: 1.15rem; color: var(--ink-muted); max-width: 60ch; }
.measure { max-width: 64ch; }
.num { font-variant-numeric: tabular-nums; }

.grid { display: grid; gap: 22px; }
.g2 { grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); }
.g3 { grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); }

.card {
  background: var(--plate);
  border: 1px solid var(--line-soft);
  border-top: 2px solid var(--gold-rule);
  border-radius: var(--r);
  box-shadow: var(--elev);
  padding: 26px 26px 28px;
}
.card h3 { margin-bottom: 8px; }
.card p { color: var(--ink-muted); font-size: 0.97rem; }

/* A rule that carries the palette's whole ramp, gold at the end */
.keel { height: 4px; border: 0; margin: 0;
        background: linear-gradient(90deg, var(--marine-deep) 0%, var(--marine) 28%, var(--stone) 58%, var(--gold) 100%); }

/* ================================================================
   Buttons — exactly one primary colour on the whole site
   ================================================================ */

.btn {
  display: inline-block;
  font-family: var(--font-ui);
  font-size: 0.97rem;
  font-weight: 600;
  line-height: 1.2;
  padding: 14px 26px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
/* The one primary action on the site, in gold.
   Three things here are forced by measurement, not taste:
   - The text is --ink, not white. White on --gold is 2.42 and fails; --ink is
     5.03. Rule 2 in the header ("gold is never a word on white") is about gold
     TYPE; this is the inverse, ink on a gold fill, and it passes.
   - The border is --gold-ink, and it is what makes the button identifiable as
     a control. Bare --gold is 2.42 on white, 2.06 on --page and 1.80 on --band,
     all under the 3.0 that SC 1.4.11 wants from a component's edge. --gold-ink
     is 4.56 against the worst of them.
   - Hover goes LIGHTER, not darker. Darkening toward --gold-rule drops --ink to
     3.42 and fails; --gold-lift raises it to 7.42. The metal catches light. */
.btn-primary {
  background: var(--gold);
  color: var(--ink);
  border: 1px solid var(--gold-ink);
  border-bottom: 2px solid var(--gold-ink);
}
.btn-primary:active { transform: translateY(1px); }
/* THE RING IS NEVER MEASURED AGAINST THE BUTTON. `outline-offset: 2px` draws it
   entirely outside the border box with a 2px gap of bare surface inside it, so
   both of its neighbours are whatever the button is sitting on. An earlier
   version of this rule picked --marine-deep by measuring it against the gold
   fill (4.51) — a surface the ring is geometrically incapable of touching.
   On the light grounds --marine-deep is genuinely right: --page 9.27,
   --plate 10.90, --plate-2 10.04, --band 8.09, --gold-wash 9.07. */
.btn-primary:focus-visible { outline-color: var(--marine-deep); }
/* Inside a marine block the surface is --marine, where --marine-deep measures
   1.46 and disappears. This context has never had a conforming ring: the old
   global --gold-rule was 2.09 here. --gold-pale is 6.16, and light gold on dark
   aqua is exactly the role that token already exists for. */
.marine-block .btn-primary:focus-visible { outline-color: var(--gold-pale); }

/* THE SAME PROBLEM, FOR EVERY OTHER FOCUSABLE ON THE SITE.
   The global ring is --gold-rule, and outline-offset: 2px means it is painted
   on the section behind the element, not on the element. --gold-rule clears
   3.0 on --page (3.03), --plate (3.56), --plate-2 (3.28) and --marine-deep
   (3.06), so the ring is fine on most of the site. It is NOT fine on the other
   three grounds: 2.64 on --band, 2.96 on --gold-wash, 2.09 on --marine.
   That covers the suburb pills and the inline links in every .band section,
   the links inside .marine-block, and the tel/mailto links the enquiry form
   writes into .form-status when sending fails — which is the one path a lead
   hits when the form is broken.
   A global swap is not available: --gold-ink is 1.78 on --marine-deep and
   would break the topbar and every footer link. So each ground takes the token
   that was made for it. */
.band :focus-visible,
.note :focus-visible,
.form-status :focus-visible { outline-color: var(--gold-ink); }   /* 4.56 / 5.11 */
.marine-block :focus-visible { outline-color: var(--gold-pale); } /* 6.16 */

.btn-ghost {
  background: transparent;
  color: var(--marine-deep);
  border: 1px solid var(--marine);
}
/* This used to set background to --plate and colour to --marine-deep, which is
   already the resting colour. On any .plate-bg section — including the one
   holding the "Call or text" button on /book — the section is already --plate,
   so transparent composited to exactly the same white and the hover was a
   zero-pixel no-op. The outline now fills in instead, which is unmistakable on
   every ground: --marine is 7.45 against --plate and 6.33 against --page, and
   white on it is 7.45. */

.cta-row { display: flex; flex-wrap: wrap; gap: 14px 18px; align-items: center; }
.cta-row .aside { font-size: 0.94rem; color: var(--ink-muted); }

/* ================================================================
   Top contact bar and navigation
   ================================================================ */

.topbar {
  background: var(--marine-deep);
  color: #FFFFFF;
  font-size: 0.82rem;
}
.topbar .wrap {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 4px 22px; padding-top: 9px; padding-bottom: 9px;
}
.topbar a { color: #FFFFFF; text-decoration: none; font-weight: 600;
            transition: color var(--dur) var(--ease); }
.topbar .where { color: var(--band); }
@media (min-width: 700px) { .topbar .where { margin-left: auto; } }

.masthead {
  background: var(--plate);
  border-bottom: 2px solid var(--gold-rule);
  position: sticky; top: 0; z-index: 40;
}
.masthead .wrap {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 12px 22px; padding-top: 14px; padding-bottom: 14px;
}

.brand { display: flex; align-items: center; gap: 12px; text-decoration: none; flex: 0 0 auto;
         transition: opacity var(--dur) var(--ease); }
/* The mark. Sized here rather than only on the <img> so there is one number to
   change, with the width/height attributes on the element kept in step to
   reserve the space before the file loads. It carries no MTS lettering: the
   words are set immediately to its right, and saying it twice at 46px produced
   an illegible smudge repeating what the type already said. */
.brand img { flex: 0 0 auto; width: 64px; height: 64px; }
/* 380, not 400. A 64px mark still fits alongside the wordmark and the Menu
   button at 390px, which is the width of most current iPhones, so it keeps the
   full size there. Below that it does not fit, and a masthead that wraps to two
   rows is a sticky bar eating a fifth of a small phone's screen. */
@media (max-width: 380px) { .brand img { width: 52px; height: 52px; } }

.brand .wm {
  font-family: var(--font-display);
  /* Scales with the viewport rather than stepping at a breakpoint. The masthead
     is the tightest row on the site: at 390px there are only 346px of content
     width, and the wordmark at its full 1.3rem takes 183px of it. Add the mark
     and the Menu button and it overflows, wrapping the button onto its own line
     and making the sticky header 143px tall. The floor keeps it readable, the
     ceiling is the size it was designed at. */
  font-size: clamp(1rem, 4.3vw, 1.3rem); line-height: 1.05;
  font-weight: 700;
  color: var(--marine); letter-spacing: 0.02em;
}
.brand .wm span { display: block; font-size: 0.6rem; font-family: var(--font-ui);
                  letter-spacing: 0.19em; text-transform: uppercase; color: var(--ink-muted); }

/* Reclaiming the masthead row on a phone. Measured at 360px: the brand, the gap
   and the Menu button came to 326.6px against 316px of content width, so the
   button wrapped and the sticky header went from 94px to 131px.
   The culprit is not the name. "Music Tuition Studio" sets at 141px; the
   LONG BAY / AUCKLAND line under it sets at 146px, because 0.19em of tracking
   across nineteen characters adds about 35px on its own. That line is what
   sets the width of the whole brand block, so that line is what has to give.
   These rules must sit AFTER the ones they override: a media query adds no
   specificity, so an identical selector earlier in the file simply wins. */
@media (max-width: 420px) {
  .brand { gap: 8px; }
  .brand .wm span { letter-spacing: 0.08em; }
}

.nav-toggle {
  margin-left: auto; display: inline-flex; align-items: center; gap: 8px;
  background: var(--plate-2); border: 1px solid var(--line);
  color: var(--marine-deep); font-family: var(--font-ui); font-weight: 600;
  font-size: 0.88rem; padding: 9px 14px; border-radius: var(--r-sm); cursor: pointer;
}
/* 899.98, not 899. These are the only paired max/min breakpoints in the file and
   at 899px they left a hole: a width strictly between 899 and 900 — routine under
   browser zoom, a 989px window at 110% resolves to 899.09 — matched neither, so
   the Menu button and the full horizontal nav both rendered and Menu did nothing. */
@media (min-width: 900px) { .nav-toggle { display: none; } }
/* Same row, same reason as the .brand rules above, and it has to live down here
   rather than with them: the base .nav-toggle rule is further down the file than
   the brand block, and a media query adds no specificity, so an override written
   up there loses to it silently. That is exactly what happened first time. */
@media (max-width: 420px) { .nav-toggle { padding: 9px 11px; gap: 6px; } }

nav.main { width: 100%; }
@media (min-width: 900px) { nav.main { width: auto; margin-left: auto; } }

nav.main ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 22px;
}
@media (max-width: 899.98px) {
  nav.main { display: none; padding: 6px 0 10px; }
  nav.main.open { display: block; }
  nav.main ul { flex-direction: column; align-items: stretch; gap: 0; }
  nav.main li { margin: 0; border-top: 1px solid var(--line-soft); }
  nav.main a { display: block; padding: 12px 2px; }
  nav.main li.cta { border-top: none; padding-top: 12px; }
  /* In the open mobile menu `nav.main a { display: block }` stretches the CTA to
     the full width of the panel. Its label inherits text-align: start and sits
     hard against the left edge, which read as an accident the moment the fill
     went gold and the button became visible at all. */
  nav.main .btn { text-align: center; }
}
/* :not(.btn) matters. `nav.main a` is (0,1,2) and beats `.btn-primary` (0,1,0),
   so without it this rule repainted the Book a lesson CTA --ink on --aqua-ink:
   2.00 to 1, effectively unreadable, on every page of the site. */
nav.main a:not(.btn) {
  color: var(--ink); text-decoration: none; font-size: 0.96rem; font-weight: 500;
  transition: color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
nav.main a[aria-current="page"] {
  color: var(--marine-deep); font-weight: 600;
  box-shadow: inset 0 -2px 0 0 var(--gold);
}
@media (max-width: 899.98px) {
  nav.main a[aria-current="page"] { box-shadow: inset 3px 0 0 0 var(--gold); padding-left: 12px; }
}
nav.main .btn { padding: 10px 20px; font-size: 0.9rem; }

/* ================================================================
   Hero
   ================================================================ */

/* .hero is a <section>, so it would otherwise pick up section's 60/76px padding
   on top of .inner's own — about 104px of empty ground above the eyebrow on a
   phone. The inner element owns the hero's spacing. */
.hero { background: var(--page); padding: 0; }
.hero .inner {
  display: grid; gap: 34px; align-items: center;
  /* padding-block, NOT the `padding: 44px 0 52px` shorthand this used to be.
     .hero .inner is (0,2,0) and beats .wrap (0,1,0), so that middle 0 was
     wiping the page gutter and only here — the hero ran edge to edge on a
     phone while every other section kept its margin. */
  padding-block: 44px 52px;
}
@media (min-width: 860px) {
  .hero .inner { grid-template-columns: 1.05fr 1fr; gap: 52px; padding-block: 64px 72px; }
}
.hero h1 { margin-bottom: 18px; }
.hero h1 em { font-style: italic; color: var(--marine); }
.hero .lede { margin-bottom: 26px; }
.hero-photo {
  border-radius: var(--r);
  overflow: hidden;
  box-shadow: var(--elev-2);
  border: 1px solid var(--line);
  background: var(--band);
}
.hero-photo img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }

.facts { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 30px; padding: 0; list-style: none; }
.facts li {
  margin: 0; font-size: 0.86rem;
  background: var(--plate); border: 1px solid var(--line);
  color: var(--ink); padding: 7px 15px; border-radius: var(--r-pill);
}
.facts b { color: var(--marine); font-weight: 600; }

/* The four demo pieces on the Grace Note page. A list, not a grid of cards:
   the useful thing about each one is the sentence saying who it suits, and a
   card layout would squeeze that to two lines and a truncation. */
.demos { list-style: none; padding: 0; margin: 26px 0 18px; display: grid; gap: 2px; }
.demos li {
  background: var(--plate); border: 1px solid var(--line); border-radius: var(--r-md, 8px);
  padding: 14px 18px; margin: 0; display: grid; gap: 3px;
}
.demos li + li { margin-top: 8px; }
.demos a { text-decoration: none; }
.demos a strong { font-family: var(--font-display, Georgia, serif); font-size: 1.14rem; color: var(--marine); }
.demos a:hover strong, .demos a:focus strong { text-decoration: underline; }
.demos span { color: var(--ink-muted); font-size: 0.93rem; }
.small { font-size: 0.88rem; color: var(--ink-muted); }

/* ================================================================
   Content blocks
   ================================================================ */

.split { display: grid; gap: 30px; align-items: start; }
@media (min-width: 820px) { .split { grid-template-columns: 1fr 1fr; gap: 46px; } }
.split.photo-right img,
.split.photo-left img { border-radius: var(--r); box-shadow: var(--elev); border: 1px solid var(--line); }
@media (min-width: 820px) { .split.photo-left .text { order: 2; } }

.figure { border-radius: var(--r); overflow: hidden; box-shadow: var(--elev); border: 1px solid var(--line); }
.figure img { width: 100%; object-fit: cover; }
.figure figcaption {
  background: var(--plate); color: var(--ink-muted);
  font-size: 0.85rem; padding: 12px 16px; margin: 0;
  border-top: 1px solid var(--line-soft);
}

.checklist { list-style: none; padding: 0; margin: 0; }
.checklist li {
  position: relative; padding-left: 30px; margin-bottom: 12px; color: var(--ink-muted);
}
.checklist li::before {
  content: ""; position: absolute; left: 4px; top: 0.55em;
  width: 9px; height: 9px; background: var(--stone);
  box-shadow: 0 0 0 1.5px var(--gold-rule); transform: rotate(45deg);
}

/* The one warm panel per page */
.note {
  background: var(--gold-wash);
  border-left: 3px solid var(--gold);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  padding: 18px 22px;
  color: var(--ink);
}

/* A flat marine block — the one saturated moment */
.marine-block {
  background: var(--marine);
  border-radius: var(--r);
  border-top: 3px solid var(--gold);
  padding: 30px 28px;
  color: var(--on-dark);
  box-shadow: var(--elev-2);
}
/* Without this the block's running text sets at ~107 characters on a wide
   screen, against 64 everywhere else on the site. */
.marine-block p { max-width: 64ch; }
.marine-block h2, .marine-block h3 { color: #FFFFFF; }
.marine-block .eyebrow { color: var(--gold-lift); }
/* Same trap, worse outcome. `.marine-block a` is (0,2,0) and also beats
   `.btn-primary`, so the CTA inside a marine block was rendering --gold-lift on
   the button's own fill. On the old aqua fill that was 3.71; on the gold fill it
   would have been 1.47, gold on gold. */
.marine-block a:not(.btn) { color: var(--gold-lift); }
.marine-block strong { color: #FFFFFF; }

.price {
  font-family: var(--font-display);
  font-size: 2.6rem; line-height: 1; color: var(--marine-deep);
  font-variant-numeric: tabular-nums;
}
.price small { font-family: var(--font-ui); font-size: 0.92rem; color: var(--ink-muted); display: block; margin-top: 6px; font-variant-numeric: normal; }

/* Suburb links */
.suburbs { display: flex; flex-wrap: wrap; gap: 10px; padding: 0; list-style: none; margin: 22px 0 0; }
.suburbs li { margin: 0; }
.suburbs a {
  display: inline-block; background: var(--plate); border: 1px solid var(--line);
  border-radius: var(--r-pill); padding: 8px 17px; font-size: 0.92rem;
  text-decoration: none; color: var(--marine-deep); font-weight: 500;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), transform var(--dur) var(--ease);
}

/* Testimonial */
blockquote.quote {
  margin: 0; padding: 0; border: 0;
}
blockquote.quote p {
  font-family: var(--font-display); font-size: clamp(1.4rem, 3vw, 1.9rem);
  line-height: 1.32; color: var(--marine-deep); margin-bottom: 14px;
}
blockquote.quote cite {
  font-style: normal; font-size: 0.9rem; color: var(--ink-muted);
  font-family: var(--font-ui);
}

/* A quote sitting in a grid of three rather than alone and centred. The solo
   testimonial runs up to 1.9rem, which is right when it is the only thing on
   the screen and far too loud three abreast. Same component, smaller voice. */
blockquote.quote.quote-sm p { font-size: clamp(1.05rem, 1.6vw, 1.22rem); line-height: 1.45; }

/* The source line under a review. --ink-muted is 5.6:1 on the white plate and
   6.0:1 on --page, so it stays readable on both grounds the cards sit on. */
.quote-source { display: block; margin-top: 2px; color: var(--ink-muted); font-size: 0.85rem; }

/* ================================================================
   Forms
   ================================================================ */

.form-card {
  background: var(--plate);
  border: 1px solid var(--line-soft);
  border-top: 3px solid var(--gold-rule);
  border-radius: var(--r);
  box-shadow: var(--elev-2);
  padding: 28px 24px 30px;
}
@media (min-width: 620px) { .form-card { padding: 32px 32px 34px; } }

.field { margin-bottom: 18px; }
.field label {
  display: block; font-size: 0.88rem; font-weight: 600;
  color: var(--marine-deep); margin-bottom: 6px;
}
.field .hint { font-weight: 400; color: var(--ink-muted); }
.field input,
.field select,
.field textarea {
  width: 100%;
  font-family: var(--font-ui);
  font-size: 1rem;
  color: var(--ink);
  background: var(--plate-2);
  border: 1px solid var(--line-field);
  border-radius: var(--r-sm);
  padding: 12px 14px;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
/* Safari draws its own rounded, grey-gradient select and ignores the border,
   the radius and the fill above, so the four dropdowns on /book looked like a
   different form from the inputs beside them. Turning the native control off
   means drawing the arrow, which is the two gradients below. */
.field select {
  appearance: none; -webkit-appearance: none;
  padding-right: 38px;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--marine) 50%),
    linear-gradient(135deg, var(--marine) 50%, transparent 50%);
  background-position: right 18px center, right 13px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.field select { text-overflow: ellipsis; }
.field textarea { min-height: 120px; resize: vertical; }
/* Two fields side by side.
   minmax(0, 1fr) rather than 1fr: a bare 1fr floors at the item's min-content,
   and "Straight after school, 3:15 to 4:30pm" gives that select a 237px floor.
   The moment the form is narrower than about 500px that floor wins and the two
   columns stop being the same width.
   The flex column is what levels the controls. The grid already makes both
   fields the same height; letting the label absorb the slack drops both controls
   onto the same line even when one label wraps and the other does not. Without
   it, "Preferred time 3:15pm to 7:30pm" wraps to two lines and its select sits
   23.2px below "Preferred day". */
.field-row { display: grid; gap: 0 18px; }
@media (min-width: 620px) {
  .field-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .field-row > .field { display: flex; flex-direction: column; }
  .field-row > .field > label { flex: 1 0 auto; }
}

/* NEVER display:none. This is the form's aria-live region, and a live region
   that is display:none is not in the accessibility tree: making it visible and
   filling it in the same tick means many screen readers announce nothing at
   all. So the element stays rendered at all times and collapses to nothing
   while it is empty, which leaves the announcement to a pure text change —
   the one mutation live regions are reliable about.
   :empty is exact here, because form.js only ever writes markup or "". */
.form-status {
  margin-top: 18px; padding: 14px 18px; border-radius: var(--r-sm);
  font-size: 0.94rem; display: block;
}
.form-status:empty { margin: 0; padding: 0; }
/* .show is kept so existing markup and any cached form.js still behave. */
.form-status.show { display: block; }
.form-status.ok   { background: var(--band); border-left: 3px solid var(--marine); color: var(--ink); }
.form-status.bad  { background: var(--gold-wash); border-left: 3px solid var(--gold-rule); color: var(--ink); }

/* Placeholder text. There was NO ::placeholder rule anywhere in this stylesheet,
   so every browser fell back to its own default — Chrome and Safari use roughly
   #757575-on-white (about 4.6:1, marginal) and some fall well below it. The
   textarea on /book is the only placeholder on the site and it carries real
   instructions, so it gets a token that is measured: --ink-muted is #4C6672,
   which is 6.4:1 on the white field. Placeholders are never the only label
   here; every field has a real <label>. */
.field input::placeholder,
.field textarea::placeholder { color: var(--ink-muted); opacity: 1; }

/* The honeypot. Never shown, never focusable by keyboard. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ================================================================
   Footer
   ================================================================ */

footer.site {
  background: var(--marine-deep);
  color: var(--band);
  padding: 48px 0 34px;
  margin-top: 0;
  border-top: 3px solid var(--gold-rule);
}
footer.site h2 { color: #FFFFFF; font-size: 1.5rem; margin-bottom: 14px; }
footer.site a { color: #FFFFFF; transition: color var(--dur) var(--ease),
                                            text-decoration-thickness var(--dur) var(--ease); }
footer.site .cols { display: grid; gap: 30px; }
@media (min-width: 720px) { footer.site .cols { grid-template-columns: 1.4fr 1fr 1fr; gap: 40px; } }
footer.site .label {
  font-size: 0.7rem; letter-spacing: 0.17em; text-transform: uppercase;
  color: var(--gold-lift); margin: 0 0 12px; font-weight: 600;
}
footer.site ul { list-style: none; padding: 0; margin: 0; }
footer.site li { margin-bottom: 8px; font-size: 0.94rem; }
footer.site .fine {
  margin-top: 34px; padding-top: 20px; border-top: 1px solid var(--line-dark);
  font-size: 0.82rem; color: var(--on-dark-soft);
  display: flex; flex-wrap: wrap; gap: 6px 20px;
}
footer.site address { font-style: normal; font-size: 0.94rem; line-height: 1.7; }

/* ================================================================
   Interaction — every hover state on the site, gathered in one place

   WHY THEY ARE ALL INSIDE @media (hover: hover).
   A touch screen has no pointer to move away. Tap a link on a phone and it
   keeps its :hover style until something else is tapped, so the last thing
   you touched sits there lit up as though a cursor were still on it. Gating
   the whole set on a real pointer means a phone gets the resting style and
   the :active press instead, which is the feedback that actually belongs to
   touch.

   :active and :focus-visible are deliberately NOT in here. A press is real on
   touch, and a keyboard user on a touch device still needs a focus ring.

   ORDER IS LOAD-BEARING. Every rule below is written to beat the resting rule
   it overrides and to lose to the more specific hover further down: the
   generic a:hover is first, and .topbar / footer / .suburbs / .marine-block
   follow it because each needs to win on its own ground.
   ================================================================ */

@media (hover: hover) and (pointer: fine) {

  /* Body links thicken rather than only shifting colour. A colour-only hover
     is invisible to anyone who cannot separate the two hues. */
  /* :not(.skip) matters. The skip link is white on --marine-deep; the generic
     rule below repainted it --marine-deep on --marine-deep, so the one control
     a keyboard user meets first vanished the moment a pointer crossed it. */
  a:not(.btn):not(.skip):hover { color: var(--marine-deep); text-decoration-thickness: 2px; }
  .skip:hover { background: var(--marine); color: #FFFFFF; }

  .btn-primary:hover { background: var(--gold-lift); color: var(--ink); }
  /* The outline fills in. This used to set the fill to --plate, which on a
     .plate-bg section was the colour already behind it — a zero-pixel no-op. */
  .btn-ghost:hover  { background: var(--marine); color: #FFFFFF; border-color: var(--marine); }

  .brand:hover { opacity: 0.78; }

  .topbar a:hover { color: var(--gold-pale); text-decoration: underline; }

  /* Hover underlines the item in stone; the current page is underlined in
     gold. The second rule exists because the hover selector is (0,3,2) and
     would otherwise strip the gold marker off the page you are already on. */
  nav.main a:not(.btn):hover { color: var(--marine-deep); box-shadow: inset 0 -2px 0 0 var(--stone); }
  nav.main a[aria-current="page"]:hover { box-shadow: inset 0 -2px 0 0 var(--gold); }

  .suburbs a:hover { background: var(--band); border-color: var(--stone); color: var(--marine-deep); }

  /* --marine, NOT --stone. Stone measures 1.86:1 on white, so hovering a field
     used to DROP its border from 3.03:1 to below the 3:1 minimum for a UI
     boundary — the control got harder to see the moment you pointed at it, and
     it quietly undid the resting-border fix. A hover must darken here, never
     lighten: the stone is a fill colour, never an edge that has to be seen. */
  .field input:hover, .field select:hover, .field textarea:hover { border-color: var(--marine); }

  footer.site a:hover { color: var(--gold-pale); text-decoration-thickness: 2px; }

  /* .marine-block a:not(.btn) is (0,3,0) and outranks the generic a:hover
     (0,2,1), so without this the links in the saturated block are the only
     ones on the site with no hover feedback at all. */
  .marine-block a:not(.btn):hover { color: var(--gold-pale); text-decoration-thickness: 2px; }
}

/* The press. This one belongs on touch as much as on a mouse, so it stays
   outside the block above. */
.btn-ghost:active  { transform: translateY(1px); }
.suburbs a:active  { transform: translateY(1px); background: var(--band); }
