/* The Birthing Doula — interactive states.
 *
 * In the design system every one of these is React useState: button hover, the
 * header's scrolled fill, the Services dropdown, the burger drawer. The pages are
 * server-rendered, so those effects never run and each state is frozen at its
 * default. This file re-expresses them as real CSS.
 *
 * Every value below is copied from the component source, not re-invented:
 *   header   SiteHeader   solidBg / padding / boxShadow on `solid`
 *   buttons  Button       the skin() branches on `lift`
 * The house ease and durations come from tokens/motion.css.
 */

/* ── header ─────────────────────────────────────────────────────────────── */

/* The overlay header must sit ON the hero, not above it in the flow.
 *
 * In the design, SiteHeader measures itself and pulls the next section up by its
 * own height (`marginBottom: -headerH`). That measurement runs in an effect which
 * server rendering never executes, so the header ends up occupying a band of its
 * own with the hero starting underneath.
 *
 * `position: sticky` cannot fix it either: the header lives inside an Elementor
 * HTML widget no taller than itself, so its sticky containing block gives it
 * nowhere to travel. Taking it out of flow solves both at once — the widget
 * collapses, the hero starts at the top of the page, and the header stays put.
 */
:root {
  /* One rest height for both header variants, and the offset every non-hero
     page starts below. Single source of truth so the two cannot drift. */
  --tbd-header-h: 91px;
  /* Scrolled, the header's padding drops from --space-4 to --space-3, 8px off
     each end. The bar is taller while transparent and tightens as it solidifies. */
  --tbd-header-h-scrolled: 75px;
  /* One duration for every part of the nav that moves — the header, the bar,
     the content offset and the page. They cover the same distance, so sharing a
     duration is what keeps them locked together; the header previously used
     --dur-base while the rest used 420ms, which drifted them by up to 54px. */
  --tbd-nav-dur: 420ms;
}

/* The page is pushed down by a transform rather than by padding. Padding moves
   layout; transform is composited, so the page slides on the GPU instead of
   relaying out an 8000px document sixty times a second. */
[data-tbd-pushed] {
  /* No CSS transition here: motion.js tweens this and the panel from one
     value, which is what keeps them from separating. */
  will-change: transform;
}

.tbd-hdr-wide,
.tbd-hdr-narrow {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
}

/* The desktop header measures 91px on its own; the phone one came out at 92px
   because its 44px burger is taller than the 27px logo. Pinning both removes
   the difference — and the height is animated, so the bar visibly tightens as
   it goes from transparent to solid. */
[data-tbd-header] {
  /* The bar's own rest height, which the scrolled state swaps out. Keeping it
     in a variable means the expanded height below is one expression rather
     than a second, competing rule. */
  --tbd-base-h: var(--tbd-header-h);

  /* The bar keeps its own height at all times. The menu is a fixed panel that
     slides out from behind it, so nothing here has to grow — animating this
     height meant relaying out the whole document every frame, which is what
     made the motion feel low-framerate. */
  height: var(--tbd-base-h);
  box-sizing: border-box;
}

[data-tbd-header].tbd-scrolled {
  --tbd-base-h: var(--tbd-header-h-scrolled);
}

/* The bar's height animates between 91px and 75px, but its contents were
   pinned to the top by padding-top, so the logo and the burger stayed at the
   same y in both states. At rest that left them 7.5px above the middle of the
   taller transparent bar — the expansion opened up empty space underneath them
   instead of around them.

   Centring the row in the box means its position is derived from the height,
   so the contents glide down as the bar grows and back up as it tightens, on
   the one height transition. The drawer is position:fixed and so out of flow;
   the row is the only in-flow child, which is what gets centred. */
[data-tbd-header] {
  display: flex !important;
  flex-direction: column !important;
  justify-content: center !important;
}

/* Centring the row cost it its width, which moved the logo off the left edge
   and the nav off the right. The row is `max-width: 1180px; margin: 0 auto`:
   as a block child it took the full 1180, but a flex item with auto margins in
   the cross axis has those margins absorb the free space, and `stretch` is
   then ignored — so it shrank to its content, 1119.6px, and sat centred.
   Giving it a width puts it back to 1180 and leaves the auto margins only the
   leftover to split, which is the layout the bar had before. */
[data-tbd-header] > div:not([data-tbd-drawer]) {
  width: 100% !important;
}

/* The header is out of flow, so on every page except home the first section
   would start underneath it. Home is exempt: its hero is meant to run under. */
[data-tbd-offset] section:first-of-type {
  padding-top: calc(var(--section-y) + var(--tbd-header-h)) !important;
}

/* The wrappers are swapped by the 1040px media query; keeping the fixed
   positioning above means neither one ever occupies layout space. */
@media (max-width: 1040px) {
  .tbd-hdr-wide {
    display: none;
  }
}

/* The overlay header sits transparent over the hero, then takes the
   deeper-right fill once the page has scrolled past 24px. */
[data-tbd-header].tbd-scrolled,
[data-tbd-header].tbd-nav-open {
  background: linear-gradient(
    90deg,
    var(--purple-500) 0%,
    var(--purple-500) 30%,
    var(--ink) 100%
  ) !important;
  box-shadow: 0 12px 30px -24px rgba(75, 48, 79, 0.6) !important;
}

[data-tbd-header].tbd-scrolled {
  padding: var(--space-3) var(--gutter) !important;
}

/* Height joins the transition so the bar tightens rather than snapping. The
   markup carries its own inline transition, which lists only background,
   padding and box-shadow — inline wins over a stylesheet, hence !important. */
[data-tbd-header] {
  transition:
    background var(--dur-base) var(--ease-calm),
    height var(--tbd-nav-dur) var(--ease-calm),
    padding var(--dur-base) var(--ease-calm),
    box-shadow var(--dur-base) var(--ease-calm) !important;
}

/* ── Services dropdown ──────────────────────────────────────────────────── */

/* The panel is rendered open so its markup exists, then closed here. It opens
   on hover and on keyboard focus, so it is reachable without a mouse. */
[data-tbd-menu] {
  /* The panel carries the stagger entrance as a CSS animation with fill `both`.
     An animation's value outranks a normal declaration, so it has to be cancelled
     before the opacity below can apply; the transition then does the fade. */
  animation: none !important;
  opacity: 0;
  visibility: hidden;
  transform: translate3d(0, -6px, 0);
  transition:
    opacity var(--dur-base) var(--ease-calm),
    transform var(--dur-base) var(--ease-calm),
    visibility 0s linear var(--dur-base);
}

[data-tbd-menu-wrap]:hover > [data-tbd-menu],
[data-tbd-menu-wrap]:focus-within > [data-tbd-menu],
[data-tbd-menu].tbd-open {
  opacity: 1;
  visibility: visible;
  transform: translate3d(0, 0, 0);
  transition-delay: 0s;
}

/* The bar is the wall the door goes up behind.
 *
 * The panel is a positioned child of the header, so it paints above the
 * header's own background — which left the retracting menu visible right across
 * the logo band. This is an opaque strip exactly one bar-height tall, sitting
 * above the panel and below the logo, so the menu disappears behind it as it
 * travels up. The shadow gives the strip its edge. */
[data-tbd-header]::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--tbd-base-h);
  z-index: 100;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(
    90deg,
    var(--purple-500) 0%,
    var(--purple-500) 30%,
    var(--ink) 100%
  );
  box-shadow: 0 8px 20px -6px rgba(34, 24, 38, 0.55);
  transition: opacity var(--tbd-nav-dur) var(--ease-calm);
}

