/*
Theme Name: JGP
Theme URI: https://jeffreygrounds.com
Author: JeffreyGrounds Photography
Description: Full-site-editing theme for JeffreyGrounds Photography.
Requires at least: 6.6
Tested up to: 6.6
Requires PHP: 7.4
Version: 0.1.0
License: GNU General Public License v2 or later
Text Domain: jgp
*/

/*
  No cascade layers here, unlike src/styles/global.css.

  In Astro the @layer theme, base, components, utilities order existed for one
  reason: to keep site.css below Tailwind's utilities, so a Tailwind class
  added to new markup would win. Tailwind is not ported, so that job is gone.

  Keeping the layer would actively break the design. WordPress prints its
  block stylesheets unlayered, and unlayered CSS beats layered CSS whatever
  the specificity, so every core block rule would outrank the whole ported
  design. Measured: with site.css inside @layer components, core's
  .wp-block-navigation__container beat a .nav-left .wp-block-navigation__container
  rule. Unlayered, ordinary specificity decides and the port wins where it
  should.

  Order below is the order global.css imported them: the one base rule, then
  site.css, then themes.css so a [data-theme] block overrides the :root
  tokens on source order.
*/

/* src/styles/global.css:22-24 */
img {
  height: auto;
}

/* ----------------------------------------- src/styles/site.css (verbatim) */
/*
  JGP design experiment - "Nate Shepherd" layout language
  ------------------------------------------------------
  Every colour, the gold offset frame, the outlined button and the split
  navbar are lifted from wp-content/themes/jgpoct2025/style.css. The layout
  language (full-bleed bands, overlapping photos, staggered panels) is the
  Nate Shepherd reference.

  TYPE
  ----
  Bodoni Moda carries every heading and quote; Jost carries navigation,
  labels, buttons and body copy. The pairing and its treatment (medium-weight
  display set slightly tight, wide-tracked small caps for labels) match the
  ArcMail demo at jeffreygrounds.arcmail.workers.dev, measured from its
  computed styles. The Google Fonts request is the same one the demo makes
  (its self-hosted files are byte-identical): Bodoni Moda without the optical
  size axis, whose default cut keeps the hairlines sturdy at display sizes,
  and Jost 300-700.

  SCALING - the same technique as the live theme
  ----------------------------------------------
  The design is drawn once at a 1513.94px base width and every length is
  written as a fraction of that base, so the whole page zooms with the window
  instead of reflowing. One custom property does it:

    --u   one "design pixel" - 1/1513.94 of the canvas width, frozen at 1px
          once the canvas reaches the base width.

  100/1513.94 = 0.06605, so 0.06605cqw is one design pixel. Every length below
  is written as calc(<design px> * var(--u)). Above 1513.94px the min()
  freezes --u at 1px and the design settles at its drawn size.

  Every screen from 600px up gets the desktop layout, shrunk to fit. Below
  600px the phone block at the bottom resets --u to 1px and the layout stacks.

  The fixed header is the one piece that lives outside .canvas. A size
  container (container-type) becomes the containing block for position:fixed
  children, so a header inside it would scroll away with the page. The header
  reads the viewport-based --u declared on :root instead.

  Hairlines use max(1px, ...) so a 1px line does not shrink to a sub-pixel
  and disappear at iPad width.

  THEME TOKENS
  ------------
  Every colour and the heading type treatment below is a token. The values
  on :root are the wedding theme, the default. src/styles/themes.css swaps
  them per specialty with data-theme="..." on <html> or any element; the
  layout, spacing and components never change. Translucent tints are mixed
  from the tokens with color-mix(), so a theme only sets solid colours.
*/

:root {
  --accent: #b39873;        /* jgpoct2025 gold. Rules, frames, labels on dark grounds */
  --accent-strong: #8a6f4a; /* jgpoct2025 dark gold. Small text and solid buttons on light grounds */
  --warm-gray: #b9b1a7;     /* jgpoct2025 band colour */
  --ink: #24211e;           /* jgpoct2025 --ink. Dark bands, header, heading text */
  --shade: #141210;         /* photo overlays */
  --paper: #fbfaf7;         /* text on dark grounds */
  --cream: #f3f2e9;         /* jgpoct2025 light band */
  --panel: #eeecea;         /* card panel behind the testimonial copy */
  --body: #4a4a4a;

  --display: 'Bodoni Moda', 'Didot', 'Times New Roman', serif;
  --ui: 'Jost', 'Futura', 'Helvetica Neue', Arial, sans-serif;

  /* Heading treatment. --display-scale multiplies the h1/h2/h3 sizes, for a
     face that runs wider or narrower than Bodoni Moda. --em-style is the
     emphasised word in a heading and every display-font quote. */
  --display-weight: 500;
  --display-tracking: -0.015em;
  --display-leading: 0.98;
  --display-case: none;
  --display-scale: 1;
  --em-style: italic;
  --em-weight: 400;

  /* Viewport-based design pixel, for the fixed header and scroll padding. */
  --u: min(0.06605vw, 1px);
  --header-h: calc(96 * var(--u));

  /* Long, soft deceleration shared by the menu motion. */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
}

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

html { scroll-padding-top: calc(var(--wp-admin--admin-bar--height, 0px) + var(--header-h) + 12 * var(--u)); }

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  font-family: var(--ui);
  color: var(--body);
  background: #fff;
  /* clip, not hidden: hidden turns the body into a scroll container and
     position:sticky in the "How it goes" section would stop sticking. */
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

.canvas {
  width: 100%;
  container-type: inline-size;
}

/* --u is declared on a child of the container, not on the container itself:
   a container's own size is not available to its own declarations. */
.scale {
  --u: min(0.06605cqw, 1px);

  --gutter: calc(80 * var(--u));
  --band: calc(100 * var(--u));

  font-size: calc(17 * var(--u));
  line-height: 1.75;
}

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

a { color: inherit; }

/* ---------------------------------------------------------------- shared */

.display {
  font-family: var(--display);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: var(--display-leading);
  text-transform: var(--display-case);
  text-wrap: balance;
  color: var(--ink);
  font-size: calc(60 * var(--u) * var(--display-scale));
}

/* The italic gold word inside a heading - the "We Know Weddings" motif from
   the live front page, carried into the new type. */
.display em { font-style: var(--em-style); font-weight: var(--em-weight); color: var(--accent-strong); }

.h1 { font-size: calc(92 * var(--u) * var(--display-scale)); }
.h2 { font-size: calc(60 * var(--u) * var(--display-scale)); }
.h3 { font-size: calc(30 * var(--u) * var(--display-scale)); line-height: 1.08; }

.display--ink { color: var(--ink); }
.on-dark .display,
.display--light { color: var(--paper); }
.on-dark .display em,
.display--light em { color: var(--accent); }

/* Wide-tracked small caps for eyebrows and labels. Gold-dark on light
   grounds, where plain gold is too faint to read at this size. */
.eyebrow {
  font-family: var(--ui);
  font-size: calc(11 * var(--u));
  font-weight: 500;
  letter-spacing: 0.22em;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--accent-strong);
}
.on-dark .eyebrow,
.eyebrow--light { color: var(--accent); }

.eyebrow + .display { margin-top: calc(20 * var(--u)); }

.lede {
  font-size: calc(19 * var(--u));
  line-height: 1.75;
  color: var(--body);
}
.on-dark .lede,
.on-dark p { color: color-mix(in srgb, var(--paper) 78%, transparent); }

/* Thin vertical rule under a centred headline. */
.rule-v {
  width: max(1px, calc(1 * var(--u)));
  height: calc(46 * var(--u));
  background: var(--accent);
  margin: calc(30 * var(--u)) auto;
  opacity: 0.7;
}

/* Short gold rule used under quotes and inside cards. */
.rule-short {
  width: calc(56 * var(--u));
  height: max(1px, calc(1 * var(--u)));
  background: var(--accent);
  border: 0;
}

.btn,
.wp-block-button.btn > .wp-block-button__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: calc(52 * var(--u));
  padding: 0 calc(28 * var(--u));
  font-family: var(--ui);
  font-size: calc(12 * var(--u));
  font-weight: 500;
  letter-spacing: 0.16em;
  line-height: 1.2;
  text-transform: uppercase;
  text-decoration: none;
  border: max(1px, calc(1 * var(--u))) solid transparent;
  transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease, transform 0.25s ease;
}

/* Solid gold. Gold-dark rather than the lighter gold so white label text
   still passes contrast. */
.btn--solid,
.wp-block-button.btn--solid > .wp-block-button__link { background: var(--accent-strong); color: #fff; border-color: var(--accent-strong); }
.btn--solid:hover,
.wp-block-button.btn--solid > .wp-block-button__link:hover { background: var(--ink); border-color: var(--ink); transform: translateY(-2px); }

/* Outlined - the existing .contact-button-bg treatment from jgpoct2025. */
.btn--outline,
.wp-block-button.btn--outline > .wp-block-button__link { background: transparent; color: var(--accent-strong); border: max(1px, calc(2 * var(--u))) solid var(--accent); }
.btn--outline:hover,
.wp-block-button.btn--outline > .wp-block-button__link:hover { background: var(--accent); color: var(--ink); transform: translateY(-2px); }

/* Outlined, on a dark or photographic ground. */
.btn--ghost,
.wp-block-button.btn--ghost > .wp-block-button__link { background: transparent; color: var(--paper); border-color: color-mix(in srgb, var(--paper) 70%, transparent); }
.btn--ghost:hover,
.wp-block-button.btn--ghost > .wp-block-button__link:hover { background: var(--paper); color: var(--ink); border-color: var(--paper); }

.btn-row { display: flex; flex-wrap: wrap; align-items: center; gap: calc(16 * var(--u)) calc(28 * var(--u)); }

/* Small-caps text link with an arrow, for the secondary action beside a button. */
.text-link,
.wp-block-button.text-link > .wp-block-button__link {
  font-size: calc(11 * var(--u));
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--accent-strong);
  border-bottom: max(1px, calc(1 * var(--u))) solid currentColor;
  padding-bottom: calc(3 * var(--u));
}
.text-link:hover,
.wp-block-button.text-link > .wp-block-button__link:hover { color: var(--ink); }
.on-dark .text-link,
.on-dark .wp-block-button.text-link > .wp-block-button__link { color: var(--accent); }
.on-dark .text-link:hover,
.on-dark .wp-block-button.text-link > .wp-block-button__link:hover { color: var(--paper); }

