/* ==========================================================================
   Gr8tStep — Gina Riley
   Counselling · Coaching · Physical Wellbeing
   ========================================================================== */

/* Bethany Elingston — Attract Studio, commercially licensed for Gr8tStep.
   TODO: convert to woff2 for production; .otf is fine for preview. */
@font-face {
  font-family: "Bethany Elingston";
  src: url("../fonts/Bethany Elingston.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  --serif: "Cormorant Garamond", "Times New Roman", serif;
  --display: "Bethany Elingston", "Cormorant Garamond", Georgia, serif;
  --sans: "Jost", "Century Gothic", "Futura", sans-serif;
  /* Used only by the password gate below — never mixed into the site's own
     three-family system. */
  --gate-sans: "Space Grotesk", "Century Gothic", sans-serif;
}

/* --------------------------------------------------------------------------
   Palette.
   Colours are referenced by role, never by hue, so the palette is a single
   block below.

   Two roles carry solid colour and they are deliberately separate:
     --accent / --on-accent   small moments (announce strip, nav, buttons)
     --band   / --on-band     large full-bleed fields (the values band)
   A bright mid-tone can work at accent scale and still be wrong across a
   1000px-tall block, so those are free to be set to different colours.
   -------------------------------------------------------------------------- */

/* The announce strip and both footer bands carry the aurora mesh: five soft
   radial blobs (lilac, peach, pastel aqua, pastel green, pastel blue) over a
   base sweep, plus a film-grain overlay.
   Every blob fades to a transparent version of its OWN colour rather than
   `transparent` (= rgba(0,0,0,0)), which would drag a grey cast through the
   blend. All stops are pale enough that --ink clears 4.5:1 across the whole
   mesh (worst case, the lilac, is 7.98:1) — --ink-soft does NOT clear it
   (down to 4.01:1), so aurora surfaces use --on-aurora: var(--ink) instead. */
:root {
  --surface: #f7f5f1;
  --surface-2: #f7f3ef;
  --ink: #14434c;
  --ink-soft: #45707a;
  --accent: #2a7885;
  --accent-bright: #48a5b5;
  --on-accent: #ffffff;
  --announce: #bec9d3;
  --on-announce: #14434c;
  --nav-active: #84b868;
  --on-nav-active: #14434c;
  --aurora:
    radial-gradient(70% 180% at 8% 30%,  #e3d9f0 0%, rgba(227, 217, 240, 0) 60%),
    radial-gradient(60% 170% at 32% 85%, #f7e0cd 0%, rgba(247, 224, 205, 0) 62%),
    radial-gradient(65% 175% at 55% 12%, #c9e7ea 0%, rgba(201, 231, 234, 0) 60%),
    radial-gradient(70% 180% at 78% 80%, #d8edc3 0%, rgba(216, 237, 195, 0) 62%),
    radial-gradient(60% 170% at 96% 25%, #d7e2ec 0%, rgba(215, 226, 236, 0) 60%),
    linear-gradient(92deg, #dfe9ee 0%, #ece2f0 48%, #f5e8da 100%);
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.62' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)' opacity='0.85'/%3E%3C/svg%3E");
  --on-aurora: var(--ink);
  --band: #14434c;
  --on-band: #ffffff;
  --cool: #bec9d3;
  --green: #84b868;
  --green-ink: #3f7a2a;
  --line: rgba(20, 67, 76, 0.6);
  --line-soft: rgba(20, 67, 76, 0.18);
  --ph-1: #e4edee;
  --ph-2: #d6e2e6;
  --ph-3: #bec9d3;
  --ph-grid: rgba(20, 67, 76, 0.06);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  font-family: var(--sans);
  font-weight: 300;
  background: var(--surface);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }

a { color: inherit; text-decoration: none; }

/* Links sitting INSIDE a run of body copy, as opposed to the nav items,
   cards and buttons the rule above is written for. Those all carry their own
   affordance (a box, a border, a hover fill); a link mid-sentence has none,
   so stripping the underline there would leave it indistinguishable from the
   text around it. Underlined rather than recoloured because --ink-soft body
   copy has nowhere contrasty left to go, and colour alone is not a reliable
   signal anyway. The hairline weight matches the borders used elsewhere. */
.pillar p a,
.about-copy p a,
.treatment-copy p a {
  text-decoration: underline;
  text-decoration-color: var(--line-soft);
  text-underline-offset: 0.22em;
  transition: text-decoration-color 200ms ease-out;
}

.pillar p a:hover,
.about-copy p a:hover,
.treatment-copy p a:hover { text-decoration-color: var(--line); }

/* Bethany Elingston has no italic, so emphasis spans fall back to the
   Cormorant italic explicitly (see .hero-panel h1 em). */
h1, h2, h3 {
  font-family: var(--display);
  font-weight: 400;
  letter-spacing: 0.01em;
  text-transform: none;
  line-height: 1.3;
}


.eyebrow {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 400;
}

/* ---------- announcement bar ---------- */

/* Links to the Book page. display:block because it is an <a> — without it the
   bar collapses to inline and loses its full-width padding. */
/* Sticks to the top of the viewport on scroll. It is the only sticky element
   on the page, so z-index just has to clear ordinary content — the intro
   drop-in below raises it further for the moment it overshoots past the
   header. The background-color is not optional here: once it detaches it has
   page content running underneath it, and the aurora gradient alone does not
   cover in every palette. */
.announce {
  display: block;
  position: sticky;
  top: 0;
  z-index: 20;
  background-color: var(--announce, var(--accent));
  background-image: var(--aurora, none);
  color: var(--on-announce, var(--on-accent));
  text-align: center;
  border-bottom: 1px solid var(--line);
  padding: 12px 20px;
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 400;
}

.announce .arrow {
  display: inline-block;
  margin-left: 18px;
  letter-spacing: 0;
  transition: transform 200ms ease-out;
}

/* The bar carries no underline or button styling, so the arrow moving is the
   main signal that the whole strip is clickable. */
.announce:hover .arrow { transform: translateX(5px); }

/* ---------- header ---------- */

.site-header {
  border-bottom: 1px solid var(--line);
}

.header-grid {
  display: grid;
  grid-template-columns: 1fr minmax(auto, 500px) 1fr;
  align-items: stretch;
}

.header-cell {
  padding: 40px 30px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  font-size: 10px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--ink-soft);
}

.header-cell.left { align-items: flex-end; text-align: right; }
.header-cell.right { align-items: flex-start; }

.brand {
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 30px 40px;
  text-align: center;
}

.brand a {
  display: block;
}

/* Logo mark, painted via mask so it follows the palette like the other
   line-art icons (see .value-cell .icon). Source is a flattened PNG with no
   alpha channel; alpha was reconstructed from luminance, so it works as a
   mask even though it isn't vector. */
.brand-mark {
  display: block;
  width: clamp(48px, 4.4vw, 64px);
  aspect-ratio: 892 / 903;
  background-color: var(--ink);
  -webkit-mask: url("../img/logo-mark.png") center / contain no-repeat;
  mask: url("../img/logo-mark.png") center / contain no-repeat;
}

/* ---------- nav ---------- */

.site-nav {
  border-bottom: 1px solid var(--line);
  display: flex;
  justify-content: center;
}

.site-nav ul {
  list-style: none;
  display: flex;
  border-left: 1px solid var(--line);
}

.site-nav li { border-right: 1px solid var(--line); }

.site-nav a {
  display: block;
  padding: 14px 24px;
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--ink-soft);
  transition: background 0.25s, color 0.25s;
  white-space: nowrap;
}

.site-nav a:hover,
.site-nav a.active {
  background: var(--nav-active, var(--accent));
  color: var(--on-nav-active, var(--on-accent));
}

/* Each nav item gets its own hue on hover/current instead of one shared
   colour — matched to the aurora's palette family (green, blue, aqua, peach,
   lilac, rose). Every one is checked at 4.5:1+ against --ink (all land
   between 4.67 and 6.41), so the dark-ink-on-light-pastel pairing used
   elsewhere holds here too. */
/* Grain over the flat nav colours too, so the solid swatches match the
   texture of the gradient surfaces rather than looking flat beside them.
   The overlay only paints while the button is coloured (hover/current). */
[data-theme="lagoon"] .site-nav a,
[data-theme="lagoon"] .footer-nav a { position: relative; }

[data-theme="lagoon"] .site-nav a::after,
[data-theme="lagoon"] .footer-nav a::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  background-image: var(--grain);
  mix-blend-mode: overlay;
  transition: opacity 200ms ease-out;
}

[data-theme="lagoon"] .site-nav a:hover::after,
[data-theme="lagoon"] .site-nav a.active::after,
[data-theme="lagoon"] .footer-nav a:hover::after {
  opacity: 0.7;
}

[data-theme="lagoon"] .site-nav li:nth-child(1) a:hover,
[data-theme="lagoon"] .site-nav li:nth-child(1) a.active { background: #84b868; color: var(--ink); }

[data-theme="lagoon"] .site-nav li:nth-child(2) a:hover,
[data-theme="lagoon"] .site-nav li:nth-child(2) a.active { background: #a2c1dd; color: var(--ink); }

[data-theme="lagoon"] .site-nav li:nth-child(3) a:hover,
[data-theme="lagoon"] .site-nav li:nth-child(3) a.active { background: #8ad3db; color: var(--ink); }

[data-theme="lagoon"] .site-nav li:nth-child(4) a:hover,
[data-theme="lagoon"] .site-nav li:nth-child(4) a.active { background: #fbae6f; color: var(--ink); }

[data-theme="lagoon"] .site-nav li:nth-child(5) a:hover,
[data-theme="lagoon"] .site-nav li:nth-child(5) a.active { background: #bea0e5; color: var(--ink); }

[data-theme="lagoon"] .site-nav li:nth-child(6) a:hover,
[data-theme="lagoon"] .site-nav li:nth-child(6) a.active { background: #e6a6bc; color: var(--ink); }

/* ---------- boxed grid sections ---------- */

.rail-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(auto, 1030px) minmax(0, 1fr);
}

.rail-grid > .rail { border-bottom: 1px solid var(--line); }

.rail-grid > .well {
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}

/* ---------- hero ---------- */

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(auto, 760px) minmax(0, 1fr);
  min-height: 640px;
  border-bottom: 1px solid var(--line);
}

.hero .hero-img {
  overflow: hidden;
}

/* <picture> is inline with auto height by default, which would break the
   img's height:100% below — same fix as .about-media. */
.hero .hero-img picture { display: block; height: 100%; }

.hero .hero-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero-panel {
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  background: var(--surface-2);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 40px;
  text-align: center;
  padding: 90px 60px;
}

.hero-panel h1 {
  font-size: clamp(30px, 4.4vw, 46px);
  line-height: 1.15;
}

.hero-panel h1 em {
  font-family: var(--serif);
  font-style: italic;
  text-transform: none;
  letter-spacing: 0.06em;
}

/* Line-art SVGs are painted via mask so they follow the palette rather than
   carrying a baked-in stroke colour. */
.hero-panel .sun {
  width: 84px;
  height: 70px;
  opacity: 0.9;
  --icon: url("../img/mark.svg");
  background-color: var(--ink);
  -webkit-mask: var(--icon) center / contain no-repeat;
  mask: var(--icon) center / contain no-repeat;
}

.hero-panel p {
  max-width: 380px;
  font-size: 14px;
  color: var(--ink-soft);
}

/* ---------- section title band ---------- */

.title-band .well {
  padding: 80px 40px;
  text-align: center;
}

.title-band h2 { font-size: clamp(20px, 2vw, 26px); }

.title-band .eyebrow { margin-bottom: 16px; color: var(--ink-soft); }

.title-band .card-link {
  display: inline-block;
  margin-top: 22px;
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--line);
  padding-bottom: 4px;
}

/* ---------- services grid (home) ---------- */

.services-inner {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

.service-card {
  border-right: 1px solid var(--line);
  border-top: 1px solid var(--line);
  padding: 54px 34px 60px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  background: var(--surface);
  transition: background 0.3s;
}

.service-card:nth-child(4n) { border-right: none; }
.service-card:nth-child(-n + 4) { border-top: none; }

.service-card:hover { background: var(--surface-2); }

.service-card h3 {
  font-size: 17px;
  min-height: 2.6em;
  display: flex;
  align-items: flex-end;
}

.service-card p {
  font-size: 13px;
  color: var(--ink-soft);
  flex: 1;
  transition: color 320ms ease-out;
}

.service-card .card-link {
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 400;
  border-bottom: 1px solid var(--line);
  align-self: flex-start;
  padding-bottom: 4px;
}

/* ---------- my approach (home) ---------- */

.approach .well {
  display: grid;
  grid-template-columns: 1fr 1fr;
  background: var(--surface);
}

.approach-copy {
  padding: 90px 64px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 22px;
}

.approach-copy h2 { font-size: clamp(20px, 2vw, 26px); }

.approach-copy p { color: var(--ink-soft); }

.approach-copy .card-link { align-self: flex-start; border-bottom: 1px solid var(--line); padding-bottom: 4px; font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase; }

.approach-badges {
  border-left: 1px solid var(--line);
  padding: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
}

.approach-badges .venn {
  width: 100%;
  max-width: 380px;
  overflow: visible;
  pointer-events: auto;
}

/* Hit-testing is done geometrically in js/venn.js against the circles' live
   positions, not by CSS :hover. Letting the shapes take pointer events would
   mean the topmost circle swallows every hover in the overlap regions, so
   only the last-drawn circle would ever respond in the middle. */
.approach-badges .venn * { pointer-events: none; }

/* One hue per overlap rather than a single flat tint — the three lenses
   multiply into a deeper shared centre where all three disciplines meet. */
.approach-badges .venn-overlap {
  fill-opacity: 0.42;
  mix-blend-mode: multiply;
  transition: fill-opacity 220ms ease-out;
}

.approach-badges .venn-overlap.lens-a { fill: var(--cool); }
.approach-badges .venn-overlap.lens-b { fill: var(--green); }
.approach-badges .venn-overlap.lens-c { fill: var(--accent-bright); }

/* Pink / green / blue, matching the hues already used for the nav and the
   aurora rather than inventing a new set. */
[data-theme="lagoon"] .approach-badges .venn-overlap.lens-a { fill: #a2c1dd; }
[data-theme="lagoon"] .approach-badges .venn-overlap.lens-b { fill: #84b868; }
[data-theme="lagoon"] .approach-badges .venn-overlap.lens-c { fill: #e6a6bc; }

/* Motion is driven by js/venn.js writing cx/cy/r straight onto the geometry,
   because every circle exists three times over — as an outline, as a clip
   shape, and as a lens fill — and all copies must stay identical or the
   colours visibly detach from the rings they belong to. Transforms can't do
   that: a clipPath's shape doesn't follow a transform on the element it
   clips. Easing is therefore done in JS too; CSS only handles the paint. */
.approach-badges .venn-circle {
  fill: none;
  stroke: var(--ink);
  stroke-opacity: 0.6;
  stroke-width: 1;
  transition: stroke-width 200ms ease-out, stroke-opacity 200ms ease-out;
}

.approach-badges .venn-circle.is-active {
  stroke-opacity: 0.95;
  stroke-width: 1.6;
}

/* ---------- Venn <-> service card link (Lagoon) ----------
   Each discipline owns one colour, shared by its nav tab, its circle and its
   card, so the relationship is legible before anything is even hovered.
   The circle fills with its own colour on activation, whether that came from
   hovering the circle or the card below (js/venn.js drives both through the
   same .is-active flag). fill-opacity is animated rather than fill so it can
   transition — CSS cannot tween `fill: none` to a colour. */
[data-theme="lagoon"] .approach-badges .venn-circle {
  fill-opacity: 0;
  transition: stroke-width 200ms ease-out,
              stroke-opacity 200ms ease-out,
              fill-opacity 320ms ease-out;
}

[data-theme="lagoon"] .approach-badges .venn-circle[data-circle="present"]  { fill: #a2c1dd; }
[data-theme="lagoon"] .approach-badges .venn-circle[data-circle="future"]   { fill: #8ad3db; }
[data-theme="lagoon"] .approach-badges .venn-circle[data-circle="physical"] { fill: #fbae6f; }

[data-theme="lagoon"] .approach-badges .venn-circle.is-active { fill-opacity: 0.5; }

/* Card takes the same colour as its circle and its nav tab. A colour
   cross-fade alone reads as a flat swap rather than an animation — there's
   no motion for the eye to track, only a slow colour drift that's easy to
   read as instant even when it technically isn't. The scale gives it the
   same kind of legible grow-in/shrink-out the linked venn circle already
   has (see GROW in js/venn.js), so hovering either half of the pairing
   feels like one consistent gesture. transform doesn't participate in
   layout, so the grow overlaps neighbouring cards' borders by design
   rather than reflowing the grid — z-index keeps the growing card's own
   edges on top of that overlap. */
[data-theme="lagoon"] .service-card {
  position: relative;
  transform: scale(1);
  transition: background-color 320ms ease-out,
              transform 320ms ease-out,
              box-shadow 320ms ease-out;
}

[data-theme="lagoon"] .service-card:hover,
[data-theme="lagoon"] .service-card.is-linked-active {
  transform: scale(1.035);
  z-index: 2;
  box-shadow: 0 18px 32px -12px rgba(20, 67, 76, 0.28);
}

/* The grain sits on a pseudo-element that fades in with the colour, so the
   texture arrives with the wash rather than being visible over the resting
   cream background. */
[data-theme="lagoon"] .service-card::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  background-image: var(--grain);
  mix-blend-mode: overlay;
  transition: opacity 320ms ease-out;
}

[data-theme="lagoon"] .service-card > * { position: relative; }

[data-theme="lagoon"] .service-card:hover::before,
[data-theme="lagoon"] .service-card.is-linked-active::before { opacity: 0.7; }

[data-theme="lagoon"] .service-card[href="counselling.html"]:hover,
[data-theme="lagoon"] .service-card[href="counselling.html"].is-linked-active {
  background-color: #a2c1dd;
}

[data-theme="lagoon"] .service-card[href="coaching.html"]:hover,
[data-theme="lagoon"] .service-card[href="coaching.html"].is-linked-active {
  background-color: #8ad3db;
}

[data-theme="lagoon"] .service-card[href="physical-wellbeing.html"]:hover,
[data-theme="lagoon"] .service-card[href="physical-wellbeing.html"].is-linked-active {
  background-color: #fbae6f;
}

/* --ink-soft drops to ~2.7-3.2:1 on these pastels (same as the page heroes),
   so body copy takes the full ink colour once the wash is in. */
[data-theme="lagoon"] .service-card:hover p,
[data-theme="lagoon"] .service-card.is-linked-active p {
  color: var(--ink);
}

.approach-badges .venn-label {
  font-family: var(--serif);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  fill: var(--ink);
  fill-opacity: 0.75;
  transition: fill-opacity 200ms ease-out;
}

.approach-badges .venn-label.is-active { fill-opacity: 1; }

/* Lagoon: the lens fills get the same grain as the gradients. Done with an
   SVG filter applied to the shapes themselves rather than overlaid noise
   rects — the lenses move under JS, and any separate overlay would be one
   more copy of the geometry to keep in sync (exactly the failure that made
   the colours detach from the rings before). A filter follows its shape. */
[data-theme="lagoon"] .approach-badges .venn-overlap {
  filter: url(#lensGrain);
}

/* Drop the grain while the circles are actually moving (js/venn.js adds
   .is-animating for the duration of the ease). Fine-grained noise isn't
   perceptible on shapes in motion, and an feTurbulence filter re-rasterising
   per frame is the single most expensive thing in this diagram — WebKit in
   particular. It returns the moment they come to rest. */
[data-theme="lagoon"] .approach-badges .venn.is-animating .venn-overlap {
  filter: none;
}

/* A circle brightens the two overlaps it takes part in. At the very centre
   the pointer is inside all three, so all three classes are set and every
   lens lifts together. */
.approach-badges .venn.hover-present .lens-a,
.approach-badges .venn.hover-present .lens-b,
.approach-badges .venn.hover-future .lens-a,
.approach-badges .venn.hover-future .lens-c,
.approach-badges .venn.hover-physical .lens-b,
.approach-badges .venn.hover-physical .lens-c {
  fill-opacity: 0.62;
}

/* ---------- values ---------- */

.values {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-bottom: 1px solid var(--line);
}

.value-cell {
  padding: 70px 38px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 16px;
}

.value-cell + .value-cell { border-left: 1px solid var(--line); }

.value-cell .icon {
  width: 72px;
  height: 72px;
  background-color: var(--ink);
  -webkit-mask: var(--icon) center / contain no-repeat;
  mask: var(--icon) center / contain no-repeat;
}

.icon-integrative { --icon: url("../img/icon-integrative.svg"); }
.icon-triangle    { --icon: url("../img/icon-triangle.svg"); }
.icon-steps       { --icon: url("../img/icon-steps.svg"); }
.icon-evidence    { --icon: url("../img/icon-evidence.svg"); }
.icon-compassion  { --icon: url("../img/icon-compassion.svg"); }

.value-cell .num {
  font-family: var(--serif);
  font-size: 22px;
  letter-spacing: 0.05em;
}

.value-cell h3 { font-size: clamp(17px, 1.7vw, 20px); letter-spacing: 0.01em; }

.value-cell p { font-size: 13px; color: var(--ink-soft); }

/* ---------- tinted (sage) band: why choose us ---------- */

/* Background lives on the wrapper, not on the two sections inside it. A
   gradient's percentage-based positions are relative to the box it's
   painted on — split across two sibling elements, each would restart its
   own copy of the mesh at its own boundary, producing a visible seam where
   they meet. Painting once here, across their combined height, is what
   makes the pattern read as one continuous surface. */
.why-us-band {
  position: relative;
  background-color: var(--band);
}

.why-us-heading {
  text-align: center;
  padding: 80px 40px 40px;
}

.why-us-heading h2 { color: var(--on-band); font-size: clamp(20px, 2vw, 26px); }

.values.tint .value-cell + .value-cell { border-left: none; }

.values.tint .icon { background-color: var(--on-band); }

.values.tint h3 { color: var(--on-band); }

.values.tint p { color: var(--on-band); opacity: 0.85; }

/* This band carries the aurora mesh instead of a flat field, so its text
   needs the full ink colour (--on-aurora) rather than --on-band (white,
   sized for a solid field — it would fail badly on a pale gradient). */
[data-theme="lagoon"] .why-us-band {
  background-image: var(--aurora);
}

[data-theme="lagoon"] .why-us-heading h2,
[data-theme="lagoon"] .values.tint h3,
[data-theme="lagoon"] .values.tint p {
  color: var(--on-aurora);
}

[data-theme="lagoon"] .values.tint .icon { background-color: var(--on-aurora); }

[data-theme="lagoon"] .why-us-band::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: var(--grain);
  opacity: 0.7;
  mix-blend-mode: overlay;
}

/* ---------- photo band ---------- */

.photo-band {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  border-bottom: 1px solid var(--line);
}

/* Square rather than a fixed height, because this band carries 1:1 social
   posts whose text runs to their edges. A fixed 460px against a column that
   narrows with the viewport turns the slot portrait — at ~700px wide it went
   to 235x460, and object-fit:cover then ate 49% of each image's width,
   straight through the lettering. Tracking the column keeps every post whole
   at every size, and on a typical desktop the cell lands within a few pixels
   of the 460 this replaces. */
.photo-band .photo { aspect-ratio: 1; overflow: hidden; position: relative; }
.photo-band .photo + .photo { border-left: 1px solid var(--line); }
.photo-band img { width: 100%; height: 100%; object-fit: cover; }

/* Hover wash over each social post. Sits at z-index 1 to clear the grain
   ::after these tiles already carry — the grain is a texture for the image
   beneath, and letting it fall over the label as well would soften type that
   needs to stay crisp at 11px. pointer-events:none so the overlay can never
   swallow a hover (or, once these become links, a click) meant for the tile.
   :focus-within is here ready for that: it does nothing while the tile holds
   no focusable child, and lights the overlay the moment one is added. */
.photo-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  text-align: center;
  background: rgba(20, 67, 76, 0.72);
  color: #fff;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  opacity: 0;
  pointer-events: none;
  transition: opacity 320ms ease-out;
}

.photo-band .photo:hover .photo-overlay,
.photo-band .photo:focus-within .photo-overlay { opacity: 1; }

/* The label drifts up as the wash arrives, so the two read as one gesture
   rather than a flat panel appearing. */
.photo-overlay-label {
  transform: translateY(6px);
  transition: transform 320ms ease-out;
}

.photo-band .photo:hover .photo-overlay-label,
.photo-band .photo:focus-within .photo-overlay-label { transform: translateY(0); }

/* ---------- photo grain (Lagoon) ----------
   Same grain used across the aurora surfaces, applied to photography too, so
   the two feel like one consistent visual system rather than colour-only.
   `overlay` at low opacity read as almost nothing in a full-page screenshot
   of the portrait — but a 3x zoom into the live element showed it is very
   much there, a proper tactile texture across skin and fabric; 0.14-0.16
   was too timid a read of that same screenshot problem. 0.7 is the value
   confirmed against Gina's portrait at real pixel scale. Every container
   already has overflow:hidden for its object-fit crop, so the overlay is
   clipped to the same bounds for free — no separate masking needed. Covers
   .about-media (Gina's portrait) and the hero/treatment-media/photo-band
   images, so every photo on the page inherits the same treatment with no
   per-image CSS changes required. */
[data-theme="lagoon"] .hero .hero-img,
[data-theme="lagoon"] .about-media,
[data-theme="lagoon"] .treatment-media,
[data-theme="lagoon"] .photo-band .photo {
  position: relative;
}

[data-theme="lagoon"] .hero .hero-img::after,
[data-theme="lagoon"] .about-media::after,
[data-theme="lagoon"] .treatment-media::after,
[data-theme="lagoon"] .photo-band .photo::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: var(--grain);
  opacity: 0.7;
  mix-blend-mode: overlay;
}

/* ---------- page hero (interior pages) ---------- */

.page-hero .well {
  padding: 110px 40px;
  text-align: center;
}

.page-hero h1 { font-size: clamp(20px, 2vw, 25px); }

.page-hero .eyebrow { margin-bottom: 20px; color: var(--ink-soft); }

.page-hero p {
  max-width: 620px;
  margin: 26px auto 0;
  color: var(--ink-soft);
}

/* Lagoon: each interior page's hero well takes the same colour as its own
   nav tab (see [data-theme="lagoon"] .site-nav li:nth-child(n) above) — Home
   is the only one excluded (the hero there is the display-font intro, not
   a page-hero .well). --ink-soft fails badly on these (2.7–4.8:1 depending
   on the hue), so eyebrow/heading/body all switch to full --ink, the same
   swap the aurora surfaces needed. Grain is a plain ::after overlay rather
   than the venn's SVG filter: this is a simple rectangle with no clip-path
   geometry that could fall out of sync. */
[data-theme="lagoon"] .page-hero-counselling .well,
[data-theme="lagoon"] .page-hero-coaching .well,
[data-theme="lagoon"] .page-hero-physical .well,
[data-theme="lagoon"] .page-hero-book .well,
[data-theme="lagoon"] .page-hero-about .well,
[data-theme="lagoon"] .book-grid .well {
  position: relative;
  color: var(--ink);
}

[data-theme="lagoon"] .page-hero-counselling .well { background-color: #a2c1dd; }
[data-theme="lagoon"] .page-hero-coaching .well    { background-color: #8ad3db; }
[data-theme="lagoon"] .page-hero-physical .well    { background-color: #fbae6f; }
[data-theme="lagoon"] .page-hero-book .well        { background-color: #e6a6bc; }
[data-theme="lagoon"] .page-hero-about .well       { background-color: #bea0e5; }
[data-theme="lagoon"] .book-grid .well             { background-color: #e6a6bc; }

[data-theme="lagoon"] .page-hero-counselling .well .eyebrow,
[data-theme="lagoon"] .page-hero-counselling .well h1,
[data-theme="lagoon"] .page-hero-counselling .well p,
[data-theme="lagoon"] .page-hero-coaching .well .eyebrow,
[data-theme="lagoon"] .page-hero-coaching .well h1,
[data-theme="lagoon"] .page-hero-coaching .well p,
[data-theme="lagoon"] .page-hero-physical .well .eyebrow,
[data-theme="lagoon"] .page-hero-physical .well h1,
[data-theme="lagoon"] .page-hero-physical .well p,
[data-theme="lagoon"] .page-hero-book .well .eyebrow,
[data-theme="lagoon"] .page-hero-book .well h1,
[data-theme="lagoon"] .page-hero-book .well p,
[data-theme="lagoon"] .page-hero-about .well .eyebrow,
[data-theme="lagoon"] .page-hero-about .well h1,
[data-theme="lagoon"] .page-hero-about .well p,
[data-theme="lagoon"] .book-grid .well h1,
[data-theme="lagoon"] .book-grid .book-intro,
[data-theme="lagoon"] .book-grid .enquiry label {
  color: var(--ink);
}

[data-theme="lagoon"] .page-hero-counselling .well::after,
[data-theme="lagoon"] .page-hero-coaching .well::after,
[data-theme="lagoon"] .page-hero-physical .well::after,
[data-theme="lagoon"] .page-hero-book .well::after,
[data-theme="lagoon"] .page-hero-about .well::after,
[data-theme="lagoon"] .book-grid .well::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: var(--grain);
  opacity: 0.7;
  mix-blend-mode: overlay;
}

/* ---------- treatment rows (service pages) ---------- */

.treatment-row .well {
  display: grid;
  grid-template-columns: 5fr 6fr;
  background: var(--surface);
}

.treatment-row.flip .well { grid-template-columns: 6fr 5fr; }

/* No .treatment-media in this row (image removed), so the copy fills the
   whole well — same width as every other row, since they all share the
   .rail-grid > .well container. The left/right divider only made sense
   against the image it used to sit beside, so it goes too. */
.treatment-row.full-bleed .well { grid-template-columns: 1fr; }
.treatment-row.full-bleed .treatment-copy { border-left: none; border-right: none; }

.treatment-media {
  overflow: hidden;
  min-height: 480px;
  padding: 48px;
  display: flex;
}

.treatment-media img {
  width: 100%;
  height: 100%;
  min-height: 380px;
  object-fit: cover;
}

.treatment-copy {
  border-left: 1px solid var(--line);
  padding: 80px 64px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 26px;
  background: var(--surface-2);
}

/* .about-copy carries a left border to divide it from the media beside it.
   When it is instead the FIRST child (Education on About, Sessions & Fees on
   Book) that border lands directly on the .well's own left border, reading as
   one thick 2px line. Only an .about-copy that actually follows something
   needs the divider. */
.about-split .well > .about-copy:first-child { border-left: none; }

.treatment-row.flip .treatment-media { order: 2; }
.treatment-row.flip .treatment-copy { order: 1; border-left: none; border-right: 1px solid var(--line); }

.treatment-copy h2 { font-size: clamp(19px, 1.9vw, 25px); }

.treatment-copy p { color: var(--ink-soft); }

.treatment-copy .practitioners {
  font-style: italic;
  font-size: 12px;
}

.treatment-copy .contact-lines {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  line-height: 2;
}

/* ---------- CTA band (colour + noise, page-level closer) ----------
   Same surface treatment as .why-us-band: the aurora mesh + grain, with
   --on-band overridden to the full ink colour since white fails on the
   pale aurora the same way it did on the values band. */
.cta-band .well {
  position: relative;
  background-color: var(--band);
  background-image: var(--aurora, none);
  color: var(--on-band);
  text-align: center;
  padding: 110px 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
}

.cta-band .eyebrow { color: var(--on-band); opacity: 0.85; }

.cta-band h2 {
  max-width: 640px;
  font-size: clamp(22px, 2.6vw, 34px);
  color: var(--on-band);
}

.cta-band p:not(.eyebrow) {
  max-width: 480px;
  margin: 0;
  color: var(--on-band);
  opacity: 0.85;
}

[data-theme="lagoon"] .cta-band .eyebrow,
[data-theme="lagoon"] .cta-band h2,
[data-theme="lagoon"] .cta-band p {
  color: var(--on-aurora);
  opacity: 1;
}

[data-theme="lagoon"] .cta-band .cta-button {
  color: var(--on-aurora);
  border-color: var(--on-aurora);
}

[data-theme="lagoon"] .cta-band .well::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: var(--grain);
  opacity: 0.7;
  mix-blend-mode: overlay;
}

/* Outline only — no fill, no hover state. Text and border both use the
   section's own text colour (--on-band, or --on-aurora on Lagoon — see the
   shared colour rule above), so the button always reads clearly against
   whatever is behind it without needing a separate contrast calculation
   for a fill colour. */
.cta-band .cta-button {
  position: relative;
  display: inline-block;
  margin-top: 6px;
  padding: 16px 40px;
  background: transparent;
  color: var(--on-band);
  border: 1px solid var(--on-band);
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 400;
}

/* ---------- about ---------- */

.about-split .well {
  display: grid;
  grid-template-columns: 1fr 1fr;
  background: var(--surface);
}

.about-media { overflow: hidden; }
/* <picture> is inline with auto height by default, which would break the
   img's height:100% — it needs a parent with a resolvable height to fill. */
.about-media picture { display: block; height: 100%; }
.about-media img { width: 100%; height: 100%; object-fit: cover; min-height: 560px; }

.about-copy {
  border-left: 1px solid var(--line);
  padding: 90px 64px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 26px;
  background: var(--surface-2);
}

.about-copy h2 { font-size: clamp(18px, 1.8vw, 22px); }

.about-copy .mission {
  font-style: italic;
  font-size: 15px;
  color: var(--ink-soft);
}

.pillars {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-bottom: 1px solid var(--line);
}

.pillar {
  padding: 90px 60px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

.pillar + .pillar { border-left: 1px solid var(--line); }

.pillar h3 { font-size: clamp(18px, 1.8vw, 23px); }

.pillar p { max-width: 420px; color: var(--ink-soft); }

.statement .well {
  padding: 90px 40px;
  text-align: center;
}

.statement p {
  max-width: 620px;
  margin: 0 auto;
  font-family: var(--serif);
  font-size: clamp(17px, 1.8vw, 21px);
  font-style: italic;
  line-height: 1.6;
}

/* ---------- book / contact ---------- */

.book-grid .well {
  padding: 100px 60px;
  text-align: center;
}

.book-grid h1 { font-size: clamp(20px, 2vw, 25px); margin-bottom: 10px; }

.book-intro {
  max-width: 560px;
  margin: 20px auto 70px;
  color: var(--ink-soft);
}

.book-list {
  display: flex;
  flex-direction: column;
  gap: 58px;
  max-width: 520px;
  margin: 0 auto;
}

.book-entry h3 {
  font-size: 15px;
  letter-spacing: 0.01em;
  margin-bottom: 14px;
}

.book-entry p {
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  line-height: 2.1;
}

.book-entry a { border-bottom: 1px solid var(--line); }

/* ---------- footer ---------- */

.site-footer { background: var(--surface); }

/* ---------- footer reveal ----------
   Scroll-linked. js/reveal.js writes --fp (footer progress, 0 to 1) onto the
   footer as it enters the viewport and everything here reads from it: the
   structural hairlines draw out from their origins while the content lifts
   into place behind them, each row travelling a different distance so the
   footer assembles in layers rather than arriving as one slab.

   Transform and opacity only — no sticky positioning. A fast flick simply
   clamps --fp to 1 and lands everything at its final state, and nothing
   depends on viewport height, which is what makes curtain-style footers
   misbehave when a mobile address bar shows or hides.

   --fp defaults to 1 so that if the script never runs, or the browser opts
   out of motion, the footer renders exactly as it always did: lines drawn,
   content in place. */
.site-footer { --fp: 1; }

/* Each rule keeps its 1px of layout as a transparent border and is painted by
   a pseudo-element instead, so nothing shifts as it draws. ::after is already
   spoken for on .footer-notice and .colophon (the grain overlay), so the
   lines use ::before throughout. Offsets are negative because an absolutely
   positioned child is placed against the padding box — the border sits just
   outside it. */
.footer-band,
.footer-nav,
.footer-notice { border-bottom-color: transparent; }

.footer-band,
.footer-nav { position: relative; }

.footer-band::before,
.footer-nav::before,
.footer-notice::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: var(--line);
  transform: scaleX(var(--fp));
  transform-origin: center;
}

/* The two verticals flanking the logo draw downward, against the horizontals
   opening outward — so the frame closes in two directions at once. */
.footer-band .cell.mid {
  position: relative;
  border-left-color: transparent;
  border-right-color: transparent;
}

.footer-band .cell.mid::before,
.footer-band .cell.mid::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--line);
  transform: scaleY(var(--fp));
  transform-origin: top center;
}

.footer-band .cell.mid::before { left: -1px; }
.footer-band .cell.mid::after { right: -1px; }

.footer-band .cell,
.footer-nav a,
.colophon {
  transform: translateY(calc((1 - var(--fp)) * var(--lift)));
  opacity: var(--fp);
}

.footer-band .cell { --lift: 30px; }
.footer-nav a      { --lift: 20px; }
.colophon          { --lift: 10px; }

.footer-band {
  border-bottom: 1px solid var(--line);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: stretch;
}

.footer-band .cell {
  padding: 60px 40px;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: center;
  line-height: 2.2;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.footer-band .cell:first-child { text-align: right; align-items: flex-end; }
.footer-band .cell:last-child { text-align: left; align-items: flex-start; }

.footer-band .cell.mid {
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  padding: 60px 80px;
  align-items: center;
}

.footer-band .cell.mid .name {
  width: clamp(120px, 11vw, 168px);
  aspect-ratio: 892 / 903;
  background-color: var(--ink);
  -webkit-mask: url("../img/logo-mark.png") center / contain no-repeat;
  mask: url("../img/logo-mark.png") center / contain no-repeat;
  margin-bottom: 22px;
  display: block;
}

.footer-nav {
  display: flex;
  justify-content: center;
  gap: 0;
  border-bottom: 1px solid var(--line);
}

.footer-nav a {
  padding: 14px 22px;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  border-right: 1px solid var(--line);
}

.footer-nav a:first-child { border-left: 1px solid var(--line); }

.footer-nav a:hover { background: var(--nav-active, var(--accent)); color: var(--on-nav-active, var(--on-accent)); }

/* Lagoon: same per-item hues as the header nav (see .site-nav above), so the
   two navigations read as one consistent system rather than the header
   being playful and the footer staying plain. No li wrapper here — the
   links are direct children of <nav>, so nth-child targets the <a> itself. */
[data-theme="lagoon"] .footer-nav a:nth-child(1):hover { background: #84b868; color: var(--ink); }
[data-theme="lagoon"] .footer-nav a:nth-child(2):hover { background: #a2c1dd; color: var(--ink); }
[data-theme="lagoon"] .footer-nav a:nth-child(3):hover { background: #8ad3db; color: var(--ink); }
[data-theme="lagoon"] .footer-nav a:nth-child(4):hover { background: #fbae6f; color: var(--ink); }
[data-theme="lagoon"] .footer-nav a:nth-child(5):hover { background: #bea0e5; color: var(--ink); }
[data-theme="lagoon"] .footer-nav a:nth-child(6):hover { background: #e6a6bc; color: var(--ink); }

.footer-notice {
  position: relative;
  border-bottom: 1px solid var(--line);
  padding: 28px 40px;
  background-image: var(--aurora, none);
}

/* --ink-soft only reaches 4.01:1 on the palest blob, so aurora surfaces take
   the full ink colour instead. */
.footer-notice .crisis-notice { color: var(--on-aurora, var(--ink-soft)); }

/* Lagoon: the disclaimer stays plain (no gradient, no grain) even though the
   announce strip, the "why work with" band and the copyright line all carry
   the aurora — a full block of colour behind safety/crisis text read as the
   wrong tone. It falls back to the page ground and the normal soft ink. */
[data-theme="lagoon"] .footer-notice {
  background-image: none;
}

[data-theme="lagoon"] .footer-notice::after {
  display: none;
}

[data-theme="lagoon"] .footer-notice .crisis-notice {
  color: var(--ink-soft);
}

.footer-notice .crisis-notice {
  border: none;
  background: none;
  padding: 0;
  max-width: 760px;
  margin: 0 auto;
  text-align: center;
}

.colophon {
  position: relative;
  background-image: var(--aurora, none);
  text-align: center;
  padding: 20px;
  font-size: 9px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--on-aurora, var(--ink-soft));
}

/* Site credit, folded into the same line as the copyright rather than a
   second row — this is a courtesy mention, not a footer nav item, so it
   should read as quieter than everything else down here, not equal to it. */
.colophon .credit { opacity: 0.7; }

.colophon .credit a {
  text-decoration: underline;
  text-decoration-color: var(--line-soft);
  text-underline-offset: 0.2em;
  transition: text-decoration-color 200ms ease-out;
}

.colophon .credit a:hover,
.colophon .credit a:focus-visible { text-decoration-color: currentColor; }

/* Film grain over the aurora surfaces; absent when --grain is none. */
.announce::after,
.footer-notice::after,
.colophon::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: var(--grain, none);
  opacity: 0.7;
  mix-blend-mode: overlay;
}

/* ---------- image placeholders (pending Gina's photography) ---------- */

.ph {
  width: 100%;
  height: 100%;
  min-height: 300px;
  flex: 1;
  position: relative;
  background: var(--ph-1);
}

.ph::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--ph-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--ph-grid) 1px, transparent 1px);
  background-size: 34px 34px;
}

.ph-2 { background: var(--ph-2); }
.ph-3 { background: var(--ph-3); }

.treatment-media .ph { min-height: 380px; }
.photo-band .ph { min-height: 0; }

/* ---------- line diagrams (service pages, second treatment row) ----------
   Two hand-built SVG figures recreated from the references in /files/: the
   globe (Counselling, "What I Work With") and the pyramid (Coaching, "Who I
   Work With"). Everything except the geometry and the fill colour is shared,
   so both carry .line-diagram and the per-figure classes only carry what
   genuinely differs. Geometry itself lives in the markup rather than here
   (see the notes there) since it is content-shaped rather than style.

   Each figure fills its .treatment-media edge to edge. That container pads
   48px to frame a photograph, which on a figure that paints its own
   background just reads as a border of bare .well colour around it — hence
   the :has() override below. Grain comes for free: the Lagoon
   .treatment-media::after overlay already covers the whole box.

   Background defaults to the theme's placeholder tone like every other .ph,
   but Lagoon recolours each to the same hue that page already uses for its
   nav tab, service card and venn circle, so the graphic reads as part of
   that colour-coding rather than a generic illustration. Black lines read
   far better than white on both — these pastels are light enough that white
   would sit close to them in luminance. */
.line-diagram {
  width: 100%;
  height: 100%;
  min-height: 380px;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ph-2);
}

/* Both the hand-built figures and the service-page photographs run edge to
   edge, so neither wants .treatment-media's 48px frame. Higher specificity
   than the bare .treatment-media rule (and than its 28px mobile override),
   so the full bleed holds at every width without an !important. */
.treatment-media:has(.line-diagram),
.treatment-media:has(img) { padding: 0; }

/* Pinned so one viewBox unit is one CSS pixel, which makes the 13px labels
   below render at exactly the 13px the home-page venn uses. The venn earns
   its consistency the same way (max-width 380 on a 380-wide viewBox). Sizing
   these by percentage instead let the scale float with the container — the
   same 13px was landing anywhere from ~11px to ~15px depending on viewport
   and which column the diagram sat in, which is what made the labels look
   inconsistent between diagrams. All three viewBoxes are 400 wide. */
.line-diagram svg {
  width: 100%;
  max-width: 400px;
  height: auto;
}

.line-diagram circle,
.line-diagram ellipse,
.line-diagram polygon {
  fill: none;
  stroke: #000;
  stroke-width: 1.4;
}

/* The hoverable pieces. `transparent` rather than `none` matters: an unfilled
   shape is only hit-testable on its stroke, so the fill has to exist for the
   interior to take the hover at all. */
.line-diagram ellipse,
.line-diagram .facet {
  fill: transparent;
  transition: fill 280ms ease-out;
}

.line-diagram ellipse:hover,
.line-diagram .tier:not(.tier-apex) .facet:hover { fill: #fff; }

/* A pyramid tier is two polygons (its left and right face) meeting on the
   near vertical edge, so hovering either has to light the whole tier — a
   half-lit tier would read as a rendering fault. :has() lets the group
   answer for both without any script. .tier-apex is excluded by request —
   it stays static while every tier below it highlights. It marks TWO of the
   six <g> groups in the markup: the true geometric apex is a sliver too
   small to ever land a cursor on, so the group actually reachable by hover
   is the one below it — together the pair is what reads as a single small
   peak, and both have to be excluded for that peak to feel non-interactive. */
.line-diagram .tier:not(.tier-apex):has(.facet:hover) .facet { fill: #fff; }

.line-diagram text {
  font-family: var(--serif);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  fill: #000;
  pointer-events: none;
}

[data-theme="lagoon"] .globe-diagram     { background: #a2c1dd; }
[data-theme="lagoon"] .pyramid-diagram   { background: #8ad3db; }
[data-theme="lagoon"] .wellbeing-diagram { background: #fbae6f; }

/* ---------- three-up services grid ---------- */

.services-inner.three { grid-template-columns: repeat(3, 1fr); }
.services-inner.three .service-card:nth-child(3n) { border-right: none; }
.services-inner.three .service-card:nth-child(-n + 3) { border-top: none; }

/* ---------- framework strip ---------- */

.framework-inner {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.framework-step {
  padding: 58px 40px 64px;
  border-right: 1px solid var(--line);
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.framework-step:nth-child(3n) { border-right: none; }
.framework-step:nth-child(n + 4) { border-top: 1px solid var(--line); }

.framework-step .step-num {
  font-family: var(--serif);
  font-size: 18px;
  letter-spacing: 0.08em;
  color: var(--green-ink);
}

.framework-step h3 { font-size: 17px; letter-spacing: 0.01em; }

.framework-step p { font-size: 13px; color: var(--ink-soft); }

/* ---------- testimonials carousel (coaching) ----------
   The section itself keeps the ordinary .well surface; the colour lives on
   the arrows instead, which take this page's own aqua plus the same grain
   overlay the .page-hero wells carry. */

/* --gutter is the horizontal padding, declared once because two things must
   agree on it: the quote column matches .treatment-copy's measure only while
   this equals ITS 64px (see "How Sessions Work" two sections down), and the
   arrows below sit flush to the section edge by cancelling exactly this much.
   .treatment-copy holds 64px at every breakpoint, so this must too. */
.testimonials .well {
  --gutter: 64px;
  padding: 84px var(--gutter) 60px;
  text-align: center;
}

.testimonials .eyebrow { margin-bottom: 14px; }
.testimonials h2 { font-size: clamp(20px, 2vw, 26px); margin-bottom: 44px; }

/* Arrows are pulled OUT of flow (positioned against .carousel below) rather
   than sharing a grid row with the quote, so nothing here needs to reserve
   column space for them — the quote column is free to be exactly as wide as
   .well's own content box, matching .treatment-copy's un-capped measure
   instead of floating narrower inside it. */
.carousel { position: relative; }

/* No-JS default: a plain stacked column of every quote, arrows hidden. The
   row/viewport behaviour below only switches on once js/carousel.js runs. */
/* Deliberately NO horizontal padding here. A slide is flex-basis:100%, which
   resolves against this track's CONTENT box, while the translateX below is a
   percentage, which resolves against its BORDER box. Padding makes those two
   disagree by exactly its own width, so every slide lands short and the next
   one bleeds into view. The arrows get their clearance from the well's
   gutter instead (see .carousel-arrow). */
.carousel-track {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 44px;
}

.testimonial { text-align: left; }

/* Deliberately sets no family, size or line-height, so the quote inherits the
   body defaults — which is exactly how .treatment-copy p gets its type too.
   Matching by shared inheritance rather than by restating the same three
   values keeps the two blocks from drifting apart if the body scale moves.
   Colour is the one thing .treatment-copy p does declare for itself, so it
   is declared here too, from the same token. The figcaption below stays on
   full --ink: that attribution was asked for darker than the quote. */
.testimonial blockquote p { color: var(--ink-soft); }

.testimonial blockquote p + p { margin-top: 14px; }

.testimonial figcaption {
  margin-top: 24px;
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
}

/* Semicircles, flat edge on the section's own border line and the curved
   half bulging inward from it — literally sitting "on the edge" of the
   section rather than floating near it. Height is 2x width so the radius
   used for the curved corners (== width) sweeps a true half-circle rather
   than a rounded-off rectangle. */
.carousel-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  overflow: hidden;      /* clips the grain overlay to the curve */
  width: 44px;
  height: 88px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  background-color: var(--ph-2);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: opacity 200ms ease-out;
}

.carousel-arrow:hover { opacity: 0.75; }

/* The `display: flex` above outranks the UA stylesheet's `[hidden] { display:
   none }`, so without this the arrows paint even while still marked hidden —
   which broke the two cases the hidden attribute exists for: a single
   testimonial (nothing to page through) and a no-JS load (nothing to page
   with). Both showed inert buttons. */
.carousel-arrow[hidden] { display: none; }

/* Offset by the full gutter so the flat edge lands on the section's own
   border rather than on .carousel's content edge, which sits a gutter's
   width inside it. This also keeps the arrows entirely within the gutter,
   clear of the quote, so the text can use the full content box. */
[data-carousel-prev] {
  left: calc(var(--gutter) * -1);
  border-left: none;
  border-radius: 0 999px 999px 0;
  padding-right: 4px;   /* nudges the glyph off the flat edge, toward the
                            visual centre of the curved bulge */
}

[data-carousel-next] {
  right: calc(var(--gutter) * -1);
  border-right: none;
  border-radius: 999px 0 0 999px;
  padding-left: 4px;
}

/* Arrows take the hue of the page they sit on, the same colour-coding the
   nav tabs and page-hero wells follow. Coaching aqua is the default because
   that is where the carousel started; each other page overrides. */
[data-theme="lagoon"] .carousel-arrow { background-color: #8ad3db; }
[data-theme="lagoon"] .testimonials-counselling .carousel-arrow { background-color: #a2c1dd; }

[data-theme="lagoon"] .carousel-arrow::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: var(--grain);
  opacity: 0.7;
  mix-blend-mode: overlay;
}

/* --- enhanced state, added by js/carousel.js --- */

.carousel.is-enhanced .carousel-viewport { overflow: hidden; }

.carousel.is-enhanced .carousel-track {
  flex-direction: row;
  align-items: stretch;   /* every slide takes the tallest one's height, so
                             advancing never jolts the page length */
  gap: 0;
  transform: translateX(calc(var(--slide, 0) * -100%));
  transition: transform 520ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* Every slide stretches to the height of the tallest one (see .carousel-track
   above), so a short quote would otherwise sit pinned to the top of that
   taller box with dead space below it — and the arrows, centred on that same
   box, would then land below the visible text instead of on it. Centring
   each slide's own content vertically here fixes both at once. */
.carousel.is-enhanced .carousel-slide {
  flex: 0 0 100%;
  min-width: 0;
  display: flex;
  align-items: center;
}

/* ---------- crisis / safeguarding notice ---------- */

.crisis-notice {
  border: 1px solid var(--line);
  padding: 30px 34px;
  font-size: 13px;
  line-height: 1.9;
  color: var(--ink-soft);
  background: var(--surface);
}

.crisis-notice p + p { margin-top: 12px; }

.crisis-notice strong {
  display: block;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-size: 10px;
  color: var(--ink);
  margin-bottom: 10px;
}

/* ---------- credentials list (about) ---------- */

.quals { list-style: none; display: flex; flex-direction: column; gap: 14px; }

.quals li {
  font-size: 13px;
  color: var(--ink-soft);
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line-soft);
}

.quals li:last-child { border-bottom: none; }

.quals .yr {
  display: block;
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--green-ink);
  margin-top: 5px;
}

/* ---------- enquiry form ---------- */

.enquiry {
  display: flex;
  flex-direction: column;
  gap: 22px;
  max-width: 520px;
  margin: 0 auto;
  text-align: left;
}

/* A centered caption sitting above a left-edge-flush, full-width field reads
   as disconnected rather than "centered" — the eye has nothing to relate the
   short centered word to. Labels stay aligned with their own field's edge;
   the form column and the submit button (below) carry the actual centering. */
.enquiry label {
  display: block;
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin-bottom: 8px;
  color: var(--ink-soft);
}

.enquiry input,
.enquiry textarea,
.enquiry select {
  width: 100%;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 300;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  padding: 13px 14px;
  border-radius: 0;
}

.enquiry textarea { min-height: 130px; resize: vertical; }

.enquiry input:focus,
.enquiry textarea:focus,
.enquiry select:focus { outline: 1px solid var(--accent); outline-offset: 1px; }

.enquiry button {
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  padding: 15px 34px;
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  cursor: pointer;
  align-self: center;
  transition: background 0.25s;
}

.enquiry button:hover { background: var(--band); color: var(--on-band); }

[data-theme="lagoon"] .book-grid .enquiry button {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--ink);
}

/* .enquiry button:hover (above) already fills with --band/--on-band on
   hover, which for Lagoon is a solid dark teal with white text — that
   already reads correctly as the "activated" state of this outline. */

[data-theme="lagoon"] .book-grid .form-note { color: var(--ink); opacity: 0.85; }

.form-note { font-size: 11px; color: var(--ink-soft); }

/* ---------- steps list (how it works) ---------- */

.steps-list {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-bottom: 1px solid var(--line);
}

.step-cell {
  padding: 60px 34px;
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.step-cell:last-child { border-right: none; }

.step-cell .step-num {
  font-family: var(--serif);
  font-size: 22px;
  letter-spacing: 0.05em;
  color: var(--green-ink);
}

.step-cell h3 { font-size: 16px; letter-spacing: 0.01em; }

.step-cell p { font-size: 13px; color: var(--ink-soft); }

/* ---------- responsive ---------- */

@media (max-width: 1080px) {
  /* Rows wrap here, and each row needs its own closing edge on both sides —
     a single container-level border can't do that since justify-content:
     center means each row's width (and therefore its last item) varies with
     viewport width. Giving every item both a left AND right border covers
     every row regardless of how many items land in it — but two adjacent
     borders sitting side by side is a 2px-wide line, not a shared 1px one
     (checked directly: item[0].right === item[1].left, and both draw their
     own 1px there). Pulling every item but the first left by its own border
     width lands that border exactly on top of its neighbour's, collapsing
     the pair back to 1px — including across a wrap, where the item starting
     a new row has no visual neighbour to its left, so the same 1px nudge is
     just an imperceptible sub-pixel shift off dead-centre. */
  .site-nav ul { flex-wrap: wrap; justify-content: center; border-top: 1px solid var(--line); border-left: none; margin-top: -1px; }
  .site-nav li { border-left: 1px solid var(--line); border-right: 1px solid var(--line); }
  .site-nav li:not(:first-child) { margin-left: -1px; }
  .site-nav a { padding: 14px 16px; }
  .header-grid { grid-template-columns: 1fr minmax(auto, 420px) 1fr; }
  .header-cell { padding: 34px 20px; font-size: 11px; }
  .brand { padding: 28px 24px; }
  .hero { grid-template-columns: minmax(0, 1fr) minmax(auto, 500px) minmax(0, 1fr); min-height: 480px; }
  .hero-panel { padding: 60px 36px; gap: 40px; }
  .services-inner { grid-template-columns: 1fr 1fr; }
  .service-card:nth-child(2n) { border-right: none; }
  .service-card:nth-child(2n + 1) { border-right: 1px solid var(--line); }
  .service-card:nth-child(n + 3) { border-top: 1px solid var(--line); }
  .services-inner.three { grid-template-columns: 1fr 1fr; }
  .services-inner.three .service-card:nth-child(3) { border-right: 1px solid var(--line); border-top: 1px solid var(--line); }
  .framework-step { padding: 50px 26px 56px; }
  /* Vertical only. The horizontal gutter deliberately stays at 64px so the
     quote keeps matching .treatment-copy, which does not shrink here either;
     narrowing it made this section run visibly wider than every other one. */
  .testimonials .well { padding-top: 64px; padding-bottom: 56px; }
  .steps-list { grid-template-columns: 1fr 1fr; }
  .step-cell:nth-child(2n) { border-right: none; }
  .step-cell:nth-child(n + 3) { border-top: 1px solid var(--line); }
  .values { grid-template-columns: 1fr 1fr; }
  .values:not(.tint) .value-cell:nth-child(n + 3) { border-top: 1px solid var(--line); }
  .values:not(.tint) .value-cell:nth-child(3) { border-left: none; }
  .treatment-row .well,
  .treatment-row.flip .well,
  .about-split .well,
  .approach .well { grid-template-columns: 1fr; }
  .treatment-copy, .about-copy, .approach-badges { border-left: none; border-top: 1px solid var(--line); }
  .treatment-row.flip .treatment-copy { border-right: none; order: 2; }
  .treatment-row.flip .treatment-media { order: 1; }
  .treatment-media { min-height: 0; padding: 28px; }
  .treatment-media img { min-height: 280px; }
  .line-diagram { min-height: 280px; }
  /* Below 400px the diagrams can no longer hold 1:1, so the labels shrink
     with them. Same compensation the venn makes at this breakpoint (17px
     against its own 300px cap) — lands back at ~13px rendered. */
  .line-diagram text { font-size: 14px; }
  .footer-band .cell { padding: 44px 20px; font-size: 11px; }
  .footer-band .cell.mid { padding: 44px 36px; }
}

@media (max-width: 640px) {
  .header-grid { grid-template-columns: 1fr; }
  .header-cell { display: none; }
  .brand { border: none; padding: 30px 20px; }
  .hero { grid-template-columns: 1fr; min-height: 0; }
  .hero .hero-img { height: 300px; }
  /* Default object-position (50% 50%) crops through both subjects' eyes:
     the source is a tall 640x853 portrait dominated by sky above the
     subjects' shoulders, so centring vertically keeps that empty sky and
     cuts the faces instead. Anchoring high keeps the crop on the couple's
     faces at any width this box actually renders at (390-640px). */
  .hero .hero-img.left img { object-position: 50% 12%; }
  .hero .hero-img.right { display: none; }
  .hero-panel { border: none; border-top: 1px solid var(--line); }
  /* Six items never divide evenly into a phone's width, so the centred
     wrapping row above left each line indented differently, with a stray
     cell edge wherever a row ran short. A 2-column grid is the same device
     every other section already uses at this width: equal cells, columns
     that actually line up, and no leftover edges. It also lifts the tap
     target to ~49px, clear of the 44px minimum (it was 43px).
     Overrides the flex row set at 1080px, borders included. */
  .site-nav ul {
    display: grid;
    grid-template-columns: 1fr 1fr;
    width: 100%;
    border-top: none;
    border-left: none;
    margin-top: 0;
  }
  .site-nav li { border: none; margin-left: 0; }
  .site-nav li:nth-child(odd) { border-right: 1px solid var(--line); }
  .site-nav li:nth-child(n + 3) { border-top: 1px solid var(--line); }
  .site-nav a {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    padding: 15px 10px;
    font-size: 11px;
    text-align: center;
    /* "Physical Wellbeing" fits one line down to ~365px; below that it wraps
       inside its cell rather than overflowing, and the grid row absorbs it. */
    white-space: normal;
  }
  .services-inner,
  .services-inner.three { grid-template-columns: 1fr; }
  .service-card { border-right: none !important; }
  .service-card:nth-child(n + 2) { border-top: 1px solid var(--line); }
  .framework-inner { grid-template-columns: 1fr 1fr; }
  .framework-step { border-right: 1px solid var(--line); border-top: none; }
  .framework-step:nth-child(2n) { border-right: none; }
  .framework-step:nth-child(n + 3) { border-top: 1px solid var(--line); }
  .steps-list { grid-template-columns: 1fr; }
  .step-cell { border-right: none; }
  .step-cell:nth-child(n + 2) { border-top: 1px solid var(--line); }
  .pillars, .photo-band { grid-template-columns: 1fr; }
  .approach-badges .venn { max-width: 300px; }
  .approach-badges .venn-label { font-size: 17px; }
  .pillar + .pillar,
  .photo-band .photo + .photo { border-left: none; border-top: 1px solid var(--line); }
  .values { grid-template-columns: 1fr; }
  .value-cell { border-left: none !important; }
  .values:not(.tint) .value-cell:nth-child(n + 2) { border-top: 1px solid var(--line); }
  /* 10px uppercase is fine to scan on a desktop but genuinely hard to read
     held at arm's length, so the small label sizes come up a notch — the
     same 11px the main nav already uses at this width. Each .card-link
     context is named individually to match the specificity of the rules
     that set 10px (.approach-copy .card-link and friends); a bare
     .card-link here loses to them, media query or not. */
  .footer-nav a,
  .approach-copy .card-link,
  .service-card .card-link,
  .title-band .card-link,
  .cta-band .cta-button { font-size: 11px; }

  /* The mailto sat at 24px tall. It is on its own line in the footer cell,
     so padding is safe here — nothing shifts around it. */
  .footer-band .cell.mid a { display: inline-block; padding: 10px 6px; }

  /* Standalone text links sat at 22px tall — half the 44px touch minimum.
     Padding would push the animated underline away from the text, so the
     hit area is extended with a pseudo-element instead: no visual change,
     no layout shift. ::after is already taken by that underline.
     Only a.card-link — the .card-link inside a .service-card is a span
     whose real target is the whole card, which is already large. */
  a.card-link::before {
    content: "";
    position: absolute;
    inset: -12px 0;
  }

  .footer-nav { flex-wrap: wrap; }
  .footer-band { grid-template-columns: 1fr; }
  .footer-band .cell.mid { border-left: none; border-right: none; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
  /* Stacked here, so the centre cell's flanking rules become the horizontal
     borders above — the drawn verticals would sit across the layout. */
  .footer-band .cell.mid::before,
  .footer-band .cell.mid::after { display: none; }
  .footer-band .cell:first-child,
  .footer-band .cell:last-child { text-align: center; align-items: center; }
}

/* ==========================================================================
   Motion & focus
   ========================================================================== */

/* Keyboard focus. Previously only the four enquiry fields had any focus
   styling, so tabbing the nav, cards or links fell back to the browser
   default ring. :focus-visible keeps it off mouse clicks. */
a:focus-visible,
button:focus-visible,
.service-card:focus-visible,
.cta-button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 1px;
}

/* Scroll reveal. The reveal class is applied by js/reveal.js only after it
   has confirmed IntersectionObserver support — content is fully visible
   until then, so a JS failure or an old browser degrades to the plain
   static page rather than a blank one. */
.reveal-ready [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
}

.reveal-ready [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  transition: opacity 620ms cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 620ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Hover treatment for the text links ("Learn More", "About Gina", …).
   The underline wipe alone was doing nothing perceptible: these links already
   carry a static border-bottom, and the ::after draws at bottom:-1px — i.e.
   exactly on top of it — so all it changed was the line's colour, 1px worth.
   The nudge is what actually reads as interactive, and it matches the
   announcement bar's arrow, which already moves on hover. The wipe stays as
   secondary polish, drawing full-strength currentColor over the muted
   --line border. */
.card-link {
  position: relative;
  transition: transform 260ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.card-link:hover,
.service-card:hover .card-link,
.service-card.is-linked-active .card-link,
a:focus-visible .card-link {
  transform: translateX(4px);
}

.card-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 380ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.card-link:hover::after,
.service-card:hover .card-link::after,
a:focus-visible .card-link::after {
  transform: scaleX(1);
}

/* Honour the OS-level reduced-motion setting across the whole site. Until
   now this was handled only inside js/venn.js, while the CSS transitions
   ignored it entirely. Reveals resolve to their final state rather than
   being disabled, so nothing is left invisible. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  .reveal-ready [data-reveal] {
    opacity: 1;
    transform: none;
  }
}

/* ==========================================================================
   Signature, intro animations
   ========================================================================== */

/* Gina's signature. Painted via mask like the logo mark and the line-art
   icons, so it takes the palette's ink colour instead of shipping as flat
   black on a coloured panel. Source scan was black-on-white; alpha was
   reconstructed from luminance. */
.signature {
  display: block;
  width: clamp(170px, 17vw, 220px);
  aspect-ratio: 720 / 176;
  margin-top: 6px;
  background-color: var(--ink);
  opacity: 0.85;
  -webkit-mask: url("../img/g-riley-sig.png") left center / contain no-repeat;
  mask: url("../img/g-riley-sig.png") left center / contain no-repeat;
}

/* --- page enter -----------------------------------------------------------
   Content fades and rises on load while the announcement bar, header and nav
   stay put, so the site's frame feels stable and only the page inside it
   changes. Both classes are added by an inline script in <head>: if scripting
   is off neither lands and nothing is ever hidden. */
.js-enter body > section {
  opacity: 0;
  transform: translateY(14px);
}

.js-enter.is-entered body > section {
  opacity: 1;
  transform: none;
  transition: opacity 700ms cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* --- announcement bar drop-in ---------------------------------------------
   First page of a session only (js/intro.js sets the sessionStorage flag).
   Translating rather than collapsing height means the bar's layout space is
   reserved from the start, so nothing below it shifts as it arrives. The
   overshoot in the easing is the bounce; z-index keeps it above the header
   during the few pixels it dips past its resting position. */
.is-first-visit .announce {
  transform: translateY(-100%);
  opacity: 0;
  z-index: 21;
}

.is-first-visit.announce-in .announce {
  transform: translateY(0);
  opacity: 1;
  transition: transform 760ms cubic-bezier(0.34, 1.56, 0.64, 1),
              opacity 320ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .js-enter body > section,
  .is-first-visit .announce {
    opacity: 1;
    transform: none;
  }
  /* The carousel still moves between slides — that is the control the user
     asked for — it just arrives instantly instead of sliding. */
  .carousel.is-enhanced .carousel-track { transition: none; }
  /* The wash still fades (opacity is not vestibular), but the label stops
     travelling to get there. */
  .photo-overlay-label { transform: none; transition: none; }
}

/* ==========================================================================
   Password gate — client-side only, first visit of the session.

   `.site-gate` sits as the first child of <body> on every page. The
   `gate-locked` class is added to <html> synchronously in an inline <head>
   script (before first paint) whenever sessionStorage has no record of a
   correct password yet this session, and removed by js/gate.js on success —
   so there's no flash of real content and no re-prompt on other pages once
   unlocked. When `gate-locked` isn't set, .site-gate stays display:none.
   ========================================================================== */

.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;
}

.site-gate {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 999;
  align-items: center;
  justify-content: center;
  /* Carries no background itself — the two halves below hold it, so they
     can part down the middle on unlock and open onto the site. */
  background: transparent;
}

html.gate-locked .site-gate { display: flex; }

/* The backdrop, in two halves. 50.5% each so their inner edges overlap by a
   hair: at exactly 50%, sub-pixel rounding on odd viewport widths leaves a
   1px seam of the page showing straight down the middle. */
.site-gate::before,
.site-gate::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 50.5%;
  background: #F2F2F2;
  z-index: -1;
  transition: transform 880ms cubic-bezier(0.76, 0, 0.24, 1) 200ms;
}

.site-gate::before { left: 0; }
.site-gate::after { right: 0; }

.site-gate.is-opening::before { transform: translateX(-100%); }
.site-gate.is-opening::after { transform: translateX(100%); }

/* The form clears out first, on the 200ms the panels wait before moving, so
   they part across an empty field rather than carrying the form off. */
.site-gate-panel,
.gate-notice {
  transition: opacity 260ms ease-out, transform 260ms ease-out;
}

.site-gate.is-opening .site-gate-panel { opacity: 0; transform: translateY(-16px); }
.site-gate.is-opening .gate-notice { opacity: 0; }

/* visibility rather than display:none. Both keep the page out of the
   accessibility tree and out of find-in-page, which was the point — but
   visibility can be handed back mid-animation, so the split opens onto the
   real site instead of a blank viewport. Layout no longer collapses while
   hidden, so the scroll is pinned separately. */
html.gate-locked body > *:not(.site-gate) { visibility: hidden; }
html.gate-locked { overflow: hidden; }
html.gate-opening body > *:not(.site-gate) { visibility: visible; }

/* Lifted above the two backdrop halves, which sit at z-index -1. */
.site-gate-panel {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 32px;
  width: 100%;
  max-width: 280px;
  padding: 40px;
  text-align: center;
}

.site-gate .gate-logo {
  display: block;
  width: 56px;
  height: 56px;
}

/* Pulled up out of the panel's own 32px gap so it reads as a caption sitting
   under the logo, not as a peer of equal weight to it or to the form below. */
.gate-tag {
  margin-top: -20px;
  font-family: var(--gate-sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.gate-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: 100%;
}

.gate-form input[type="password"] {
  font-family: var(--gate-sans);
  font-size: 14px;
  text-align: center;
  letter-spacing: 0.02em;
  padding: 14px 16px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink);
}

.gate-form input[type="password"]::placeholder { color: var(--ink-soft); }

.gate-form input[type="password"]:focus {
  outline: none;
  border-color: var(--accent);
}

.gate-form button {
  font-family: var(--gate-sans);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 500;
  padding: 14px 20px;
  background: #F8C0FF;
  border: 1px solid #F8C0FF;
  color: var(--ink);
  cursor: pointer;
  transition: background 200ms ease-out, border-color 200ms ease-out;
}

.gate-form button:hover { background: #f2a0ff; border-color: #f2a0ff; }

.gate-error {
  font-family: var(--gate-sans);
  font-size: 12px;
  color: var(--ink-soft);
}

.gate-help {
  font-family: var(--gate-sans);
  font-size: 12px;
  color: var(--ink-soft);
}

.gate-help a { text-decoration: underline; }

.gate-notice {
  position: absolute;
  z-index: 1;
  left: 20px;
  right: 20px;
  bottom: 28px;
  font-family: var(--gate-sans);
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-soft);
  text-align: center;
}