/* Only while the menu is out; the closed bar stays transparent over the hero. */
[data-tbd-header].tbd-nav-open::before {
  opacity: 1;
}

/* Logo and burger ride above that strip. */
[data-tbd-header] > div:not([data-tbd-drawer]) {
  position: relative;
  z-index: 101;
}

/* The logo glides between left and centre as the menu opens and closes, on the
   same duration as everything else in the bar. */
[data-tbd-header] a:has(img) {
  transition: transform var(--tbd-nav-dur) var(--ease-calm);
}

/* ── the dropdown caret ─────────────────────────────────────────────────── */

/* The panel is force-rendered open so its markup exists, which also bakes the
   caret at rotate(180deg) — pointing up, as though already open. Put it back
   down at rest; it then rotates up when the menu opens, and a caret that moves
   reads as a control rather than as decoration. The brand has no icon set, so
   `▾` staying the only affordance keeps this inside the design language. */
[data-tbd-caret] {
  display: inline-block;
  transform: rotate(0deg) !important;
  transition: transform var(--dur-base) var(--ease-calm);
}

[data-tbd-menu-wrap]:hover > a > [data-tbd-caret],
[data-tbd-menu-wrap]:focus-within > a > [data-tbd-caret],
[aria-expanded="true"] > [data-tbd-caret] {
  transform: rotate(180deg) !important;
}

/* Items nudge 3px right and fill with linen on hover. */
[data-tbd-menu] a:hover {
  background: var(--linen);
  transform: translate3d(3px, 0, 0);
}

[data-tbd-menu] a {
  transition:
    background var(--dur-base) var(--ease-calm),
    transform var(--dur-base) var(--ease-calm);
}

/* ── buttons ────────────────────────────────────────────────────────────── */

/* Gold primary: lifts onto a softer, deeper shadow. The gold skin declares no
   transition of its own, so it is supplied here. */
[data-tbd-btn="gold"],
[data-tbd-btn="solid"] {
  transition:
    box-shadow 300ms var(--ease-calm),
    transform 300ms var(--ease-calm) !important;
}

[data-tbd-btn="gold"]:hover {
  box-shadow: 0 14px 30px rgba(75, 48, 79, 0.26) !important;
  transform: translateY(-2px) !important;
}

[data-tbd-btn="solid"]:hover {
  box-shadow: 0 14px 30px rgba(75, 48, 79, 0.28) !important;
  transform: translateY(-2px) !important;
}

/* Outline secondary: the purple fill sweeps in from the left and the ink
   flips to white. background-size is already 0% 100% at rest. */
[data-tbd-btn="outline"]:hover {
  background-size: 100% 100% !important;
  color: #ffffff !important;
  box-shadow: 0 14px 28px rgba(75, 48, 79, 0.22) !important;
  transform: translateY(-2px) !important;
}

/* Over a photograph the same sweep runs in --ink instead. */
[data-tbd-btn="onphoto"]:hover {
  background-size: 100% 100% !important;
  box-shadow: 0 14px 28px rgba(15, 10, 18, 0.38) !important;
  transform: translateY(-2px) !important;
}

/* Press is 1px, per motion.css. Applies to every variant. */
[data-tbd-btn]:active {
  transform: translateY(1px) !important;
}

/* Focus is a 2px purple-link ring at 3px offset — never removed, since this is
   the only affordance a keyboard user gets. */
[data-tbd-btn]:focus-visible {
  outline: 2px solid var(--purple-link);
  outline-offset: 3px;
}

/* ── the burger ─────────────────────────────────────────────────────────── */

/* Three gold rules and nothing else. The ring around it read as a stray UI
   chip against a design that has no other outlined controls, and 1px white
   hairlines were too faint to look deliberate. Gold matches the rules and
   dashes used everywhere else in the system, and it sits at the right-hand end
   of the bar where the fill is --ink, so it stays well clear on contrast. */
[data-tbd-burger] {
  border: none !important;
  border-radius: 0 !important;
  transition: transform var(--tbd-nav-dur) var(--ease-calm);
}

[data-tbd-burger] i {
  width: 20px !important;
  height: 2px !important;
  background: var(--gold-400) !important;
  border-radius: 1px;
  transition:
    transform var(--tbd-nav-dur) var(--ease-calm),
    opacity 180ms var(--ease-calm);
}

/* Open: the whole mark turns a half-circle while the outer rules close into a
   cross and the middle one goes. Closing runs the rotation back to zero, which
   unwinds the other way. */
[data-tbd-burger][aria-expanded="true"] {
  transform: rotate(180deg);
}

/* The rules sit 7px apart — 2px tall with a 5px gap — so that is how far the
   outer two travel to meet in the middle. */
[data-tbd-burger][aria-expanded="true"] i:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

[data-tbd-burger][aria-expanded="true"] i:nth-child(2) {
  opacity: 0;
  transform: scaleX(0);
}

[data-tbd-burger][aria-expanded="true"] i:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* ── centring the logo lockup on the row ────────────────────────────────── */

/* Two separate things pushed the lockup up, and both read as "a padding at the
   bottom of the logo".

   1. The anchor is an inline-block with line-height 24px, and the artwork span
      inside it is vertical-align:baseline — so the line box reserved 6.5px of
      descender space underneath the artwork. The anchor itself was centred on
      the row correctly, but the artwork sat at the top of it, leaving the
      whole logo 2.2px above the centre the burger sits on.

   2. logo-wordmark-gold.png is 1600x141, but the capitals stop at row 112.2;
      the strip below them carries the three small diamonds. Centring the
      canvas centres the diamonds too, so the word itself reads high. The cap
      band's centre is 56.09/141 of the image, not 0.5.

   Making the anchor a flex container drops the descender, so it is the artwork
   that gets centred rather than a box with dead space under it. The symbol's
   own margin-top has to go with it, or it would push the spiral back off the
   centre by half its value. The wordmark then keeps a nudge of

       margin-top = 0.2044 x height,  0.2044 = 2 x (0.5 - 56.09/141)

   the factor of two being because align-items:center re-centres the margin
   box, so the content moves only half as far as the margin changes.

   a[aria-label] is the logo link: it is the only anchor carrying one in either
   header, on every page and in all three languages. */
[data-tbd-header] a[aria-label] {
  display: inline-flex !important;
  align-items: center !important;
}

[data-tbd-header] a[aria-label] img[src*="logo-symbol"] {
  margin-top: 0 !important;
}

[data-tbd-header] a[aria-label] img[src*="logo-wordmark"] {
  /* 0.2044 x 17.176 */
  margin-top: 3.511px !important;
}

/* ── the logo, on a phone ───────────────────────────────────────────────── */

/* A larger mark without a taller bar. The header's height is pinned, so the
   room comes from its vertical padding: 24px each side left only a 43px box for
   a 35.6px logo. At 16px the box is 59px, which carries the bigger mark with
   clearance to spare — and still clears the 75px scrolled bar. */
@media (max-width: 1040px) {
  .tbd-hdr-narrow [data-tbd-header] {
    padding-top: var(--space-3) !important;
    padding-bottom: var(--space-3) !important;
  }

  .tbd-hdr-narrow [data-tbd-header] img[src*="logo-symbol"] {
    height: 34px !important;
    width: 34px !important;
  }

  /* a[aria-label] is carried here only to outrank the unscoped rule above,
     which would otherwise win on specificity and impose the desktop nudge. */
  .tbd-hdr-narrow [data-tbd-header] a[aria-label] img[src*="logo-wordmark"] {
    height: 17px !important;
    width: auto !important;
    /* 0.2044 x 17 — the phone logo is enlarged, so the nudge is rescaled */
    margin-top: 3.475px !important;
  }
}