/* The gold offset frame from jgpoct2025 (.intro-image::before and friends),
   rewritten as a reusable component. Wrap a photo or a panel in .framed and
   the frame peeks out on two sides. On a panel the frame lines run through
   its padding, so a framed panel needs more than 22 design px of padding. */
.framed { position: relative; }
.framed > img { position: relative; z-index: 1; }
.framed::before {
  content: '';
  position: absolute;
  border: max(1px, calc(2 * var(--u))) solid var(--accent);
  z-index: 2;
  pointer-events: none;
  /* frame escapes top-left */
  inset: calc(-22 * var(--u)) calc(22 * var(--u)) calc(22 * var(--u)) calc(-22 * var(--u));
}
/* mirrored: escapes top-right */
.framed--right::before {
  inset: calc(-22 * var(--u)) calc(-22 * var(--u)) calc(22 * var(--u)) calc(22 * var(--u));
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  padding: 12px 20px;
  background: #fff;
  color: var(--ink);
}
.skip-link:focus { left: 0; }

/* Scroll reveal. Browsers without scroll-driven animations, and anyone who
   asked for reduced motion, simply see everything in place. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .reveal {
      animation: reveal-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 40%;
    }
  }
}
@keyframes reveal-rise {
  from { opacity: 0; translate: 0 calc(28 * var(--u)); }
  to   { opacity: 1; translate: 0 0; }
}

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

/* Same three-part split as the live header: links left, logo centred, links
   right. Fixed to the top of the window. It starts clear over the hero
   photograph and turns solid ink once the hero copy slides up underneath it
   (site.js adds .is-solid). */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  transition: background-color 0.35s ease, box-shadow 0.35s ease;
}

/* Logged in, WordPress pins its admin bar to the top of the window and
   publishes its height as --wp-admin--admin-bar--height (32px, or 46px at
   782px and below). The header sits just under it. Below 600px the bar
   scrolls away with the page instead, so site.js follows its bottom edge. */
.admin-bar .site-header { top: var(--wp-admin--admin-bar--height, 0px); }

.site-header-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: calc(46 * var(--u));
  height: var(--header-h);
  padding: 0 calc(80 * var(--u));
  transition: height 0.35s ease;
}

.site-header.is-solid,
.site-header.menu-open {
  background: var(--ink);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--accent) 35%, transparent);
}
.site-header.is-solid .site-header-inner { height: calc(76 * var(--u)); }

.site-header nav.nav-left,
.site-header nav.nav-right { display: flex; align-items: center; gap: calc(40 * var(--u)); }
.nav-left { justify-content: flex-end; }
.nav-right { justify-content: flex-start; }

.site-header :is(.nav-left, .nav-right) a {
  font-family: var(--ui);
  font-size: calc(11 * var(--u));
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--paper);
  padding-bottom: calc(4 * var(--u));
  border-bottom: max(1px, calc(1 * var(--u))) solid transparent;
  transition: border-color 0.3s ease, color 0.3s ease;
  white-space: nowrap;
}
.site-header :is(.nav-left, .nav-right) a:hover { border-bottom-color: var(--accent); }

/* Inquire is the one action link - boxed in gold like the reference's
   INQUIRE button, but outlined so it stays inside our palette. */
.site-header :is(.nav-left, .nav-right) a.nav-cta {
  padding: calc(10 * var(--u)) calc(18 * var(--u));
  border: max(1px, calc(1 * var(--u))) solid var(--accent);
  color: var(--accent);
}
.site-header :is(.nav-left, .nav-right) a.nav-cta:hover { background: var(--accent); color: var(--ink); }

.site-header .logo img {
  width: calc(130 * var(--u));
  height: auto;
  filter: brightness(0) invert(1);
  transition: width 0.35s ease;
}
.site-header.is-solid .logo img { width: calc(112 * var(--u)); }

.menu-toggle,
.mobile-menu { display: none; }

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

.hero {
  position: relative;
  height: calc(900 * var(--u));
  overflow: hidden;
  background: var(--ink);
}
.hero > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Top shade keeps the clear header legible; the bottom-left shade holds the
   hero copy. The couple stand right of centre, outside both. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgba(0,0,0,0.45) 0%, rgba(0,0,0,0) 22%),
    linear-gradient(to top, color-mix(in srgb, var(--shade) 78%, transparent) 0%, color-mix(in srgb, var(--shade) 35%, transparent) 38%, color-mix(in srgb, var(--shade) 0%, transparent) 62%),
    linear-gradient(to right, color-mix(in srgb, var(--shade) 35%, transparent) 0%, color-mix(in srgb, var(--shade) 0%, transparent) 55%);
}

.hero-text {
  position: absolute;
  left: var(--gutter);
  bottom: calc(100 * var(--u));
  z-index: 3;
  max-width: calc(760 * var(--u));
}
.hero-text .display { color: var(--paper); }
.hero-text .display em,
.page-hero .display em { color: var(--accent); }
.hero-text .lede {
  color: color-mix(in srgb, var(--paper) 82%, transparent);
  max-width: calc(560 * var(--u));
  margin: calc(28 * var(--u)) 0 calc(38 * var(--u));
}

/* Page hero for sub-pages: shorter, with a centred title plate. */
.page-hero { height: calc(560 * var(--u)); }
.page-hero::after {
  background: linear-gradient(to bottom, color-mix(in srgb, var(--ink) 60%, transparent) 0%, color-mix(in srgb, var(--ink) 42%, transparent) 100%);
}
.page-hero .page-hero-text {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--header-h) var(--gutter) 0;
}
.page-hero .display { color: var(--paper); }
.page-hero .eyebrow { color: var(--accent); }
/* About hero: Jeff's face sits near the top of the photo, right of centre.
   Anchor the crop to the top so the face stays in the right half, clear of
   the centred title. */
.page-hero--jeff > img { object-position: 60% 0%; }

/* ----------------------------------------------------------- proof strip */

/* Reference: the credentials row directly under the hero. Here the figure
   is set large in Bodoni gold with the label underneath, split by gold
   hairlines. */
.proof {
  background: var(--ink);
  padding: calc(46 * var(--u)) var(--gutter);
}
.proof ul {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  max-width: calc(1400 * var(--u));
  margin: 0 auto;
}
.proof li {
  padding: 0 calc(34 * var(--u));
  text-align: center;
  border-left: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--accent) 35%, transparent);
}
.proof li:first-child { border-left: 0; }
.proof strong,
.proof .proof-figure {
  display: block;
  font-family: var(--display);
  font-weight: var(--display-weight);
  font-size: calc(40 * var(--u));
  line-height: 1;
  color: var(--accent);
}
.proof span,
.proof .proof-label {
  display: block;
  margin-top: calc(12 * var(--u));
  font-size: calc(11 * var(--u));
  font-weight: 500;
  letter-spacing: 0.22em;
  line-height: 1.7;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--paper) 72%, transparent);
}

/* ------------------------------------------------------- centred statement */

.statement {
  background: var(--cream);
  padding: var(--band) var(--gutter);
  text-align: center;
}
.statement .display { max-width: calc(900 * var(--u)); margin-left: auto; margin-right: auto; }
.statement-copy {
  max-width: calc(660 * var(--u));
  margin: 0 auto;
}
.statement-copy p + p { margin-top: 1.1em; }

/* --------------------------------------------------------- stories collage */

/* Reference: the "STORIES" scatter grid - photos on an asymmetric 12-column
   grid with the heading block sitting in the open corner top right. */
.stories {
  padding: var(--band) var(--gutter);
  background: #fff;
}
.stories-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: calc(47 * var(--u));
  gap: calc(14 * var(--u));
  max-width: calc(1400 * var(--u));
  margin: 0 auto;
}
.stories-grid img { width: 100%; height: 100%; object-fit: cover; }

.stories-head {
  grid-column: 8 / 13;
  grid-row: 1 / 6;
  align-self: start;
  z-index: 3;
  padding-left: calc(20 * var(--u));
}
.stories-head .lede { margin-top: calc(22 * var(--u)); font-size: calc(17 * var(--u)); max-width: calc(420 * var(--u)); }

.s1 { grid-column: 3 / 8;  grid-row: 1 / 6; }
.s2 { grid-column: 1 / 6;  grid-row: 5 / 11; }
.s3 { grid-column: 7 / 12; grid-row: 6 / 11; }
.s4 { grid-column: 6 / 11; grid-row: 11 / 17; }
.s5 { grid-column: 2 / 6;  grid-row: 12 / 17; }
.s6 { grid-column: 8 / 13; grid-row: 16 / 22; }

/* Keep the subject in frame where the cell crops the photo: the couple in s4 sit
   low in a tall photo, the ring in s6 sits at the very bottom edge. */
.s4 img { object-position: 50% 90%; }
.s6 img { object-position: 50% 100%; }

.stories-cta {
  grid-column: 2 / 7;
  grid-row: 18 / 21;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: calc(22 * var(--u));
}