/* ── the arc under the hero, turned over ────────────────────────────────── */

/* The arc was never drawn by the hero. The section below it carries

       border-radius: 50% 50% 0 0 / var(--arc-rise-sm) ... ;
       margin-top: calc(-1 * var(--arc-rise-sm));

   so the cream pulls itself 40px up into the hero and its own top corners are
   rounded away, leaving a dome that rises into the photograph.

   Turning the arc over means moving it to the other element: the hero takes a
   matching curve on its bottom corners and is lifted above the cream, so the
   dark ground bulges down instead. The cream keeps its negative margin and its
   compensating padding, so nothing below moves and no height changes — the
   overlap is the same 40px, just owned by the other side of the line. At the
   left and right edges the cream's flat top is still under the hero's cut
   corners, so the join stays sealed.

   The hero comes first in the document, so without a z-index the cream, being
   later, would paint over the curve. The fixed bar sits at z-index 40 and is
   unaffected. */
/* Both sections carry their border-radius inline, so these have to be marked
   important to reach them at all. */
[data-tbd-hero] {
  border-radius: 0 0 50% 50% / 0 0 var(--arc-rise-sm) var(--arc-rise-sm) !important;
  z-index: 1;
}

[data-tbd-hero] + section {
  border-radius: 0 !important;
}

/* ── the hero, on a phone ───────────────────────────────────────────────── */

/* The hero was pinned to 900px, taller than the phone screen itself. At that
   height the frame is so narrow that cover shows only 56% of the photograph's
   width — and the two faces in it sit about 80% of the width apart, so one of
   them was always cropped out. It was Lina's: all that survived on the right
   was her hand on the belly.

   Letting the height follow the content settles it at roughly 693px, which
   shows 73% of the width and holds both faces. Content-driven rather than a
   fixed number on purpose: a narrower phone wraps the heading onto another
   line, and a fixed height would clip it. Desktop keeps the 900px hero. */
@media (max-width: 1040px) {
  [data-tbd-hero] {
    height: auto !important;
    min-height: 0 !important;
  }

  /* Ships as 0% — hard against the left edge, which is what cut Lina out. */
  [data-tbd-hero] > img {
    object-position: 60% 42% !important;
  }
}

/* ── framing the service photographs ────────────────────────────────────── */

/* The photographs that shipped with the design were pre-cropped to 760x570,
   and cropped tightly enough that the subject was gone: the postpartum frame
   held Lina's face with only the crown of the baby's head at the very bottom
   edge, the rebozo frame stopped just above the belly, and the labour frame
   cut off at the hand on the client's back. Nothing could be recovered by
   moving the crop, so the full originals replace them.

   They are portrait, roughly 3:4, sitting in a landscape cell — 720x520 on
   desktop, 390x320 on a phone — so only about half of each frame's height is
   ever on screen, and which half has to be chosen deliberately. That is the
   second value of object-position: it lines that point of the photograph up
   with the same point of the cell, so one value holds at both sizes. */
img[src*="service-labour-full"] {
  /* the hand resting on the small of her back, rather than the ceiling */
  object-position: center 70%;
}

img[src*="service-postpartum-full"] {
  /* the newborn is the subject; she stays in frame from the mouth down */
  object-position: center 85%;
}

img[src*="service-rebozo-full"] {
  /* far enough down that the belly, not just the cloth, is in the frame */
  object-position: center 85%;
}

/* ── the phone review deck ──────────────────────────────────────────────── */

/* A swipeable paper stack, ported from the prototype. Geometry, timings,
   easing curves and transforms are the prototype's — only the palette and the
   typefaces are swapped for the site's own tokens, so it reads as part of this
   site rather than a bolted-on widget.

   Phone only. Above 768px the horizontal rail stays exactly as it is. */
[data-tbd-deck] { display: none; }

@media (max-width: 767.98px) {
  [data-tbd-deck] { display: block; }
  /* the rail is the no-JavaScript fallback; once the deck exists it goes */
  [data-tbd-deck] ~ [data-tbd-rev-rail],
  [data-tbd-rev-rail].tbd-rail-replaced { display: none; }
}

.tbd-stage {
  position: relative;
  height: 516px;   /* card bottom 484 + the back sheet 30 = 514; no dead space */
  margin: 20px 0 10px;
  touch-action: pan-y;          /* vertical page scrolling is never trapped */
}

.tbd-rcard {
  position: absolute;
  left: 10px; right: 10px; top: 74px;
  height: 410px;
  padding: 72px 22px 16px;
  gap: 8px;
  border: 1px solid var(--border-hairline);
  border-radius: 30px;
  background: var(--shell);
  box-shadow: var(--shadow-raised);
  display: flex;
  flex-direction: column;
  transform-origin: center bottom;
  will-change: transform, opacity;
  transition: transform .52s cubic-bezier(.18,.82,.24,1.08), opacity .34s ease;
}

/* Only the active paper is perfectly straight; the two behind it keep the
   random tilt and offset they were dealt when they joined the stack. All three
   are fully opaque — they are sheets of paper, so you never see one through
   another; only their offset edges show. */
.tbd-rcard[data-depth="0"] { z-index: 3; transform: translateX(0) translateY(0) rotate(0deg) scale(1); opacity: 1; touch-action: pan-y; }
.tbd-rcard[data-depth="1"] { z-index: 2; transform: translateX(var(--paper-x,0px)) translateY(15px) rotate(var(--paper-tilt,0deg)) scale(.965); opacity: 1; }
.tbd-rcard[data-depth="2"] { z-index: 1; transform: translateX(var(--paper-x,0px)) translateY(30px) rotate(var(--paper-tilt,0deg)) scale(.93); opacity: 1; }

/* The two sheets behind are blank paper. The prototype could leave their
   content showing because they were translucent; opaque, a second portrait and
   a second set of quote marks poke out from behind the top card. Only depths 1
   and 2 are blanked -- a card flying out keeps its content all the way off. */
.tbd-rcard[data-depth="1"] > *,
.tbd-rcard[data-depth="2"] > * { opacity: 0; transition: opacity .18s ease; }

.tbd-rcard.entering[data-depth="2"] { transform: translateX(125%) translateY(30px) rotate(calc(var(--paper-tilt,0deg) + 8deg)) scale(.93); opacity: 0; }
.tbd-rcard.entering[data-depth="1"] { transform: translateX(135%) translateY(15px) rotate(calc(var(--paper-tilt,0deg) + 7deg)) scale(.965); opacity: 0; }
.tbd-rcard.entering[data-depth="0"] { transform: translateX(145%) rotate(7deg); opacity: 0; }
.tbd-rcard.incoming-back { z-index: 0 !important; transform: translateX(128%) translateY(30px) rotate(calc(var(--paper-tilt,0deg) + 8deg)) scale(.93) !important; opacity: 0 !important; }
.tbd-rcard.incoming-previous[data-depth="0"] { z-index: 4 !important; transform: translateX(-118%) translateY(0) rotate(-7deg) scale(1) !important; opacity: 0 !important; }

/* The portrait: one circle, overlapping the card's top edge. No ring, no
   plate, no shadow — the initial on its own colour is the whole element, the
   way Google draws a reviewer with no photo. */
.tbd-rav {
  position: absolute;
  top: -58px; left: 50%;
  transform: translateX(-50%);
  width: 116px; height: 116px;
  border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: 44px;
  line-height: 1;
  color: #FFFFFF;
  border: 0; box-shadow: none; background-clip: padding-box;
  pointer-events: none;
  user-select: none;
}

.tbd-rname {
  font-family: var(--font-display);
  font-size: 20px; line-height: 1.1; text-align: center;
  margin: 0; color: var(--text-heading);
}

.tbd-trust { display: flex; align-items: center; justify-content: center; gap: 10px;
             margin: 0; flex-wrap: wrap; }
.tbd-stars { display: flex; gap: 2px; line-height: 1; }
.tbd-gr { display: inline-flex; align-items: center; gap: 5px; font-size: 12px;
          color: var(--text-muted); white-space: nowrap; }
.tbd-gr svg { width: 15px; height: 15px; display: block; flex: 0 0 15px; }

.tbd-chips { display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; margin: 0; }
.tbd-chip { display: inline-flex; align-items: center; justify-content: center;
            min-height: 32px; padding: 6px 12px; border-radius: var(--radius-pill);
            background: var(--cream); color: var(--ink-soft);
            border: 1px solid var(--border-hairline);
            font-size: 12px; line-height: 1.2; text-align: center; }

.tbd-qshell { position: relative; flex: 1; margin: 0; padding: 0 12px;
              display: flex; align-items: center; justify-content: center; min-height: 0; }
.tbd-quote { font-family: var(--font-display); font-size: 21px; line-height: 1.36;
             text-align: center; margin: 0; color: var(--ink-soft);
             display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical;
             overflow: hidden; }
/* The marks belong to the sentence, not to the card: inline, so the opening
   one sits against the first word and the closing one against the last,
   wherever the text happens to end. line-height:0 stops a 72px glyph from
   inflating the line box, so the six-line clamp still measures true. */
.tbd-qmark { display: inline; color: var(--purple-500); font-family: var(--font-display);
             font-size: 72px; line-height: 0; vertical-align: -0.45em;
             /* -0.45em, not less: the clamp on .tbd-quote is overflow:hidden,
                and at -0.34em the opening mark's box sat 5px above the box and
                had its top sliced off, which is why it read smaller than the
                closing one. The glyphs are identical; one was being cut. */
             pointer-events: none; opacity: .5; }
.tbd-qmark.open { margin-right: 2px; }
.tbd-qmark.close { margin-left: 2px; }

.tbd-readfull { align-self: center; border: 0; background: transparent; padding: 8px 0;
                min-height: 44px; font-family: var(--font-body); font-size: 13px;
                font-weight: var(--weight-body-strong); color: var(--gold-text);
                text-decoration: underline; text-underline-offset: 4px; cursor: pointer;
                transition: opacity .18s ease; touch-action: pan-y;
                user-select: none; -webkit-user-select: none; }
.tbd-rcard:not([data-depth="0"]) .tbd-readfull { opacity: 0; pointer-events: none; }
.tbd-rcard[data-depth="0"] .tbd-readfull { opacity: 1; pointer-events: auto; }

/* one row: arrow · dots · arrow, all on the same centre line */
.tbd-deck-nav { display: flex; align-items: center; justify-content: center;
                gap: 14px; margin-top: 2px; }
/* The outline skin, copied from the SSR secondary button: white at rest with a
   purple arrow, and the purple sweeps in from the left on press. Hover, press
   and focus are NOT defined here -- data-tbd-btn="outline" on the element picks
   those up from the brand button rules above, so the arrow flips to white with
   the fill because the SVG is stroked in currentColor. */
.tbd-deck-nav button { width: 44px; height: 44px; flex: 0 0 44px; display: grid;
                       place-items: center; cursor: pointer; padding: 0;
                       border: 1px solid var(--dusty-200) !important;
                       border-radius: var(--radius-pill);
                       background-image: linear-gradient(90deg, var(--purple-500) 0%, var(--purple-link) 100%);
                       background-size: 0% 100%; background-repeat: no-repeat;
                       background-color: var(--surface-card-light);
                       box-shadow: 0 4px 12px rgba(75,48,79,.10);
                       color: var(--purple-link);
                       transition: background-size 420ms var(--ease-calm),
                                   color 240ms var(--ease-calm),
                                   box-shadow 300ms var(--ease-calm),
                                   transform 300ms var(--ease-calm); }
.tbd-dots { display: flex; align-items: center; gap: 6px; min-height: 18px; }
.tbd-dot { width: 5px; height: 5px; border-radius: var(--radius-pill);
           background: var(--dusty-300); opacity: .72; flex: 0 0 auto;
           transition: width .28s cubic-bezier(.2,.8,.2,1),
                       height .28s cubic-bezier(.2,.8,.2,1), opacity .2s ease; }
.tbd-dot.active { width: 20px; height: 6px; background: var(--purple-link); opacity: 1; }

.tbd-hint { position: absolute; z-index: 8; left: 50%; bottom: 6px;   /* clear of Read full review, which ends 468px down */
            transform: translateX(-50%); opacity: 0; pointer-events: none;
            border: 1px solid var(--border-hairline); background: rgba(252,250,248,.96);
            border-radius: var(--radius-pill); padding: 8px 12px; font-size: 12px;
            color: var(--text-muted); box-shadow: var(--shadow-soft); white-space: nowrap; }
.tbd-hint.play { animation: tbdHint 2.3s ease forwards; }
/* Saying "swipe" is weaker than showing it: once the stack has landed the top
   card leans left and returns, so the gesture is demonstrated, not described. */
.tbd-rcard[data-depth="0"].tbd-demo-swipe {
  animation: tbdCardHint 2.3s cubic-bezier(.4,0,.2,1) forwards; }
@keyframes tbdHint { 0%,8% { opacity: 0 } 18%,72% { opacity: 1 } 90%,100% { opacity: 0 } }
@keyframes tbdCardHint { 0%,18% { transform: translateX(0) rotate(0) }
  52% { transform: translateX(-36px) rotate(-2.5deg) }
  72%,100% { transform: translateX(0) rotate(0) } }

/* the full review, in a short box that scrolls inside itself */
.tbd-modal { position: fixed; inset: 0; z-index: 1000; display: none;
             align-items: center; justify-content: center; padding: 18px;
             background: rgba(75,48,79,.45); }
.tbd-modal.open { display: flex; }
.tbd-dialog { width: min(100%,390px); height: clamp(410px,62dvh,520px);
              max-height: calc(100dvh - 76px); background: var(--shell);
              border: 1px solid var(--border-hairline); border-radius: 30px;
              box-shadow: 0 30px 80px rgba(34,24,38,.34); overflow: hidden;
              display: flex; flex-direction: column;
              animation: tbdModalIn .28s cubic-bezier(.2,.8,.2,1); }
@keyframes tbdModalIn { from { transform: translateY(15px) scale(.97); opacity: 0 }
                        to { transform: none; opacity: 1 } }
.tbd-mhead { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between;
             gap: 12px; padding: 15px 17px; border-bottom: 1px solid var(--border-hairline); }
.tbd-mkick { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-muted); }
/* The WordPress theme paints every <button> dark grey, and its `button:hover`
   selector scores (0,1,1) -- higher than a bare class -- so the close control
   turned into a dark box under the pointer. The brand's own button variants
   already carry !important for exactly this reason; these two need it too.

   The X wears the same outline skin as the deck arrows and carries
   data-tbd-btn="outline", so its hover sweep, 1px press and purple focus ring
   all come from the brand rules rather than being redefined here. */