/* -------------------------------------------------------------- print band */

/* Full-bleed colour photograph with a cream panel laid over its lower left
   corner. The panel carries the gold offset frame, the same layered-box
   treatment as the collage above. */
.print {
  position: relative;
  min-height: calc(820 * var(--u));
  display: flex;
  align-items: flex-end;
  padding: var(--band) var(--gutter);
  overflow: hidden;
}
.print > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.print::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, color-mix(in srgb, var(--shade) 25%, transparent) 0%, color-mix(in srgb, var(--shade) 0%, transparent) 60%);
}
.print-panel {
  position: relative;
  z-index: 3;
  max-width: calc(640 * var(--u));
  background: var(--cream);
  padding: calc(64 * var(--u)) calc(60 * var(--u)) calc(60 * var(--u));
}
.print-panel .display { margin-bottom: calc(26 * var(--u)); }
.print-panel p + p { margin-top: 1em; }
/* Photo credit line at the foot of the panel. It sits on the cream rather
   than on the photograph, where bright water swallowed white text. */
.print-caption {
  margin-top: calc(30 * var(--u));
  padding-top: calc(18 * var(--u));
  border-top: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--accent) 35%, transparent);
  font-size: calc(13 * var(--u));
  line-height: 1.6;
}
.print-caption .eyebrow { margin-right: calc(10 * var(--u)); }

/* ------------------------------------------------------------ meet Jeff */

/* Reference: "Hi, I'm Jeff." - headline left, lead paragraph right, then
   photos and the rest of the story. Here the two photos overlap inside their
   gold frames and the story sits in a grey panel, like the testimonial cards
   on the previous version of this page. */
.jeff {
  padding: var(--band) 0;
  background: #fff;
}
.jeff-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: calc(14 * var(--u));
  max-width: calc(1400 * var(--u));
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.jeff-head { grid-column: 1 / 6; grid-row: 1; align-self: end; }
.jeff-lede { grid-column: 7 / 13; grid-row: 1; align-self: end; }

.jeff-media {
  grid-column: 1 / 7;
  grid-row: 2;
  position: relative;
  margin-top: calc(90 * var(--u));
  min-height: calc(640 * var(--u));
}
.jeff-media img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.jm1 { width: 62%; margin-left: calc(22 * var(--u)); }
/* Jeff's portrait is cut from a landscape photo; his face is right of centre. */
.jm1 img { object-position: 76% 50%; }
.jm2 { position: absolute; left: 52%; top: calc(200 * var(--u)); width: 44%; z-index: 3; }

.jeff-panel {
  grid-column: 7 / 13;
  grid-row: 2;
  align-self: start;
  margin-top: calc(150 * var(--u));
  background: var(--panel);
  padding: calc(56 * var(--u)) calc(54 * var(--u));
  z-index: 2;
}
.jeff-panel p + p { margin-top: 1em; }

.mission {
  margin: calc(34 * var(--u)) 0 calc(38 * var(--u));
  padding-left: calc(26 * var(--u));
  border-left: max(1px, calc(2 * var(--u))) solid var(--accent);
}
.mission p {
  font-family: var(--display);
  font-style: var(--em-style);
  font-size: calc(26 * var(--u));
  line-height: 1.35;
  color: var(--ink);
}
.mission cite { display: block; margin-top: calc(14 * var(--u)); font-style: normal; }

/* ------------------------------------------------------------ how it goes */

/* Reference: "The part before the photographs." The intro column sticks
   under the header while the four steps scroll past it. Our version stacks
   the steps as offset white cards on the cream band, and a gold rail beside
   them fills as you scroll through. */
.how {
  background: var(--cream);
  padding: var(--band) var(--gutter);
}
.how-grid {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: calc(100 * var(--u));
  max-width: calc(1400 * var(--u));
  margin: 0 auto;
}
.how-intro {
  position: sticky;
  top: calc(var(--wp-admin--admin-bar--height, 0px) + 76 * var(--u) + 64 * var(--u));
  align-self: start;
  padding-top: calc(10 * var(--u));
}
.how-intro .lede { margin: calc(28 * var(--u)) 0 calc(36 * var(--u)); font-size: calc(17 * var(--u)); max-width: calc(440 * var(--u)); }

.how-steps {
  list-style: none;
  position: relative;
  padding-left: calc(60 * var(--u));
}
/* The rail: a faint track and a gold fill that grows with scroll. */
.how-steps::before,
.how-steps::after {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: max(1px, calc(2 * var(--u)));
}
.how-steps::before { background: color-mix(in srgb, var(--accent) 25%, transparent); }
.how-steps::after { background: var(--accent); transform-origin: top; }

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .how-steps::after {
      animation: rail-fill linear both;
      animation-timeline: view();
      /* Starts as the list's top passes mid-window, full as its bottom does. */
      animation-range: cover 50vh cover calc(100% - 50vh);
    }
  }
}
@keyframes rail-fill {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

.step {
  position: relative;
  display: grid;
  grid-template-columns: calc(120 * var(--u)) 1fr;
  gap: calc(24 * var(--u));
  background: #fff;
  padding: calc(50 * var(--u)) calc(52 * var(--u));
  margin-right: calc(70 * var(--u));
}
.step + .step { margin-top: calc(56 * var(--u)); }
/* Every other card shifts right, so the stack reads as layered boxes. */
.step:nth-child(even) { margin-right: 0; margin-left: calc(70 * var(--u)); }

.step-num {
  font-family: var(--display);
  font-style: var(--em-style);
  font-size: calc(30 * var(--u));
  line-height: 1.08;
  color: var(--accent-strong);
}
.step .display { margin-bottom: calc(14 * var(--u)); }

/* --------------------------------------------------- couples who were there */

/* Reference: "Couples who were there." - heading left, a note right, then
   six quotes in three columns. Our version keeps the three columns but uses
   the grey quote panels and gold frames, with the middle column dropped so
   the panels stagger. */
.reviews {
  padding: var(--band) var(--gutter) calc(var(--band) + 25 * var(--u));
  background: #fff;
}
.reviews-inner { max-width: calc(1400 * var(--u)); margin: 0 auto; }

.section-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: calc(60 * var(--u));
  margin-bottom: calc(56 * var(--u));
}
.section-head .note {
  max-width: calc(380 * var(--u));
  text-align: right;
  font-size: calc(15 * var(--u));
}

.reviews-grid {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(60 * var(--u)) calc(46 * var(--u));
  align-items: start;
}
.reviews-grid > li:nth-child(3n+2) { translate: 0 calc(70 * var(--u)); }

.review {
  background: var(--panel);
  padding: calc(52 * var(--u)) calc(44 * var(--u)) calc(44 * var(--u));
  display: flex;
  flex-direction: column;
}
.review::after {
  /* Oversized Bodoni quote mark, tucked into the panel's top right. */
  content: '\201C';
  position: absolute;
  top: calc(14 * var(--u));
  right: calc(34 * var(--u));
  font-family: var(--display);
  font-size: calc(110 * var(--u));
  line-height: 1;
  color: color-mix(in srgb, var(--accent) 45%, transparent);
  pointer-events: none;
}
.review { position: relative; }
.review blockquote p {
  font-family: var(--display);
  font-style: var(--em-style);
  font-size: calc(18 * var(--u));
  line-height: 1.6;
  color: var(--ink);
}
.review .rule-short { margin: calc(28 * var(--u)) 0 calc(20 * var(--u)); }
.review-name { font-style: normal; }
.review-where { display: block; font-size: calc(14 * var(--u)); color: var(--body); margin-top: calc(4 * var(--u)); }

.reviews-cta { margin-top: calc(75 * var(--u)); }

/* ---------------------------------------------------------------- packages */

/* Reference: "No guide to download. Here are the numbers." Every collection
   and price is the one published on jeffreygrounds.com/packages/. The home
   page shows the price ladder per category; packages.html carries the full
   inclusions and add-ons. */
.packages {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  padding: var(--band) var(--gutter) calc(var(--band) + 25 * var(--u));
}
.packages-inner { max-width: calc(1400 * var(--u)); margin: 0 auto; }
.packages .section-head .note { max-width: calc(520 * var(--u)); }

.tiers {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(46 * var(--u));
  align-items: start;
}
.tier {
  background: #fff;
  padding: calc(52 * var(--u)) calc(46 * var(--u)) calc(46 * var(--u));
}
.tiers > .tier:nth-child(2) { translate: 0 calc(60 * var(--u)); }

.tier .display { margin-top: calc(14 * var(--u)); }
.tier-blurb { margin: calc(18 * var(--u)) 0 calc(26 * var(--u)); font-size: calc(15 * var(--u)); min-height: calc(80 * var(--u)); }
.tier-from { display: flex; align-items: baseline; gap: calc(12 * var(--u)); }
.tier-from .price { font-family: var(--display); font-weight: var(--display-weight); font-size: calc(52 * var(--u)); line-height: 1; color: var(--ink); }

.ladder { list-style: none; margin: calc(28 * var(--u)) 0 calc(30 * var(--u)); border-top: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--accent) 35%, transparent); }
.ladder li {
  display: flex;
  align-items: baseline;
  gap: calc(10 * var(--u));
  padding: calc(12 * var(--u)) 0;
  font-size: calc(15 * var(--u));
  line-height: 1.4;
  border-bottom: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--accent) 20%, transparent);
}
.ladder li span:first-child { flex: 1; color: var(--ink); }
.ladder li span:last-child { font-family: var(--display); font-size: calc(18 * var(--u)); color: var(--accent-strong); white-space: nowrap; }

/* "Not sure which one fits your day?" - a cream plate that overlaps the
   bottom of the tier cards. */
.fit {
  position: relative;
  z-index: 3;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: calc(60 * var(--u));
  margin: calc(90 * var(--u)) calc(120 * var(--u)) 0;
  background: var(--cream);
  padding: calc(56 * var(--u)) calc(64 * var(--u));
}
.fit p { margin-top: calc(14 * var(--u)); max-width: calc(620 * var(--u)); }
.fit .btn-row { flex-direction: column; align-items: stretch; }

/* ----------------------------------------------------------------- inquire */

/* Reference: "Tell Jeff about your day." Here it is the dark tinted photo
   band from the previous "Featured In" section, with the form on a cream
   panel wearing the gold frame. */
.inquire {
  position: relative;
  padding: var(--band) var(--gutter);
  overflow: hidden;
}
.inquire > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.inquire::after {
  content: '';
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--ink) 84%, transparent);
}
.inquire-grid {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: calc(110 * var(--u));
  align-items: center;
  max-width: calc(1240 * var(--u));
  margin: 0 auto;
}
.inquire-copy .lede { margin: calc(28 * var(--u)) 0 calc(40 * var(--u)); }

.contact-list { display: grid; gap: calc(24 * var(--u)); }
.contact-list dt { font-size: calc(11 * var(--u)); font-weight: 500; letter-spacing: 0.22em; text-transform: uppercase; color: var(--accent); }
.contact-list dd { margin-top: calc(4 * var(--u)); color: var(--paper); }
.contact-list dd a { text-decoration: none; font-family: var(--display); font-size: calc(26 * var(--u)); line-height: 1.3; }
.contact-list dd a:hover { color: var(--accent); }
.contact-list dd.plain { color: color-mix(in srgb, var(--paper) 78%, transparent); font-size: calc(15 * var(--u)); }

.inquire-form {
  background: var(--cream);
  padding: calc(56 * var(--u)) calc(54 * var(--u));
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(22 * var(--u)) calc(24 * var(--u));
}
.inquire-form .full { grid-column: 1 / -1; }
.inquire-form label { display: block; }
.inquire-form label span { display: block; margin-bottom: calc(8 * var(--u)); }
.inquire-form input,
.inquire-form textarea {
  width: 100%;
  font: inherit;
  font-size: calc(16 * var(--u));
  color: var(--ink);
  background: #fff;
  border: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--ink) 18%, transparent);
  border-radius: 0;
  padding: calc(12 * var(--u)) calc(14 * var(--u));
}
.inquire-form textarea { min-height: calc(130 * var(--u)); resize: vertical; }
.inquire-form input:focus,
.inquire-form textarea:focus { outline: max(2px, calc(2 * var(--u))) solid var(--accent); outline-offset: 0; border-color: var(--accent); }
.inquire-form .btn { justify-self: start; cursor: pointer; }
/* The form is a light panel inside a dark section, so it takes back the
   light-ground colours that .on-dark hands to its labels and paragraphs. */
.inquire-form .eyebrow { color: var(--accent-strong); }

/* Contact Form 7 (theme/inc/contact-form.php). It wraps each control in a
   span inside the label, and its error tip in another, which the
   "label span" rule above would give the eyebrow's bottom margin. Its
   message after sending sits in the form's grid, so it takes the full row. */
.inquire-form .wpcf7-form-control-wrap { margin-bottom: 0; }
/* The tip hangs in the row gap instead of taking space. Contact Form 7
   removes it the moment a corrected field loses focus, which is on the
   mousedown of a click on Send; a tip in the flow would pull the button up
   before the mouseup, and the click would miss it. The gap widens to hold
   the tips while the form is .invalid, a class that only changes when a
   submission comes back, never mid-click. */
.inquire-form .wpcf7-not-valid-tip {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: calc(6 * var(--u));
  font-size: calc(13 * var(--u));
  line-height: 1.4;
}
.inquire-form.invalid { row-gap: calc(46 * var(--u)); }
.wpcf7 .inquire-form .wpcf7-response-output {
  grid-column: 1 / -1;
  margin: 0;
  padding: calc(12 * var(--u)) calc(14 * var(--u));
  font-size: calc(14 * var(--u));
  color: var(--ink);
}

/* --------------------------------------------------------------- sub-page */

.prose {
  max-width: calc(720 * var(--u));
  margin: 0 auto;
  padding: var(--band) var(--gutter);
}
.prose p + p { margin-top: 1.4em; }
.prose .display { margin-bottom: calc(28 * var(--u)); }

/* Our Goal (About): the team photo under the centred copy, wider than the
   text column so four faces are not tiny. */
/* about.astro:71 centred this column with an inline style. A style attribute
   the block does not declare fails block validation and drops the group out
   of the visual editor, so the rule moves here. */
.goal .prose { padding-bottom: calc(64 * var(--u)); text-align: center; }
.goal-photo {
  max-width: calc(880 * var(--u) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 0 var(--gutter) var(--band);
}

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(110 * var(--u));
  align-items: center;
  max-width: calc(1240 * var(--u));
  margin: 0 auto;
  padding: var(--band) var(--gutter);
}
.split--reverse .split-copy { order: 2; }
/* Landscape photo on the left: give it the wider column so it is not shorter
   than the copy beside it. */
.split--landscape { grid-template-columns: 3fr 2fr; }
.split-copy .display { margin-bottom: calc(26 * var(--u)); }
.split-copy p + p { margin-top: 1.3em; }
.split-copy .btn { margin-top: calc(34 * var(--u)); }

.band-warm { background: color-mix(in srgb, var(--accent) 16%, transparent); }
.band-cream { background: var(--cream); }

.cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(46 * var(--u));
  max-width: calc(1240 * var(--u));
  margin: 0 auto;
  padding: var(--band) var(--gutter);
}
.card img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; }
.card h3 { margin: calc(26 * var(--u)) 0 calc(12 * var(--u)); }
.card p { font-size: calc(15 * var(--u)); }

/* Closing dark band on sub-pages. */
.closing {
  position: relative;
  padding: var(--band) var(--gutter);
  overflow: hidden;
  text-align: center;
}
.closing > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.closing::after { content: ''; position: absolute; inset: 0; background: color-mix(in srgb, var(--ink) 78%, transparent); }
.closing-inner { position: relative; z-index: 2; max-width: calc(760 * var(--u)); margin: 0 auto; }
.closing .lede { margin: calc(24 * var(--u)) 0 calc(38 * var(--u)); }
.closing .btn-row { justify-content: center; }

/* ---------------------------------------------------------- packages page */

.pkg-section { padding: var(--band) var(--gutter); }
.pkg-inner { max-width: calc(1400 * var(--u)); margin: 0 auto; }
.pkg-section .section-head { margin-bottom: calc(70 * var(--u)); }

.plans {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(60 * var(--u)) calc(46 * var(--u));
  align-items: start;
}
.plan {
  position: relative;
  background: var(--panel);
  padding: calc(50 * var(--u)) calc(44 * var(--u)) calc(44 * var(--u));
  display: flex;
  flex-direction: column;
  height: 100%;
}
.band-warm .plan { background: #fff; }
.plan .display { margin-bottom: calc(18 * var(--u)); }
.plan .tier-from { margin-bottom: calc(24 * var(--u)); }
.plan ul {
  list-style: none;
  flex: 1;
  border-top: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--accent) 35%, transparent);
  margin-bottom: calc(30 * var(--u));
}
.plan li {
  padding: calc(10 * var(--u)) 0 calc(10 * var(--u)) calc(22 * var(--u));
  position: relative;
  font-size: calc(15 * var(--u));
  line-height: 1.5;
  border-bottom: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--accent) 20%, transparent);
}
.plan li::before {
  content: '';
  position: absolute;
  left: 0;
  top: calc(19 * var(--u));
  width: calc(8 * var(--u));
  height: max(1px, calc(1 * var(--u)));
  background: var(--accent);
}
.plan .btn { align-self: flex-start; }
/* Middle column drops, the same stagger as the review panels. */
.plans > li:nth-child(3n+2) { translate: 0 calc(56 * var(--u)); }
.pkg-section:has(.plans) { padding-bottom: calc(var(--band) + 56 * var(--u)); }

.addons {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(46 * var(--u));
  align-items: start;
}
.addon { background: #fff; padding: calc(46 * var(--u)) calc(44 * var(--u)); }
.addon .display { margin-bottom: calc(20 * var(--u)); }
.addon ul { list-style: none; }
.addon > ul > li { padding: calc(8 * var(--u)) 0; font-size: calc(15 * var(--u)); line-height: 1.5; color: var(--ink); border-bottom: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--accent) 20%, transparent); }
.addon li ul { margin-top: calc(4 * var(--u)); }
.addon li li { padding: calc(2 * var(--u)) 0 calc(2 * var(--u)) calc(18 * var(--u)); color: var(--body); }

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

/* Reference content: the Google review ask, the tagline, a link column and a
   contact column. Rearranged around the centred logo that mirrors the header,
   with the review ask in the middle as a framed plate. The slim bottom bar is
   the previous version's copyright / social / back-to-top row. */
.footer-rule { height: max(2px, calc(3 * var(--u))); background: var(--accent); }

.site-footer {
  background: var(--ink);
  color: color-mix(in srgb, var(--paper) 72%, transparent);
}
.footer-top {
  text-align: center;
  padding: calc(90 * var(--u)) var(--gutter) calc(70 * var(--u));
}
.footer-top img {
  width: calc(170 * var(--u));
  height: auto;
  margin: 0 auto;
  filter: brightness(0) invert(1);
}
.footer-tagline {
  margin-top: calc(22 * var(--u));
  font-family: var(--display);
  font-style: var(--em-style);
  font-size: calc(22 * var(--u));
  color: color-mix(in srgb, var(--paper) 86%, transparent);
}