.tbd-mx { width: 44px; height: 44px; flex: 0 0 44px; padding: 0;
          display: grid; place-items: center; cursor: pointer;
          border: 1px solid var(--dusty-200) !important;
          border-radius: 50%;
          background-image: linear-gradient(90deg, var(--purple-500) 0%, var(--purple-link) 100%) !important;
          background-size: 0% 100%; background-repeat: no-repeat;
          background-color: var(--surface-card-light) !important;
          color: var(--purple-link) !important;
          box-shadow: 0 4px 12px rgba(75,48,79,.10);
          transition: background-size 420ms var(--ease-calm),
                      color 240ms var(--ease-calm),
                      box-shadow 300ms var(--ease-calm),
                      transform 300ms var(--ease-calm); }
.tbd-mx:hover { color: #FFFFFF !important; }
.tbd-mbody { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden;
             -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
             touch-action: pan-y; padding: 22px 22px 30px; scrollbar-width: thin; }
.tbd-mbody::-webkit-scrollbar { width: 5px }
.tbd-mbody::-webkit-scrollbar-thumb { background: var(--border-hairline); border-radius: 99px }
.tbd-mstars { display: flex; gap: 3px; margin-bottom: 18px; }
.tbd-mquote { font-family: var(--font-display); font-size: 20px; line-height: 1.52;
              margin: 0; color: var(--ink); }
.tbd-mlang { margin-top: 16px; font-size: 12px; color: var(--text-muted); }
.tbd-mfoot { flex: 0 0 auto; display: flex; align-items: center; gap: 12px;
             padding: 12px 14px calc(12px + env(safe-area-inset-bottom,0px));
             border-top: 1px solid var(--border-hairline); }
.tbd-mwho { display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1; }
.tbd-mav { width: 40px; height: 40px; flex: 0 0 40px; border-radius: 50%; display: grid;
           place-items: center; color: #fff; font-family: var(--font-display); font-size: 16px; }
.tbd-mname { font-size: 14px; font-weight: var(--weight-body-strong); color: var(--ink); }
.tbd-mmeta { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.tbd-mclose { flex: 0 0 auto; min-width: 92px; min-height: 48px; border: 0;
              border-radius: var(--radius-pill); background: var(--purple-link);
              color: #FFFFFF; padding: 0 20px; font-family: var(--font-body);
              font-weight: var(--weight-body-strong); cursor: pointer;
              touch-action: manipulation; box-shadow: var(--shadow-soft); }
.tbd-mclose:active { transform: translateY(1px); }
/* same theme override, so the footer button keeps its purple under the pointer */
.tbd-mclose { background: var(--purple-link) !important; color: #FFFFFF !important; }
.tbd-mclose:hover { background: var(--purple-500) !important;
                    box-shadow: 0 14px 30px rgba(75,48,79,.26); }
.tbd-mx:focus-visible, .tbd-mclose:focus-visible {
  outline: 2px solid var(--purple-link); outline-offset: 3px; }
body.tbd-modal-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .tbd-rcard { transition: none !important; }
  .tbd-rcard.entering { transform: none !important; opacity: 1 !important; }
  .tbd-hint, .tbd-dialog, .tbd-rcard.tbd-demo-swipe { animation: none !important; }
}

/* ── the review rail ────────────────────────────────────────────────────── */

/* Phone: three cards, stacked, nothing else on screen. Desktop: a rail that
   scrolls sideways with about five in view, so fourteen reviews cost the page
   one band instead of fourteen. Most relevant first in both.

   Pressing a card opens it; the full review then scrolls inside the card, so a
   300-word review never stretches the section. */
[data-tbd-rev-rail] {
  display: grid;
  gap: var(--space-4);
}

/* the full text is hidden until the card is opened */
[data-tbd-rev-full] {
  display: none;
  max-height: 260px;
  overflow-y: auto;
  padding-right: var(--space-3);
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

[data-tbd-rev][data-open] [data-tbd-rev-full] {
  display: block;
}

[data-tbd-rev][data-open] [data-tbd-rev-quote] {
  /* the pull quote stays, but steps back once the whole review is showing */
  font-size: var(--text-body-lg);
  color: var(--text-heading);
}

[data-tbd-rev-open] {
  -webkit-appearance: none;
  appearance: none;
  transition: box-shadow var(--dur-base) var(--ease-calm),
              transform var(--dur-base) var(--ease-calm);
}

[data-tbd-rev-open]:hover {
  box-shadow: var(--shadow-soft);
}

[data-tbd-rev-open]:focus-visible {
  outline: 2px solid var(--gold-400);
  outline-offset: 3px;
}

/* "Read the full review" / "Close", written by motion.js so the label always
   matches what pressing will do. */
[data-tbd-rev-more]:not(:empty)::before {
  content: "";
}

[data-tbd-rev-more] {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Phone — three, stacked, and that is all. */
@media (max-width: 767.98px) {
  [data-tbd-rev-rail] > [data-tbd-rev]:nth-child(n + 4) {
    display: none;
  }
}

/* Desktop — a horizontal rail, roughly five in view. */
@media (min-width: 768px) {
  [data-tbd-rev-rail] {
    grid-auto-flow: column;
    grid-auto-columns: minmax(280px, 1fr);
    overflow-x: auto;
    scroll-snap-type: x proximity;
    padding-bottom: var(--space-4);
    scrollbar-width: thin;
  }

  [data-tbd-rev] {
    scroll-snap-align: start;
  }

  [data-tbd-rev-open] {
    height: 100%;
  }
}

/* Five across on a wide screen. No minimum width here on purpose: a floor
   would win over the division and leave three and a bit in view. The cards
   are narrow by design — they carry one line until they are opened. */
@media (min-width: 1200px) {
  [data-tbd-rev-rail] {
    grid-auto-columns: calc((100% - 4 * var(--space-4)) / 5);
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-tbd-rev-rail] { scroll-behavior: auto; }
  [data-tbd-rev-open] { transition: none; }
}

/* ── the question accordion ─────────────────────────────────────────────── */

/* Fifteen questions open at once is a very long page, so each answer is folded
   away and one opens at a time. The panel is animated with grid-template-rows
   rather than max-height: the grid resolves the real height itself, so there is
   no guessed pixel value to be wrong and no jump at the end of the travel.

   The question is a real <button> so it is focusable and announced as
   expandable; the styling below only removes the button chrome, because the
   heading around it already carries the type. */
[data-tbd-acc-q] {
  -webkit-appearance: none;
  appearance: none;
}

[data-tbd-acc-q]:hover [data-tbd-acc-icon],
[data-tbd-acc-q]:focus-visible [data-tbd-acc-icon] {
  border-color: var(--text-heading);
}

[data-tbd-acc-q]:focus-visible {
  outline: 2px solid var(--gold-400);
  outline-offset: 4px;
  border-radius: 2px;
}

/* The chevron: two borders on a rotated square, the same device the nav caret
   uses, so the two read as one family. */
[data-tbd-acc-icon] {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  margin-top: 0.35em;
  border-right: 1.5px solid var(--rule-decorative);
  border-bottom: 1.5px solid var(--rule-decorative);
  transform: rotate(45deg);
  transform-origin: center;
  transition: transform var(--dur-base) var(--ease-calm),
              border-color var(--dur-base) var(--ease-calm);
}

[data-tbd-acc][data-open] [data-tbd-acc-icon] {
  transform: rotate(-135deg);
}

[data-tbd-acc-panel] {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-base) var(--ease-calm),
              opacity var(--dur-base) var(--ease-calm);
  opacity: 0;
}

[data-tbd-acc-panel] > * {
  overflow: hidden;
  min-height: 0;
}

[data-tbd-acc][data-open] > [data-tbd-acc-panel] {
  grid-template-rows: 1fr;
  opacity: 1;
}

/* Without JavaScript every answer simply stays open and readable. */
.no-js [data-tbd-acc-panel] {
  grid-template-rows: 1fr;
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  [data-tbd-acc-panel],
  [data-tbd-acc-icon] {
    transition: none;
  }
}

/* ── the blue box on tap ─────────────────────────────────────────────────── */

/* Touch browsers paint a translucent rectangle over whatever you press:
   -webkit-tap-highlight-color, which defaults to rgba(0, 0, 0, 0.18) and is
   tinted blue on Android. It is drawn in the element's own coordinate space,
   so it rotated along with the burger, and it takes the whole box rather than
   the pill's rounded edge — which is why it read as a stray blue square
   sitting on top rather than as press feedback. A mouse never triggers it,
   which is why only the phone showed it.

   Nothing is lost by turning it off: the burger spins into its cross, and the
   buttons carry fills that a touch triggers too, so every control still
   answers a press. The property inherits, so the root covers the document;
   the list below is for the controls iOS Safari does not inherit it on. */
html {
  -webkit-tap-highlight-color: transparent;
}

a,
button,
summary,
[role="button"],
[data-tbd-btn],
[data-tbd-burger] {
  -webkit-tap-highlight-color: transparent;
}

/* A press that drifts a little selects the label instead of pressing it, and
   the selection leaves its own blue wash behind. Controls are not text to be
   read, so they opt out; body copy stays selectable. */
[data-tbd-header] a,
[data-tbd-header] button,
[data-tbd-footer] a,
[data-tbd-btn] {
  -webkit-user-select: none;
  user-select: none;
}

/* ── the expanding nav, on a phone ───────────────────────────────────────── */

/* The menu is a fixed panel that slides down from behind the bar, carrying the
   bar's own fill so the two read as one surface. Being fixed takes it out of
   flow, so the header never changes height and nothing here costs a relayout —
   the panel and the page both move on `transform` alone. */
[data-tbd-drawer] {
  display: block !important;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 99;
  box-sizing: border-box;

  /* The top of the panel sits behind the bar, so its fill continues seamlessly
     out of the header rather than starting below it. */
  /* !important because the panel ships an inline padding of --space-4, which
     otherwise wins and tucks the top of the menu behind the bar. */
  padding: var(--tbd-base-h) 0 var(--space-5) !important;
  background: linear-gradient(
    90deg,
    var(--purple-500) 0%,
    var(--purple-500) 30%,
    var(--ink) 100%
  ) !important;
  border-radius: 0 !important;
  border-top: none !important;
  margin: 0 !important;
  max-width: none !important;
  text-align: center;

  /* Taller than the screen, the panel scrolls itself — and `contain` stops that
     scroll ever chaining through to the page behind it. */
  max-height: 100vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;

  transform: translateY(-100%);
  /* Only the first-paint state. Visibility is handed to motion.js from then on:
     a CSS delay cannot survive the inline `transition: none` the tween needs,
     and without the delay the panel blanks out in one frame while its box is
     still animating — which looked like the menu vanishing and the page
     sliding up behind it. */
  visibility: hidden;
  will-change: transform;
}



/* While a finger is dragging the panel it must track the finger exactly, so
   every transition is suspended for the duration of the gesture. */
html.tbd-dragging [data-tbd-drawer],
html.tbd-dragging [data-tbd-pushed] {
  transition: none !important;
}

/* With the menu open the page behind it does not scroll at all; a scroll
   gesture closes the menu instead. This is the standard mobile-menu behaviour
   and stops the page drifting underneath an open panel. */
.tbd-drawer-inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  align-items: center;
}

.tbd-drawer-inner > nav {
  padding-top: var(--space-4);
}

/* Every row on its own line, centred: the links, the call to action and the
   language switcher. The CTA row ships as justify-content:space-between, which
   is what pushed the button left and the languages right. */
[data-tbd-drawer] nav {
  align-items: center !important;
  gap: var(--space-4) !important;
}

/* Only the row that holds the call to action and the languages stacks; the
   previous selector was broad enough to catch the language group itself, which
   is why FR / EN / ES ended up one above the other. */
.tbd-drawer-inner > div:last-child {
  flex-direction: column !important;
  align-items: center !important;
  justify-content: center !important;
  gap: var(--space-4) !important;
}

/* The three languages read as one switch, so they stay side by side. */
.tbd-drawer-inner > div:last-child > div {
  flex-direction: row !important;
  align-items: center !important;
  justify-content: center !important;
  gap: var(--space-2) !important;
}

/* Services reads as a control rather than a link: a pill with the caret inside
   it, using the brand's own pill radius and hairline rather than a new glyph. */
[data-tbd-drawer] a[aria-haspopup] {
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 9px 20px !important;
  border: 1px solid rgba(255, 255, 255, 0.28) !important;
  border-radius: var(--radius-pill) !important;
  transition: background var(--dur-base) var(--ease-calm);
}

[data-tbd-drawer] a[aria-haspopup][aria-expanded="true"] {
  background: rgba(255, 255, 255, 0.1) !important;
}

[data-tbd-drawer] a[aria-haspopup] [data-tbd-caret] {
  font-size: 13px !important;
}

/* The submenu's own top margin and padding are zeroed while collapsed, which is
   what showed up as a gap between Services and About me. */
[data-tbd-drawer] [data-tbd-menu] {
  position: static !important;
  min-width: 0 !important;
  box-shadow: none !important;
  border: none !important;
  background: transparent !important;
  align-items: center !important;
  margin: 0 !important;
  padding: 0 !important;
  overflow: hidden;
  opacity: 1;
  box-sizing: border-box;
  /* No transition: motion.js tweens this height together with the page push,
     for the same reason the panel does. Animating it here left the bar growing
     while the page stood still, opening a 148px overlap that snapped shut when
     a timer caught up. */
  height: 0;
}

[data-tbd-drawer] [data-tbd-menu].tbd-open {
  visibility: visible;
}

/* The breathing room under Services sits on the first item, not on the submenu
   itself. As padding on the submenu it could not be tweened: under border-box a
   height of 0 still floors at the padding, so the box jumped 16px before the
   tween had written anything. On a child it is simply part of the measured
   content height. */
[data-tbd-drawer] [data-tbd-menu] > *:first-child {
  margin-top: var(--space-3);
}

/* ── footer, on a phone ─────────────────────────────────────────────────── */

/* The columns stack under 1040px and read better centred with the lockup. */
@media (max-width: 1040px) {
  [data-tbd-footer] {
    text-align: center;
  }

  [data-tbd-footer] > div,
  [data-tbd-footer] > div > div {
    justify-items: center;
    justify-content: center;
  }

  [data-tbd-footer] ul,
  [data-tbd-footer] li {
    list-style: none;
    padding-left: 0;
    text-align: center;
  }

  /* The fine-print row carries an inline justify-content:space-between, which
     outranks a plain rule — hence !important rather than specificity games. */
  [data-tbd-footer] > div:last-child {
    justify-content: center !important;
    text-align: center !important;
  }

  /* "The practice" is the third of the four column blocks. Hidden on phone only
     to keep the footer short; matched by position rather than by its heading,
     which would differ in French and Spanish. */
  /* The footer's first child is a decorative <i>, so the grid is not
     :first-child — target it by its own class instead. */
  [data-tbd-footer] .tbd-footer-grid > div:nth-child(3) {
    display: none !important;
  }
}

/* ── the story section, on a phone ──────────────────────────────────────── */

/* The heading is centred; under 1040px the body and the button follow it. */
@media (max-width: 1040px) {
  #story-intro p,
  #story-intro .tbd-split > div {
    text-align: center;
  }

  /* The paragraphs are capped at 46ch and 52ch, so centring the text is not
     enough — the boxes themselves have to be centred too. */
  #story-intro p {
    margin-left: auto !important;
    margin-right: auto !important;
  }
}

/* ── decorative imagery ─────────────────────────────────────────────────── */

/* The oversized spiral is sized in px inline. WordPress themes ship
   img{max-width:100%}, which clamps its width on a phone while the inline
   height still applies, squeezing the mark. The artwork is never distorted. */
[aria-hidden="true"] img,
[data-tbd-drift] img {
  max-width: none !important;
  max-height: none !important;
}

/* ── reduced motion ─────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  [data-tbd-header],
  [data-tbd-menu],
  [data-tbd-menu] a,
  [data-tbd-btn] {
    transition: none !important;
  }

  [data-tbd-btn]:hover {
    transform: none !important;
  }
}

/* ── "What I offer" rows, once stacked ──────────────────────────────────── */

/* The rows alternate by design: even rows put the photograph in the left
   column, odd rows in the right, and each slides in from the side it sits on.
   That is correct on desktop and is left alone.
   Below 600px the grid collapses to one column — `repeat(auto-fit,
   minmax(300px, 1fr))` fits two columns at exactly 600px and above — and DOM
   order then decides the stacking, so the odd rows stacked heading, button,
   image. Ordering the photograph first makes every row lead with its image
   without touching the markup or the desktop layout. */
@media (max-width: 599.98px) {
  [data-tbd-srow] > img {
    order: -1;
  }
}

/* The design system sets the section intro inline at --text-lead (19px), which
   wraps to two lines on a phone. --text-body is the brand's own next size down,
   so the wording stays and the line does not break. */
[data-tbd-rev-head] p { font-size: var(--text-body) !important; }

/* ── the desktop coverflow ───────────────────────────────────────────────── */

/* Above 768px the rail gives way to the camera-roll layout: one review straight
   and forward, its neighbours receding on a 1500px perspective. The card's
   content classes are shared with the phone deck so the two read identically;
   only the box and the 3D staging differ.

   Everything below is inside the min-width query and scoped to [data-tbd-flow],
   so none of it can reach the phone deck. */
[data-tbd-flow] { display: none; }

@media (min-width: 768px) {
  [data-tbd-flow] { display: block; }
  /* the rail is the no-JavaScript fallback; once the coverflow exists it goes */
  [data-tbd-flow] ~ [data-tbd-rev-rail] { display: none; }

  /* 600, not 570: the front card is raised 17px AND pulled 125px forward, and
     the 1500px perspective magnifies that by 1.09 about the centre -- which put
     the top of its portrait 29px above the viewport, where overflow:hidden cut
     it off. The extra height plus the shallower margin below drops the whole
     stack far enough for the circle to clear. */
  .tbd-cfvp { position: relative; height: 600px; margin: 22px 0 14px;
              perspective: 1500px; overflow: hidden;
              touch-action: pan-y;        /* vertical page scrolling is never trapped */
              cursor: grab; }
  .tbd-cfvp.is-drag { cursor: grabbing; }
  .tbd-cftrack { position: absolute; inset: 0; transform-style: preserve-3d; }

  .tbd-cfcard {
    position: absolute; left: 50%; top: 50%;
    width: 390px; height: 435px; margin: -175px 0 0 -195px;
    padding: 77px 28px 24px; gap: 8px;
    border: 1px solid var(--border-hairline); border-radius: 30px;
    background: var(--shell); box-shadow: var(--shadow-raised);
    display: flex; flex-direction: column; align-items: center; text-align: center;
    will-change: transform, opacity, filter;
    transition: transform .58s cubic-bezier(.18,.82,.24,1), opacity .4s, filter .4s;
    user-select: none; -webkit-user-select: none;
  }

  /* the shared content, sized up for the bigger card */
  [data-tbd-flow] .tbd-rav { top: -66px; width: 136px; height: 136px; font-size: 52px; }
  [data-tbd-flow] .tbd-rname { font-size: 22px; }
  [data-tbd-flow] .tbd-qshell { padding: 0 19px; width: 100%; }
  [data-tbd-flow] .tbd-quote { font-size: 22px; -webkit-line-clamp: 5; }
  [data-tbd-flow] .tbd-qmark { font-size: 74px; vertical-align: -0.45em; }

  /* only the review in front offers its link */
  .tbd-cfcard:not(.is-active) .tbd-readfull { opacity: 0; pointer-events: none; }

  /* a roomier dialog, the same dialog */
  .tbd-modal-lg .tbd-dialog { width: min(620px, 90vw); height: min(620px, 72vh);
                              max-height: calc(100dvh - 96px); }
  .tbd-modal-lg .tbd-mquote { font-size: 20px; line-height: 1.6; }
  .tbd-modal-lg .tbd-mbody { padding: 26px 32px 32px; }
}

@media (min-width: 768px) and (prefers-reduced-motion: reduce) {
  .tbd-cfcard { transition: none !important; }
}

/* ── reviewer portraits and the link back to Google ──────────────────────── */

/* Six of the fourteen set a profile picture; the rest keep the brand initial,
   because Google's stand-in is a flat grey letter circle that looks worse than
   the one we draw. The photo sits inside the same circle, so the two kinds sit
   together without the layout shifting. */
.tbd-rav.has-photo, .tbd-mav.has-photo { overflow: hidden; padding: 0; }
.tbd-rav.has-photo img, .tbd-mav.has-photo img {
  width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 50%;
}
.tbd-mav.has-photo { border-radius: 50%; }

/* The way out to the real thing, for anyone who wants to verify it. */
.tbd-msrc {
  display: inline-block; margin-top: var(--space-4);
  font-family: var(--font-body); font-size: var(--text-small);
  font-weight: var(--weight-body-strong); color: var(--purple-link);
  text-decoration: underline; text-underline-offset: 4px;
  text-decoration-thickness: 1px;
}
.tbd-msrc:hover { color: var(--purple-500); }
.tbd-msrc[hidden] { display: none; }

/* The full review keeps the shape the reviewer gave it. Twelve of the fourteen
   are written as several paragraphs separated by a blank line; rendering them
   as one block collapsed a five-paragraph review into a wall of text, which is
   what made it read as shorter than it is. */
.tbd-mpara { margin: 0; }
.tbd-mpara + .tbd-mpara { margin-top: 0.9em; }

/* ── the theme paints every <button> dark grey ───────────────────────────── */

/* The WordPress theme sets `button { background: #55555e }` and
   `button:hover { background: #3f4047 }`. That hover selector scores (0,1,1),
   which beats a bare class and ties with `.tbd-deck-nav button`, so relying on
   source order is not safe. Every control the review system builds therefore
   states its own background with !important.

   This caught me twice -- first the dialog's close buttons, then "Read full
   review", which turned into a black box under the pointer. Anything new in
   here that is a <button> needs the same treatment. */
.tbd-readfull,
.tbd-readfull:hover,
.tbd-readfull:focus,
.tbd-readfull:active {
  background: transparent !important;
  color: var(--gold-text) !important;
}
.tbd-readfull:hover { text-decoration-thickness: 2px; }

.tbd-deck-nav button {
  background-color: var(--surface-card-light) !important;
  color: var(--purple-link) !important;
}
.tbd-deck-nav button:hover { color: #FFFFFF !important; }

/* ── the paper the reviews are printed on ───────────────────────────────── */

/* The watercolour from the "What I offer" band in the middle of the home page,
   brought onto the cards so they are stained paper rather than flat white.
   buildDeck and buildFlow deal every value per review, so no two sheets match.

   It is masked away from the middle. Across the whole card it sat under the
   quote and made it harder to read; held to the edge it gives the card depth
   and leaves the text on clean ground.

   z-index:-1, not 0: the card is a stacking context, so a negative layer paints
   above the card's own background but below its text. A positive one sat over
   the content, and pushing the content back with a `> *` rule overrode
   .tbd-rav's `position:absolute` -- same specificity, later in the file --
   which dropped the portrait into flow. */
.tbd-rcard::before,
.tbd-cfcard::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  pointer-events: none; z-index: -1;
  background-image:
    radial-gradient(var(--w1, 60% 55% at 12% 18%),
      rgba(var(--c1, 188,168,189), var(--a1, .24)) 0%, transparent 64%),
    radial-gradient(var(--w2, 48% 48% at 88% 72%),
      rgba(var(--c2, 255,188,89), var(--a2, .16)) 0%, transparent 66%),
    radial-gradient(var(--w3, 70% 60% at 62% 8%),
      rgba(var(--c3, 188,168,189), var(--a3, .20)) 0%, transparent 70%),
    radial-gradient(rgba(255,188,89,0.18) 1.1px, transparent 1.2px),
    radial-gradient(rgba(188,168,189,0.15) 1px, transparent 1.1px);
  background-size: auto, auto, auto, 96px 96px, 152px 152px;
  background-position:
    0 0, 0 0, 0 0,
    var(--tex-x, 0) var(--tex-y, 0),
    var(--tex-y, 48px) var(--tex-x, 70px);
  /* closest-side, so the radius is the card's own half-size and the stops mean
     what they say. Sized in percentages of the box instead, the 46% stop
     reached 201px on a 390px-wide card -- past its own edge -- so the whole
     card fell in the clear zone and the wash vanished entirely. */
  -webkit-mask-image: radial-gradient(closest-side,
                        #0000 40%, #0007 72%, #000 100%);
          mask-image: radial-gradient(closest-side,
                        #0000 40%, #0007 72%, #000 100%);
}

/* ── the spiral behind the reviews ──────────────────────────────────────── */

/* The watermark sits at bottom:59px, which on this section puts it right under
   the card stack -- it is there, but nothing of it ever shows. Lifting it clear
   of the cards lets it read as the section's own mark while you scroll past.
   Scoped with :has() to the section that carries the reviews, so the matching
   spiral higher up the home page keeps its own placement. */
section:has([data-tbd-rev-rail]) img[src*="logo-symbol"] {
  /* the design system sets bottom inline, so this has to outrank it */
  bottom: 300px !important;
}

/* ── two-tone headings stay on one line ─────────────────────────────────── */

/* SectionHeading renders its emphasis as `<em>` with display:block, so every
   heading broke before its last words whether or not the line was full --
   "Why I do / this work", "Support, from preparation to the / first weeks".
   Inline instead, so it wraps only when it actually runs out of room.

   The markup has no whitespace between the two parts ("Why I do<em>this
   work</em>"), so going inline alone would run them together; the ::before
   supplies the space the markup never had. */
h1 > em, h2 > em, h3 > em { display: inline; }
h1 > em::before, h2 > em::before, h3 > em::before { content: " "; }

/* ── the reviews band: full width, and purple rather than gold ──────────── */

/* The coverflow lives inside the site's content measure -- the section pads
   64px and an inner wrapper caps at 1180px -- so the cards were being clipped
   130px short of each screen edge. Full-bleed via negative margins rather than
   a transform, which would have fought the 1500px perspective on this element.
   The section's own overflow:hidden keeps 100vw from causing a page scrollbar. */
@media (min-width: 768px) {
  .tbd-cfvp {
    width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
  }
}

/* The ground under the reviews was the speckle variant, whose two big washes
   are gold -- against a gold spiral and now-textured cards it all sat in the
   same warm register and the depth disappeared. This is the purple wash the
   "What I offer" band uses, so the section reads cool and the gold spiral and
   the cards have something to sit against. Inline styles, so !important. */
/* Both spellings: the source ships it unspaced, but the drift script rewrites
   the style attribute on scroll and the browser re-serialises it with spaces. */
section:has([data-tbd-rev-rail]) div[style*="radial-gradient(rgba(255,188,89"],
section:has([data-tbd-rev-rail]) div[style*="radial-gradient(rgba(255, 188, 89"] {
  background-image:
    radial-gradient(60% 55% at 12% 18%, rgba(188,168,189,0.50) 0%, transparent 62%),
    radial-gradient(48% 48% at 88% 72%, rgba(188,168,189,0.34) 0%, transparent 65%),
    radial-gradient(70% 60% at 62% 8%, rgba(188,168,189,0.30) 0%, transparent 70%),
    radial-gradient(80% 60% at 50% 108%, rgba(255,188,89,0.10) 0%, transparent 62%)
    !important;
  /* The speckle variant this replaces also set background-size to 96px/152px
     tiles for its dots. Left alone, those tiles chopped these soft washes into
     a grid of repeating blurry squares across the whole band. */
  background-size: auto !important;
  background-position: 0 0 !important;
  background-repeat: no-repeat !important;
}

/* ── the secondary button ───────────────────────────────────────────────── */

/* White with purple text read as body copy rather than a control -- on the
   cream grounds it was barely there. A wash of the brand's gold makes it
   obviously pressable while staying far lighter than the solid gold primary,
   so "Book a free Meet & Greet" is still the one thing the eye lands on. The
   purple sweep on hover is unchanged; only the resting state moves.

   Inline styles from the design system, so !important throughout. */
[data-tbd-btn="outline"] {
  background-color: rgba(255,188,89,.16) !important;
  color: var(--ink) !important;
  border: 1px solid rgba(255,188,89,.62) !important;
  /* The purple sweep is a background-image, which by default fills only the
     padding box, while background-color fills the border box. With the border
     going transparent on hover that left a 1px ring of the gold tint around the
     purple -- at a 999px radius it read as a corner that had lost its curve.
     border-box makes the sweep cover the whole shape. */
  background-origin: border-box !important;
}
[data-tbd-btn="outline"]:hover { border-color: transparent !important; }

/* The deck arrows and the dialog's close button carry data-tbd-btn="outline"
   for its hover/press/focus behaviour, not its colour. They stay white circles;
   the arrow rule already outranks the variant, the X needs the extra weight. */
.tbd-modal .tbd-mx {
  background-color: var(--surface-card-light) !important;
  color: var(--purple-link) !important;
  border: 1px solid var(--dusty-200) !important;
}
.tbd-modal .tbd-mx:hover { color: #FFFFFF !important; border-color: transparent !important; }