.footer-cols {
  display: grid;
  grid-template-columns: 1fr minmax(0, 1.3fr) 1fr;
  gap: calc(70 * var(--u));
  align-items: start;
  max-width: calc(1240 * var(--u));
  margin: 0 auto;
  padding: 0 var(--gutter) calc(90 * var(--u));
}
.footer-col { padding-top: calc(50 * var(--u)); }
.footer-col .eyebrow { margin-bottom: calc(20 * var(--u)); }
.footer-col ul { list-style: none; display: grid; gap: calc(14 * var(--u)); }
.footer-col a {
  font-size: calc(11 * var(--u));
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  color: color-mix(in srgb, var(--paper) 78%, transparent);
  transition: color 0.3s ease;
}
.footer-col a:hover { color: var(--accent); }
.footer-col--right { text-align: right; }

.footer-review {
  text-align: center;
  background: color-mix(in srgb, var(--paper) 4%, transparent);
  padding: calc(50 * var(--u)) calc(46 * var(--u));
}
.footer-review .display { color: var(--paper); font-size: calc(30 * var(--u)); }
.footer-review p { margin: calc(14 * var(--u)) 0 calc(28 * var(--u)); font-size: calc(15 * var(--u)); }

.footer-bar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: calc(24 * var(--u));
  padding: calc(26 * var(--u)) var(--gutter);
  border-top: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--paper) 12%, transparent);
}
.footer-bar small,
.footer-bar .to-top {
  font-size: calc(10 * var(--u));
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--paper) 60%, transparent);
  text-decoration: none;
}
.footer-bar .to-top { justify-self: end; transition: color 0.3s ease; }
.footer-bar .to-top:hover { color: var(--accent); }
.footer-social { display: flex; gap: calc(20 * var(--u)); justify-content: center; }
.footer-social img {
  width: calc(17 * var(--u));
  height: calc(17 * var(--u));
  filter: brightness(0) invert(1);
  opacity: 0.62;
  transition: opacity 0.3s ease;
}
.footer-social a:hover img { opacity: 1; }

/* ------------------------------------------------------------------ phone */

/* Below 600px the zoom-shrink is switched off: --u drops back to 1px, so
   every calc() length above becomes the plain design pixel it was drawn at,
   and the overlap grids collapse into a single readable column. */
@media (max-width: 599px) {
  :root {
    --u: 1px;
    --header-h: 64px;
    /* The header sits outside .scale, so it needs its own phone gutter. */
    --gutter: 20px;
  }
  .scale {
    --u: 1px;
    --gutter: 20px;
    --band: 64px;
    font-size: 16px;
  }

  .h1 { font-size: calc(40px * var(--display-scale)); }
  .display, .h2 { font-size: calc(32px * var(--display-scale)); }
  .h3 { font-size: calc(24px * var(--display-scale)); }
  .lede { font-size: 17px; }

  /* Header: logo left, menu button right, links in a drop-down panel. */
  .site-header-inner { grid-template-columns: 1fr auto; padding: 0 var(--gutter); gap: 16px; }
  .site-header.is-solid .site-header-inner { height: 64px; }
  .site-header nav.nav-left,
  .site-header nav.nav-right { display: none; }
  .site-header .logo { grid-column: 1; grid-row: 1; justify-self: start; }
  .site-header .logo img,
  .site-header.is-solid .logo img { width: 104px; }

  /* On phones the ink ground sits on the bar and the panel rather than on
     the header box itself. That lets the backdrop - a negative z-index child
     of the header - paint between the page and the bar without dimming it. */
  .site-header.is-solid,
  .site-header.menu-open { background: transparent; box-shadow: none; }
  .site-header-inner { transition: background-color 0.35s ease, box-shadow 0.35s ease, height 0.35s ease; }
  .site-header.is-solid .site-header-inner,
  .site-header.menu-open .site-header-inner { background: var(--ink); }
  .site-header.is-solid:not(.menu-open) .site-header-inner { box-shadow: 0 1px 0 color-mix(in srgb, var(--accent) 35%, transparent); }

  /* Backdrop: the page dims and softens behind the open menu. A tap on it
     lands on the header element itself, which site.js treats as "close". */
  .site-header::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -1;
    background: color-mix(in srgb, var(--shade) 55%, transparent);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.45s ease, visibility 0s linear 0.45s;
  }
  .site-header.menu-open::before {
    opacity: 1;
    visibility: visible;
    transition: opacity 0.5s ease, visibility 0s;
  }

  .menu-toggle {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    justify-self: end;
    background: none;
    border: 1px solid color-mix(in srgb, var(--paper) 60%, transparent);
    color: var(--paper);
    font: 500 11px/1 var(--ui);
    letter-spacing: 0.22em;
    text-transform: uppercase;
    padding: 10px 14px;
    cursor: pointer;
    transition: border-color 0.4s ease, color 0.4s ease;
  }
  .site-header.menu-open .menu-toggle { border-color: var(--accent); color: var(--accent); }

  /* Two hairlines that meet in the middle, then cross into an X. Opening
     slides them together first and rotates second; closing plays it back. */
  .menu-icon { position: relative; width: 18px; height: 7px; }
  .menu-icon::before,
  .menu-icon::after {
    content: '';
    position: absolute;
    left: 0;
    width: 100%;
    height: 1px;
    background: currentColor;
    transition: transform 0.25s ease, top 0.25s ease 0.2s;
  }
  .menu-icon::before { top: 0; }
  .menu-icon::after { top: 6px; }
  .site-header.menu-open .menu-icon::before,
  .site-header.menu-open .menu-icon::after {
    top: 3px;
    transition: top 0.2s ease, transform 0.4s var(--ease-out) 0.2s;
  }
  .site-header.menu-open .menu-icon::before { transform: rotate(45deg); }
  .site-header.menu-open .menu-icon::after { transform: rotate(-45deg); }

  /* The panel unfolds from the bar. Animating grid rows from 0fr to 1fr
     lets it grow to its natural height without a hard-coded max-height.
     visibility keeps closed links out of the tab order and screen readers,
     and switches only after the fold has finished. */
  .mobile-menu {
    display: grid;
    grid-template-rows: 0fr;
    background: var(--ink);
    visibility: hidden;
    transition: grid-template-rows 0.45s var(--ease-out), visibility 0s linear 0.45s;
  }
  .site-header.menu-open .mobile-menu {
    grid-template-rows: 1fr;
    visibility: visible;
    transition: grid-template-rows 0.65s var(--ease-out), visibility 0s;
  }
  .mobile-menu-inner { min-height: 0; overflow: hidden; }
  .mobile-menu-list { position: relative; padding: 10px var(--gutter) 32px; }

  /* Gold hairline drawn outward from the centre as the panel opens. */
  .mobile-menu-list::before {
    content: '';
    position: absolute;
    top: 0;
    left: var(--gutter);
    right: var(--gutter);
    height: 1px;
    background: color-mix(in srgb, var(--accent) 60%, transparent);
    transform: scaleX(0);
    transition: transform 0.3s ease;
  }
  .site-header.menu-open .mobile-menu-list::before {
    transform: scaleX(1);
    transition: transform 0.8s var(--ease-out) 0.1s;
  }

  .mobile-menu a {
    display: block;
    padding: 14px 0;
    font: 500 12px/1.4 var(--ui);
    letter-spacing: 0.22em;
    text-transform: uppercase;
    text-decoration: none;
    color: var(--paper);
    border-bottom: 1px solid color-mix(in srgb, var(--paper) 10%, transparent);
    opacity: 0;
    transform: translateY(-10px);
    transition: opacity 0.2s ease, transform 0.2s ease;
  }
  .mobile-menu a.nav-cta { color: var(--accent); border-bottom: 0; }

  /* Links arrive one after another as the panel unfolds, and all leave
     together, quickly, on close. */
  .site-header.menu-open .mobile-menu a {
    opacity: 1;
    transform: none;
    transition: opacity 0.5s ease, transform 0.6s var(--ease-out);
  }
  .site-header.menu-open .mobile-menu a:nth-child(1) { transition-delay: 0.14s; }
  .site-header.menu-open .mobile-menu a:nth-child(2) { transition-delay: 0.19s; }
  .site-header.menu-open .mobile-menu a:nth-child(3) { transition-delay: 0.24s; }
  .site-header.menu-open .mobile-menu a:nth-child(4) { transition-delay: 0.29s; }
  .site-header.menu-open .mobile-menu a:nth-child(5) { transition-delay: 0.34s; }
  .site-header.menu-open .mobile-menu a:nth-child(6) { transition-delay: 0.39s; }

  /* Page stays put behind the open menu. */
  html.menu-lock { overflow: hidden; }

  /* A portrait crop of the landscape hero shows only the centre, and the
     couple stand right of centre, 62% of the way down, where the overlaid copy
     would cover them. So on phones the photo sits above the copy, cropped
     towards its right edge, and fades into ink where the copy overlaps it. */
  .hero { height: auto; }
  .hero > img { display: block; height: 62svh; min-height: 380px; object-position: 92% 50%; }
  .hero::after {
    bottom: auto;
    height: max(62svh, 380px);
    background:
      linear-gradient(to bottom, rgba(0,0,0,0.45) 0%, rgba(0,0,0,0) 22%),
      linear-gradient(to top, var(--ink) 0%, color-mix(in srgb, var(--ink) 85%, transparent) 14%, color-mix(in srgb, var(--ink) 0%, transparent) 32%);
  }
  .hero-text { position: relative; left: auto; bottom: auto; margin-top: -90px; padding: 0 var(--gutter) 48px; }
  .page-hero { height: 340px; }

  .proof { padding: 34px var(--gutter); }
  .proof ul { grid-template-columns: 1fr 1fr; row-gap: 28px; }
  .proof li { padding: 0 12px; }
  .proof li:nth-child(3) { border-left: 0; }
  .proof strong,
  .proof .proof-figure { font-size: 32px; }
  .proof span,
  .proof .proof-label { font-size: 10px; }

  /* Scatter grid -> stack. */
  .stories-grid { grid-auto-rows: auto; gap: 18px; }
  .stories-head,
  .stories-grid .framed,
  .stories-grid img,
  .stories-cta,
  .s1, .s2, .s3, .s4, .s5, .s6 { grid-column: 1 / -1; grid-row: auto; }
  .stories-grid img { height: auto; }
  .stories-head { padding: 0 0 12px; }
  .stories-cta { padding-top: 12px; }

  /* Photo on top, cream panel lapping up over its bottom edge. */
  .print { display: block; min-height: 0; padding: 0 0 var(--band); background: #fff; }
  .print > img { position: static; height: 340px; }
  .print::after { display: none; }
  .print-panel { margin: -56px var(--gutter) 0 calc(var(--gutter) + 12px); padding: 40px 28px; }

  .jeff-grid { display: block; }
  .jeff-lede { margin-top: 22px; }
  .jeff-media { margin-top: 44px; min-height: 0; padding-bottom: 60px; }
  .jm1 { width: 72%; margin-left: 12px; }
  .jm2 { top: auto; bottom: 0; left: auto; right: 12px; width: 48%; }
  .jeff-panel { margin-top: 40px; padding: 36px 26px; }
  .mission p { font-size: 22px; }

  .how-grid { grid-template-columns: 1fr; gap: 44px; }
  .how-intro { position: static; }
  .how-steps { padding-left: 22px; }
  .step,
  .step:nth-child(even) { grid-template-columns: 1fr; gap: 6px; margin: 0; padding: 32px 26px; }
  .step + .step { margin-top: 34px; }

  .section-head { flex-direction: column; align-items: flex-start; gap: 20px; margin-bottom: 44px; }
  .section-head .note { text-align: left; }

  .reviews { padding-bottom: var(--band); }
  .reviews-grid,
  .tiers,
  .plans,
  .addons { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  .reviews-grid > li:nth-child(3n+2),
  .plans > li:nth-child(3n+2),
  .tiers > .tier:nth-child(2) { translate: none; }
  .pkg-section:has(.plans) { padding-bottom: var(--band); }
  .review, .tier, .plan, .addon { padding: 40px 28px 32px; }
  /* Lets the 52px price drop under "Starting at" on the narrowest phones. */
  .tier-from { flex-wrap: wrap; }
  .reviews-cta { margin-top: 48px; }

  .fit { grid-template-columns: 1fr; margin: 48px 0 0; padding: 40px 28px; gap: 28px; }

  /* minmax(0, 1fr), not 1fr: a plain 1fr column cannot shrink below its
     longest unbreakable line, which pushed the page wider than a 320px phone. */
  .inquire-grid { grid-template-columns: minmax(0, 1fr); gap: 56px; }
  .inquire-form { grid-template-columns: minmax(0, 1fr); padding: 40px 26px; }
  .contact-list dd a { overflow-wrap: anywhere; }

  .split, .split--reverse { grid-template-columns: 1fr; gap: 40px; }
  .split--reverse .split-copy { order: 0; }
  .cards { grid-template-columns: 1fr; gap: 34px; }

  /* The offset frame needs room the phone width does not have. */
  .framed::before { inset: -12px 12px 12px -12px; }
  .framed--right::before { inset: -12px -12px 12px 12px; }

  .footer-top { padding: 60px var(--gutter) 44px; }
  .footer-cols { grid-template-columns: 1fr; gap: 44px; text-align: center; padding-bottom: 56px; }
  .footer-col--right { text-align: center; }
  .footer-review { order: -1; padding: 36px 24px; }
  .footer-bar { grid-template-columns: 1fr; justify-items: center; text-align: center; gap: 18px; }
  .footer-bar .to-top { justify-self: center; }
}

/* Reduced motion: the phone menu still opens and closes, but with a quick
   fade instead of the unfold, stagger and icon morph. */
@media (max-width: 599px) and (prefers-reduced-motion: reduce) {
  .mobile-menu,
  .mobile-menu a,
  .mobile-menu-list::before,
  .menu-icon::before,
  .menu-icon::after,
  .site-header::before {
    transition-duration: 0.01s !important;
    transition-delay: 0s !important;
  }
}

/* --------------------------------------- src/styles/themes.css (verbatim) */
/*
  Specialty themes. Each one only swaps the tokens declared on :root in
  site.css: colours, the two font families and the heading treatment.
  Layout, spacing and components stay the same across every theme.

  Apply with data-theme="<name>" on <html> for a whole site, or on any
  element to preview a theme inside another page. The fonts each theme names
  are loaded by the <link> built from src/lib/themes.ts.

  Weddings is the default and has no block here: it is :root in site.css.

  Contrast: --accent-strong carries small text and white button labels on
  light grounds, and --accent carries labels on --ink. In every theme below
  both reach 4.5:1 or better on white, --cream, --panel and the warm band.
*/

/* body resolves var(--ui) and var(--body) once, from :root. A themed element
   deeper in the page re-resolves them, or its plain text keeps the fonts of
   the page around it. */
[data-theme] { font-family: var(--ui); color: var(--body); }

/* Evening events: wine ink, rose-gold accent, a high-contrast serif. */
[data-theme='events'] {
  --accent: #cf9a86;
  --accent-strong: #97533f;
  --ink: #2a1a24;
  --shade: #150c12;
  --paper: #fbf7f5;
  --cream: #f6efeb;
  --panel: #eee5e1;
  --body: #4c4146;

  --display: 'Playfair Display', 'Didot', 'Times New Roman', serif;
  --ui: 'Montserrat', 'Helvetica Neue', Arial, sans-serif;
  --display-tracking: -0.01em;
  --display-leading: 1.02;
  --display-scale: 0.95;
}

/* Portraits: forest-green ink, warm clay accent, a soft rounded serif. */
[data-theme='portraits'] {
  --accent: #c79a76;
  --accent-strong: #8e5b3a;
  --ink: #25302a;
  --shade: #111713;
  --paper: #faf8f3;
  --cream: #f3eee4;
  --panel: #ebe5da;
  --body: #4a4e48;

  --display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --ui: 'Nunito Sans', 'Helvetica Neue', Arial, sans-serif;
  --display-weight: 400;
  --display-tracking: -0.02em;
  --display-leading: 1;
  --display-scale: 0.95;
  --em-weight: 300;
}

/* Real estate: navy ink, steel-blue accent, a plain grotesque with no
   italics, so headings read like a business report rather than a card. */
[data-theme='real-estate'] {
  --accent: #7ea6c9;
  --accent-strong: #2b5f8e;
  --ink: #14223a;
  --shade: #0a1220;
  --paper: #f7f9fc;
  --cream: #eff3f7;
  --panel: #e6ebf1;
  --body: #3e4753;

  --display: 'Inter Tight', 'Helvetica Neue', Arial, sans-serif;
  --ui: 'Inter', 'Helvetica Neue', Arial, sans-serif;
  --display-weight: 600;
  --display-tracking: -0.03em;
  --display-leading: 1.02;
  --display-scale: 0.8;
  --em-style: normal;
  --em-weight: 600;
}

/* Athletics and performing arts: near-black ink, blaze-orange accent, heavy
   condensed capitals with a slanted emphasis word. */
[data-theme='athletics'] {
  --accent: #ff6b1a;
  --accent-strong: #b93d0b;
  --ink: #0f1218;
  --shade: #07090c;
  --paper: #ffffff;
  --cream: #f3f5f8;
  --panel: #eaedf1;
  --body: #353b44;

  --display: 'Barlow Condensed', 'Arial Narrow', Impact, sans-serif;
  --ui: 'Barlow', 'Helvetica Neue', Arial, sans-serif;
  --display-weight: 800;
  --display-tracking: 0.005em;
  --display-leading: 0.9;
  --display-case: uppercase;
  --display-scale: 1.08;
  --em-weight: 800;
}

/* ------------------------- src/pages/specialties/_specialties.css (verbatim) */
/*
  The specialty sites' additions, without the @layer wrapper for the reason
  given at the top of this file.
*/
/* Stand-in where Jeff has not supplied a photo for a specialty yet. */
.sp-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(12 * var(--u));
  width: 100%;
  height: 100%;
  padding: calc(24 * var(--u));
  text-align: center;
  background:
    repeating-linear-gradient(135deg, color-mix(in srgb, var(--accent) 8%, transparent) 0 calc(14 * var(--u)), transparent calc(14 * var(--u)) calc(28 * var(--u))),
    var(--ink);
}
.sp-placeholder .eyebrow { color: var(--accent); }
.sp-placeholder-label {
  font-family: var(--display);
  font-style: var(--em-style);
  font-size: calc(26 * var(--u));
  line-height: 1.2;
  color: color-mix(in srgb, var(--paper) 86%, transparent);
}
/* In a hero the label would sit under the headline, so only the pattern shows. */
.hero > .sp-placeholder > * { display: none; }

.card .sp-placeholder,
.sp-split-photo { aspect-ratio: 3 / 4; }
.sp-split-photo { width: 100%; object-fit: cover; }

/* Specialty cards: the About page's .card, as whole-card links. */
.sp-specialties { padding: var(--band) var(--gutter); }
.sp-specialties .section-head { max-width: calc(1240 * var(--u)); margin-left: auto; margin-right: auto; }
.sp-card-grid {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: calc(70 * var(--u)) calc(46 * var(--u));
  max-width: calc(1240 * var(--u));
  margin: 0 auto;
}
.sp-card-link { display: block; text-decoration: none; }
.sp-card-link p { margin-bottom: calc(18 * var(--u)); }
.sp-card-link:hover .display { color: var(--accent-strong); }
.sp-domain { margin-top: calc(26 * var(--u)); text-transform: none; letter-spacing: 0.08em; }
.sp-domain + .display { margin-top: calc(8 * var(--u)); }

.sp-breadcrumb { padding: calc(28 * var(--u)) var(--gutter) 0; }
.sp-breadcrumb ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: calc(10 * var(--u));
  max-width: calc(1240 * var(--u));
  margin: 0 auto;
  font-size: calc(11 * var(--u));
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.sp-breadcrumb li + li::before { content: '/'; margin-right: calc(10 * var(--u)); color: var(--accent); }
.sp-breadcrumb a { color: var(--accent-strong); text-decoration: none; }
.sp-breadcrumb [aria-current] { color: var(--ink); }

.sp-expect-title { margin-top: calc(30 * var(--u)); }
.sp-expect { list-style: none; margin-top: calc(10 * var(--u)); border-top: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--accent) 35%, transparent); }
.sp-expect li {
  position: relative;
  padding: calc(10 * var(--u)) 0 calc(10 * var(--u)) calc(22 * var(--u));
  font-size: calc(15 * var(--u));
  line-height: 1.5;
  color: var(--ink);
  border-bottom: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--accent) 20%, transparent);
}
.sp-expect li::before {
  content: '';
  position: absolute;
  left: 0;
  top: calc(19 * var(--u));
  width: calc(8 * var(--u));
  height: max(1px, calc(1 * var(--u)));
  background: var(--accent);
}

/* Sideways links to the other specialties at the same level. */
.sp-more { padding: var(--band) var(--gutter); }
.sp-more-inner { max-width: calc(1240 * var(--u)); margin: 0 auto; }
.sp-more ul {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: calc(24 * var(--u)) calc(46 * var(--u));
  margin-top: calc(26 * var(--u));
}
.sp-more a {
  display: block;
  height: 100%;
  padding: calc(30 * var(--u)) calc(32 * var(--u));
  background: #fff;
  text-decoration: none;
  font-size: calc(15 * var(--u));
  transition: transform 0.25s ease;
}
.sp-more a:hover { transform: translateY(-2px); }
.sp-more .display { display: block; margin-bottom: calc(10 * var(--u)); }

/* Footer plate on a genre site: links to the other genre sites. */
.sp-other-sites { list-style: none; display: grid; gap: calc(12 * var(--u)); margin-top: calc(22 * var(--u)); }
.sp-other-sites a {
  font-size: calc(11 * var(--u));
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  color: color-mix(in srgb, var(--paper) 78%, transparent);
}
.sp-other-sites a:hover { color: var(--accent); }

.inquire-form select {
  width: 100%;
  font: inherit;
  font-size: calc(16 * var(--u));
  color: var(--ink);
  background: #fff;
  border: max(1px, calc(1 * var(--u))) solid color-mix(in srgb, var(--ink) 18%, transparent);
  border-radius: 0;
  padding: calc(12 * var(--u)) calc(14 * var(--u));
}

/* Prototype label, bottom left. Not part of the design. */
.sp-concept {
  position: fixed;
  left: 12px;
  bottom: 12px;
  z-index: 90;
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: calc(100vw - 24px);
  padding: 7px 12px;
  background: color-mix(in srgb, var(--ink) 92%, transparent);
  border: 1px solid var(--accent);
  font: 500 11px/1.3 var(--ui);
  letter-spacing: 0.06em;
  color: var(--paper);
}
.sp-concept span { color: var(--accent); text-transform: uppercase; letter-spacing: 0.18em; white-space: nowrap; }
.sp-concept strong { min-width: 0; overflow-wrap: anywhere; }
.sp-concept a { color: var(--accent); white-space: nowrap; }

.site-header.menu-open .mobile-menu a:nth-child(7) { transition-delay: 0.44s; }
.site-header.menu-open .mobile-menu a:nth-child(8) { transition-delay: 0.49s; }
.site-header.menu-open .mobile-menu a:nth-child(9) { transition-delay: 0.54s; }

@media (max-width: 599px) {
  .hero > .sp-placeholder { height: 62svh; min-height: 380px; }
  .sp-placeholder-label { font-size: 22px; }
  .sp-card-grid,
  .sp-more ul { grid-template-columns: minmax(0, 1fr); gap: 44px; }
  .sp-more ul { gap: 16px; }
  .sp-more a { padding: 24px; }
  .sp-breadcrumb ol { font-size: 10px; }
  .page-hero > .sp-placeholder { height: 100%; min-height: 0; }
}

/* ------------------------------------------- WordPress block markup seams */
/*
  The only rules in this file that are not in the Astro sources. Each one
  exists because a core block emits an extra wrapper the Astro markup did not
  have. They re-point existing rules at the generated element; none of them
  changes a design value, and none uses !important.
*/

/* core/navigation wraps its links in <ul><li>; Layout.astro:43-45 had bare
   anchors as direct flex children of the nav. display: contents removes the
   two wrappers from layout so the anchors are flex children again. */
.nav-left .wp-block-navigation__container,
.nav-right .wp-block-navigation__container,
.nav-left .wp-block-navigation-item,
.nav-right .wp-block-navigation-item {
  display: contents;
}

/* core/cover is the hero element. The ported .hero rules (site.css:360-398)
   supply the frame — height, overflow, the ink ground and the ::after
   overlay — so cover's own framing has to stand down. The copy inside is a
   group carrying the design's own .hero-text or .page-hero-text class, which
   is why none of those rules are repeated here. */
.hero.wp-block-cover {
  display: block;
  min-height: 0;
  padding: 0;
  align-items: initial;
  justify-content: initial;
}

/* core/cover puts the copy inside .wp-block-cover__inner-container, and core
   gives that wrapper position: relative. Both hero texts are positioned
   against the hero itself - .hero-text at site.css:389 sits on its bottom
   edge, .page-hero-text at site.css:410 fills it - so the relative wrapper
   becomes their containing block instead, and it is only as tall as its own
   content. Measured: the wrapper computed to 0px tall and .hero-text landed
   at y -592, above the top of the page. Taking the wrapper out of positioning
   hands the job back to .hero, which is already position: relative. */
.hero.wp-block-cover > .wp-block-cover__inner-container {
  position: static;
}

/* The full-bleed photo bands. site.css:962, site.css:842 and site.css:787
   place a bare img child; core/image wraps every photo in a <figure>, so the
   figure takes the place the img had and the img fills it. Same values, one
   element further out. */
.closing > .wp-block-image,
.inquire > .wp-block-image,
.print > .wp-block-image {
  position: absolute;
  inset: 0;
  margin: 0;
}
.closing > .wp-block-image img,
.inquire > .wp-block-image img,
.print > .wp-block-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Photographs placed on a grid. site.css:766-771 and site.css:889-891 place
   the photo itself; core/image's <figure> is now the grid or positioned item,
   so it takes the placement and the photo fills it. The .s* and .jm* classes
   ride on the figure, which is what carries them in the patterns. */
.stories-grid > .wp-block-image,
.jeff-media > .wp-block-image {
  /* margin-block only: core/image's bottom margin has to go, but .jm1 at
     site.css:890 sets its own margin-left, and a margin shorthand here would
     wipe it out. */
  margin-block: 0;
}
.stories-grid > .wp-block-image {
  height: 100%;
}

/* Tall is what .hero already is. Restated against the variation class so the
   choice is explicit and switching back from Short always lands here. */
.hero.is-style-hero-tall {
  height: calc(900 * var(--u));
}

/* Short is the .page-hero block at site.css:400-417, which in the Astro
   markup was a second class on the same element. Values unchanged; only the
   selector moves, from .page-hero to the Cover block's variation class. */
.hero.is-style-hero-short {
  height: calc(560 * var(--u));
}
.hero.is-style-hero-short::after {
  background: linear-gradient(to bottom, color-mix(in srgb, var(--ink) 60%, transparent) 0%, color-mix(in srgb, var(--ink) 42%, transparent) 100%);
}
.hero.is-style-hero-short .page-hero-text {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--header-h) var(--gutter) 0;
}
.hero.is-style-hero-short .display { color: var(--paper); }
.hero.is-style-hero-short .display em { color: var(--accent); }
.hero.is-style-hero-short .eyebrow { color: var(--accent); }

@media (max-width: 599px) {
  /* site.css:1297-1298 lets the photo size the tall hero on phones. Cover
     takes its image out of flow, so put it back. */
  .hero.wp-block-cover > img.wp-block-cover__image-background {
    position: relative;
  }

  /* The phone photo height and crop from site.css:1298. Core's
     .wp-block-cover .wp-block-cover__image-background { height: 100% } is
     (0,2,0) and beats .hero > img (0,1,1), which left the photo only as
     tall as the auto-height hero allowed and the copy lying over its lower
     half. The short hero keeps its fixed height and full-height photo. */
  .hero.is-style-hero-tall > img.wp-block-cover__image-background {
    display: block;
    height: 62svh;
    min-height: 380px;
    object-position: 92% 50%;
  }

  .hero.is-style-hero-tall { height: auto; }
  .hero.is-style-hero-short { height: 340px; }

  /* site.css:1329 puts the print photo back in the flow above the panel on
     phones. The figure core/image wraps it in is what the full-bleed rule
     above made absolute, so the figure goes back in the flow and the photo
     keeps the phone height. */
  .print > .wp-block-image { position: static; }
  .print > .wp-block-image img { height: 340px; }
}

/* Core doubles a class on purpose to raise its own specificity:
   .wp-block-navigation .wp-block-navigation-item__content.wp-block-navigation-item__content
   { color: inherit } is (0,3,0) and beats site.css:324, leaving the links the
   body grey instead of --paper. Re-point the colour alone, one class higher. */
.site-header :is(.nav-left, .nav-right) a.wp-block-navigation-item__content {
  color: var(--paper);
}

/* A navigation link's className lands on its <li>, not on the <a>, so
   a.nav-cta (site.css:341-346) never matches. Same declarations, re-pointed
   at the anchor inside the marked item. */
.site-header :is(.nav-left, .nav-right) .nav-cta a {
  padding: calc(10 * var(--u)) calc(18 * var(--u));
  border: max(1px, calc(1 * var(--u))) solid var(--accent);
  color: var(--accent);
}
.site-header :is(.nav-left, .nav-right) .nav-cta a:hover {
  background: var(--accent);
  color: var(--ink);
}

/* The footer columns are core/navigation too, so the client edits them in
   Site Editor > Navigation. site.css:1134-1145 was written for a plain
   <ul><li><a>. Core makes each item a flex box and each link a block, which
   drops the line box the gap was measured with and ignores the right-hand
   column's text-align, and its doubled class again overrides the colour.
   Put the item, the link and the colour back as the list had them. A
   specialty site's "Also by Jeff" plate is the same kind of list. */
.site-footer :is(.footer-col, .sp-other-sites) .wp-block-navigation-item { display: list-item; }
.site-footer :is(.footer-col, .sp-other-sites) .wp-block-navigation-item__content { display: inline; }
.site-footer :is(.footer-col, .sp-other-sites) a.wp-block-navigation-item__content {
  color: color-mix(in srgb, var(--paper) 78%, transparent);
}
.site-footer :is(.footer-col, .sp-other-sites) a.wp-block-navigation-item__content:hover { color: var(--accent); }

/* core/button wraps its anchor in a <div class="wp-block-button">. The .btn
   and .text-link treatments belong on the anchor, which is the click target
   and the element the ported rules were written for, so the selectors above
   grew a second form rather than having their declarations copied.

   The wrapper then only has to stop being a block: inline-flex shrink-wraps
   the anchor, so the wrapper is exactly the size of the button and behaves as
   the bare <a> did inside .btn-row and .stories-cta. display: contents would
   also work visually, but an element with no box measures zero wide, and
   matrix.spec.js:42-51 reads every element's width against its parent's to
   catch layout escapes. */
.wp-block-button:is(.btn, .text-link) {
  display: inline-flex;
}

/* The block's className lands on that wrapper, so the bare .btn, .btn--*
   and .text-link selectors match it as well as the anchor, and the wrapper
   drew a second box: a border and 28 design px of padding either side of the
   anchor's own (a double outline on ghost and outline buttons, a double
   underline on text links, and every solid button 56 design px wider than
   in Astro). Only the anchor is the button; the wrapper draws nothing. Two
   classes, so this outranks .btn--solid:hover by source order and the
   single-class variants outright. */
.wp-block-button:is(.btn, .text-link),
.wp-block-button:is(.btn, .text-link):hover {
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  transform: none;
}

/* core/button's own stylesheet pads the anchor with
   :where(.wp-block-button__link) { padding: calc(.667em + 2px) ... }. The
   .btn rules replace that padding outright, but .text-link (site.css:265) is
   an underlined word, not a box, and only ever set padding-bottom, so the
   other three sides were coming from core. A :where() selector carries no
   specificity, so naming them here is enough. */
.wp-block-button.text-link > .wp-block-button__link {
  padding: 0 0 calc(3 * var(--u));
}

/* core/separator is an <hr>, and core gives every separator a 100px width and
   a pair of borders. .rule-v (site.css:284) and .footer-rule (site.css:1145)
   draw themselves with width, height and background, so both borders and the
   width cap have to go. */
.wp-block-separator:is(.rule-v, .footer-rule) {
  border: 0;
  width: auto;
  opacity: 1;
}
.wp-block-separator.rule-v {
  width: max(1px, calc(1 * var(--u)));
  opacity: 0.7;
}

/* core/quote brings its own left border, margin and padding at the same
   specificity as .mission (site.css:720), so source order would decide which
   wins depending on when core prints its block styles. One extra class makes
   the design's own values unambiguous. */
.wp-block-quote.mission {
  margin: calc(34 * var(--u)) 0 calc(38 * var(--u));
  padding-left: calc(26 * var(--u));
  border-left: max(1px, calc(2 * var(--u))) solid var(--accent);
  border-right: 0;
}
/* core/quote's citation has no class control, so the <cite> lost the eyebrow
   class the Astro markup gave it. Same treatment as .eyebrow (site.css:261),
   re-pointed at the element. */
.wp-block-quote.mission cite {
  font-family: var(--ui);
  font-size: calc(11 * var(--u));
  font-weight: 500;
  letter-spacing: 0.22em;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--accent-strong);
}

/* The skip link and the back-to-top link are paragraphs now, so the class the
   ported rules key on sits on the <p> and the anchor is inside it. :focus
   fires on the anchor, which is why the skip link reveals itself on
   :focus-within. */
.skip-link:focus-within {
  left: 0;
}
.footer-bar .to-top a {
  color: inherit;
  text-decoration: none;
}

/* ------------------------------------ specialty sites: block markup seams */
/*
  src/pages/specialties/_specialties.css was written for the Astro markup.
  Where a core block cannot produce that markup, the rule is re-pointed here.
*/

/* A specialty site's phone menu is a Navigation block in its header part.
   functions.php moves its links into the phone panel and prints nothing where
   it sits, so this only hides it inside the Site Editor, where it is reached
   through List View. */
.site-header-inner > .nav-mobile { display: none; }

/* "Also by Jeff": _specialties.css:114 put the list layout on a <ul>; the
   Navigation block carries the class on its <nav> and prints the <ul> inside. */
.sp-other-sites { margin-top: calc(22 * var(--u)); }
.sp-other-sites .wp-block-navigation__container { display: grid; gap: calc(12 * var(--u)); }
.site-footer .sp-other-sites a.wp-block-navigation-item__content {
  font-size: calc(11 * var(--u));
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
}

/* The hero without a photo. _Shot.astro put a .sp-placeholder inside the
   hero; the Cover block shows the page's featured image instead, so the
   pattern is drawn on the Cover itself and a featured image covers it. */
.hero.hero--placeholder {
  background:
    repeating-linear-gradient(135deg, color-mix(in srgb, var(--accent) 8%, transparent) 0 calc(14 * var(--u)), transparent calc(14 * var(--u)) calc(28 * var(--u))),
    var(--ink);
}

/* Whole-card links. Astro wrapped each card in one <a class="sp-card-link">
   (_specialties.css:48-50); no core block can hold a heading, a photo and a
   paragraph inside a link. The heading holds the link, and its ::after is
   stretched over the card, so the whole card is still one click target and
   one link for a screen reader. */
.sp-card { position: relative; }
.sp-card h3 a { color: inherit; text-decoration: none; }
.sp-card h3 a::after { content: ''; position: absolute; inset: 0; }
.sp-card > p:not(.sp-card-more) { margin-bottom: calc(18 * var(--u)); }
.sp-card:hover .display { color: var(--accent-strong); }
/* A photo in the frame, and the placeholder standing in for one, fill the
   card's width the way the <img> did. */
.sp-card .wp-block-image { margin: 0; }

/* The placeholder's two lines were <span>s; as paragraphs inside a card,
   .card p (site.css:1014) is more specific and shrank both to body size. */
.card .sp-placeholder > .eyebrow { font-size: calc(11 * var(--u)); }
.card .sp-placeholder > .sp-placeholder-label { font-size: calc(26 * var(--u)); }
@media (max-width: 599px) {
  .card .sp-placeholder > .sp-placeholder-label { font-size: 22px; }
}

/* core/image puts the class on its <figure>; _specialties.css:34-35 sized the
   <img>. */
.wp-block-image.sp-split-photo { aspect-ratio: auto; margin: 0; }
.wp-block-image.sp-split-photo img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; }

/* The breadcrumb's current page. Rich text drops aria-current, so the list
   item is marked with a class instead (_specialties.css:69). */
.sp-breadcrumb .is-current { color: var(--ink); }

/* Sideways links. Each tile was one <a> (_specialties.css:101-111); here the
   tile is the list item and the name's link is stretched over it. */
.sp-more-item {
  position: relative;
  height: 100%;
  padding: calc(30 * var(--u)) calc(32 * var(--u));
  background: #fff;
  font-size: calc(15 * var(--u));
  transition: transform 0.25s ease;
}
.sp-more-item:hover { transform: translateY(-2px); }
.sp-more .sp-more-item a { display: inline; height: auto; padding: 0; background: none; color: inherit; font-size: inherit; }
.sp-more-item a::after { content: ''; position: absolute; inset: 0; }

@media (max-width: 599px) {
  .sp-more-item { padding: 24px; }
}

/* On phones the tall hero's photo sits above the copy and gives the hero its
   height (site.css:1298). With no photo there is nothing to do that, so the
   placeholder keeps the same height the photo would have taken,
   _specialties.css:162. Once a featured image is set, the photo takes over. */
@media (max-width: 599px) {
  .hero.is-style-hero-tall.hero--placeholder:not(:has(> .wp-block-cover__image-background)) {
    padding-top: max(62svh, 380px);
  }
}
