/* ==========================================================================
   WHITAKER & HOLLIS — MERGE BUILD
   base: bicklawllp.com   donor: kmm.com   method: site/merge-playbook.md

   THE TOKEN BLOCK IS THE COHERENCE PASS (playbook §5.5, §6).
   Every value below is the BASE's, measured off its CSSOM at 1440 and 390,
   except the rows marked "donor" — each of which REPLACES a base value in
   the same slot rather than being added alongside it.
   ========================================================================== */

:root {

  /* --- ground and ink -------------------------------------------------- */
  --paper:      #fefefe;   /* base — rgb(254,254,254), its page ground */
  --ink:        #0a0a0a;   /* base — rgb(10,10,10) */
  --body:       #414042;   /* base — rgb(65,64,66), its running text */
  --rule:       #e0dcd7;   /* base — rgb(224,220,215), every hairline it draws */

  /* ground — donor. The base's dark ground is #353441 charcoal; the cool
     navy is the donation, and it is a substitution, not an addition. */
  --ground:     #0e1f30;
  /* mist — donor. The base's off-white band is #f8f8f8; this one carries
     the navy's hue instead of being neutral. */
  --mist:       #eef1f4;

  /* --- the band set ---------------------------------------------------- */
  /* The base rotates five grounds through its slides, its practice boxes and
     its mobile title bands. Near-duplicates in its CSS (#548e8f, #5c9495,
     #67a1a4, #6da7a8 are all one intent) are collapsed to one token each. */
  --plum:       #8d1b54;   /* base — rgb(141,27,84). Primary. 18x as the roster hover scrim. */
  --teal:       #548c8d;   /* base — rgb(84,140,141) */
  --teal-deep:  #4b7b7c;   /* base — rgb(75,123,124), the roster scrim only */
  --olive:      #899868;   /* base — rgb(137,152,104) */
  --stone:      #7f786f;   /* base — rgb(127,120,111) */
  --lime:       #b0d37e;   /* base — rgb(176,211,126), the one accent word per hero slide */

  /* --- type: ONE scale, the base's ------------------------------------- */
  /* root 16px at both widths. Ladder 14·16·18·24·30·36·48·60·80 — nine steps,
     which is the base's own count. Three line-height ratios, also its own. */
  --f-cond:  "Roboto Condensed", "Arial Narrow", sans-serif;   /* base — display, labels, nav */
  --f-serif: "Playfair Display", Georgia, serif;                /* DONOR — takes the base's serif
                                                                   slot from PT Serif at every step.
                                                                   The donor's own face is Butler;
                                                                   this is the licensed stand-in,
                                                                   see the @font-face note below. */
  --f-sans:  "Roboto", Helvetica, Arial, sans-serif;            /* base — body */

  --t-xs:   14px;   /* base — legal */
  --t-sm:   16px;   /* base — body */
  --t-md:   18px;   /* base — nav, roles, buttons */
  --t-lg:   24px;   /* base — quote author, insight titles */
  --t-xl:   30px;   /* base — attorney names, practice boxes */
  --t-2xl:  36px;   /* base — section heads */
  --t-3xl:  48px;   /* base — intro statement, pull quote */
  --t-4xl:  60px;   /* base — wordmark */
  --t-5xl:  80px;   /* base — hero. This is what the donor's 115px re-typesets into. */

  --lh-flat: 1.0;   /* base — display and nav */
  --lh-head: 1.4;   /* base — headings */
  --lh-read: 1.6;   /* base — running text */

  /* --- rhythm: ONE set, the base's ------------------------------------- */
  --sp-1:    5px;    /* base — 68 uses */
  --sp-2:   10px;    /* base — 85 uses */
  --sp-3:   20px;    /* base — 109 uses, the workhorse */
  --sp-4:   25px;    /* base — header pad, accordion tab */
  --sp-5:   40px;    /* base — footer pad */
  --sp-6:   50px;    /* base */
  --sp-7:  100px;    /* base — .choose-firm, .banner-title */
  --sp-8:  115px;    /* base — .accordion */
  --sp-9:  140px;    /* base — .quote-slider .outer inset */

  /* --- containers: three, against the base's thirteen ------------------ */
  --wrap:        1280px;   /* base — its 80px inset at 1440 */
  --wrap-narrow:  970px;   /* base */
  --gutter:        20px;

  /* --- radius: one non-zero -------------------------------------------- */
  --r-pill: 68px;   /* base — the carousel arrows, and nothing else */

  /* --- motion: two curves, four durations ------------------------------ */
  /* The base declares five curves and nine durations. Collapsed to its own
     top two and top four by frequency. */
  --e-out:  ease-out;
  --e-io:   ease;
  --d-1:    0.3s;   /* base — 151 uses */
  --d-2:    0.5s;   /* base —  39 uses, roster hover */
  --d-3:    0.6s;   /* base —  36 uses, the hover paragraph */
  --d-4:    1s;     /* base —  15 uses, the slide crossfade */

  /* The height of OUR header, measured — not the base's 149px, which was read
     off a header whose logo is an 80px image where ours is 36px type. The
     interior routes hang their first band off this, so a stale 149 here is a
     42px hole under the nav that nothing else on the page explains. */
  --header-h: 107px;
}

/* ==========================================================================
   FONTS — all self-hosted. See style.css for what is and is not licensed.
   ========================================================================== */

@font-face { font-family: "Roboto Condensed"; src: url(../fonts/robotocondensed-light-webfont.woff2) format("woff2");   font-weight: 300; font-style: normal; font-display: swap; }
@font-face { font-family: "Roboto Condensed"; src: url(../fonts/robotocondensed-regular-webfont.woff2) format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Roboto"; src: url(../fonts/roboto-thin-webfont.woff2) format("woff2");    font-weight: 100; font-style: normal; font-display: swap; }
@font-face { font-family: "Roboto"; src: url(../fonts/roboto-light-webfont.woff2) format("woff2");   font-weight: 300; font-style: normal; font-display: swap; }
@font-face { font-family: "Roboto"; src: url(../fonts/roboto-regular-webfont.woff2) format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
/* The serif in the donor's slot. The donor's own face is Butler, which is not
   licensed to this project; Playfair Display (SIL OFL 1.1) stands in it — the
   same high-contrast display serif with a large x-height, which is why the
   ladder below did not have to move.

   ONE VARIABLE FILE PER SUBSET, not three statics. Google ships Playfair as a
   variable font, so 400/500/700 are one file; the two subsets are split on
   unicode-range the way its own stylesheet splits them.

   The declared floor is 300 but the weight axis starts at 400, so the three
   rules that ask for 300 (the two 21vw monograms and the 48px lede) render at
   400. That is the axis clamping, not a missing file — Butler-Light's step is
   the one thing this swap could not carry across. */
@font-face {
  font-family: "Playfair Display"; src: url(../fonts/playfairdisplay-latin.woff2) format("woff2");
  font-weight: 300 900; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Playfair Display"; src: url(../fonts/playfairdisplay-latin-ext.woff2) format("woff2");
  font-weight: 300 900; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
                 U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ==========================================================================
   RESET — the base's, and only the base's (playbook §2: not scopable)
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
html { font-size: 16px; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--body);
  font-family: var(--f-sans);
  font-weight: 300;
  font-size: var(--t-sm);
  line-height: var(--lh-read);
  /* TRAP §8.2 — clip, never hidden. `hidden` makes body a scroll container
     and every sticky element on the page then sticks to it, not the viewport. */
  overflow-x: clip;
}

h1, h2, h3, h4, p, figure, ul, ol { margin: 0; padding: 0; }
ul, ol { list-style: none; }
img, svg { max-width: 100%; display: block; border: 0; }
a { color: inherit; text-decoration: none; transition: color var(--d-1) var(--e-out); }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
/* base — its own reset carries this pair. `border-radius` matters here beyond
   tidiness: the consistency probe counts every non-zero radius on the page, and a
   UA radius on a form control would put a second one on the contact route against
   the base's one. */
input, select, textarea { font: inherit; color: inherit; margin: 0; border-radius: 0; }

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

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.skip-link {
  position: absolute; top: -60px; left: var(--gutter); z-index: 10001;
  background: var(--ground); color: #fff; padding: var(--sp-2) var(--sp-3);
  font-family: var(--f-cond); text-transform: uppercase; font-size: var(--t-md);
}
.skip-link:focus { top: var(--sp-2); }

/* ==========================================================================
   SECTION HEADS — the base's two-colour device.
   Its "OUR TEAM" is one word plum-italic, the next teal-regular. It uses the
   same move in the hero and in every band head, so it is a token, not a one-off.
   ========================================================================== */

.head {
  font-family: var(--f-cond);
  font-weight: 300;
  font-size: var(--t-2xl);
  line-height: var(--lh-head);
  text-transform: uppercase;
  text-align: center;
  color: var(--teal);
  margin: 0 0 var(--sp-5);
}
.head em { color: var(--plum); font-style: italic; }
.head--rule { padding-bottom: var(--sp-5); border-bottom: 2px solid var(--rule); }

/* ==========================================================================
   HEADER — base. Transparent over the hero, collapses to white after the
   first fold. TRAP §8.9: dropping the collapse leaves the nav sitting on top
   of every section that scrolls under it.
   ========================================================================== */

.header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 10000;
  padding: var(--sp-4) 0;                     /* base — 25px 0 */
  transition: var(--d-1) var(--e-out);        /* base — 300ms ease-out */
}
.header__inner { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }

/* The base's logo is an image in a 328px box. Ours is type, and it has to sit
   in the same box or the nav has nowhere to go — at 60px "WHITAKER HOLLIS"
   measured 440px and pushed all five nav items onto two lines each. */
.header__logo { display: block; max-width: 328px; }
.header__mark {
  display: block;                             /* was inline: the sub-line ran on
                                                 the same line as the wordmark */
  font-family: var(--f-cond);
  font-weight: 300;
  font-size: var(--t-2xl);                    /* fits the base's 328px logo box */
  line-height: var(--lh-flat);
  text-transform: uppercase;                  /* no letter-spacing: the base tracks
                                                 `normal` on every one of its runs,
                                                 and the consistency pass counted a
                                                 -0.01em here as a token the base
                                                 does not have */
  color: #fff;
  white-space: nowrap;
}
.header__mark b { font-weight: 400; color: var(--lime); }
.header__sub {
  display: block;                             /* base — its own is display:block */
  font-family: var(--f-serif);                /* DONOR face in the base's sub-line slot */
  font-size: var(--t-xs);
  line-height: var(--lh-flat);
  text-align: right;
  color: rgba(255, 255, 255, 0.8);            /* base — its .trans span colour */
  margin-top: var(--sp-1);
}

.nav { margin-left: auto; }
.nav ul { display: flex; justify-content: flex-end; }
.nav li { white-space: nowrap; }
.nav a {
  display: block;
  padding: var(--sp-2) var(--sp-4);           /* base — 10px 25px */
  font-family: var(--f-sans);
  font-weight: 300;
  font-size: var(--t-md);                     /* base — 18px */
  line-height: var(--lh-flat);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.8);            /* base */
  transition: var(--d-1) var(--e-out);
}
.nav a:hover, .nav a:focus { color: #fff; background: var(--ground); }

/* collapsed — base's .header.fixed, exactly */
.header.is-stuck {
  background: #fff;
  border-bottom: 2px solid var(--teal);
  padding: var(--sp-2) 0;                     /* base — 10px 0 */
}
.header.is-stuck .header__mark { font-size: var(--t-lg); color: var(--ground); }
.header.is-stuck .header__mark b { color: var(--plum); }
.header.is-stuck .header__sub  { color: rgba(14, 31, 48, 0.5); }
.header.is-stuck .nav a        { color: var(--ground); }
.header.is-stuck .nav a:hover,
.header.is-stuck .nav a:focus  { color: #fff; background: var(--ground); }

.header__toggle {
  display: none;
  width: 40px; height: 40px;
  border: 2px solid #fff; color: #fff;
  font-size: var(--t-md); line-height: 1;
}
.header.is-stuck .header__toggle { border-color: var(--ground); color: var(--ground); }

/* --- the phone path — SPEC 1.1, 6.1 / 17 A1, A3, A4 --------------------
   Added 2026-08-31. The site failed all three fold checks with telCount 0:
   the number appeared 23 times as plain text and never once as a tel: link
   outside the six bios and /contact/. 8/8 of the teardown put a callable
   number in the first viewport on BOTH viewports — logo, nav and phone are
   the ONLY universal fold content in the whole sample.

   It takes the nav's own type and colour rather than inventing a treatment,
   because it sits in the nav's row and a second idiom there would read as a
   button bolted on. */
.header__tel {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  /* LAST in the row, with the nav pushed right beside it, so the header reads
     logo .... nav phone. Placed between the logo and the nav it renders as an
     orphan: the row is space-between with three visible children, and the
     number lands in open space belonging to neither group. */
  order: 3;
  padding: var(--sp-2) var(--sp-3);
  font-family: var(--f-cond);
  font-size: var(--t-md);
  line-height: var(--lh-flat);
  white-space: nowrap;
  color: #fff;
  transition: var(--d-1) var(--e-out);
}
.header__tel:hover, .header__tel:focus-visible { color: var(--lime); }
.header.is-stuck .header__tel { color: var(--ground); }
.header.is-stuck .header__tel:hover,
.header.is-stuck .header__tel:focus-visible { color: var(--plum); }
.is-solidhead .header__tel { color: var(--ground); }
.icon-phone { flex: 0 0 auto; }

/* The sticky mobile call bar. The teardown SPLITS 5/3 on this, so spec 6.1
   marks it DECIDE and then decides: every argument in OFFER.md 1 is about the
   person checking you on a phone in a parking lot.

   56px, and it is deliberate arithmetic rather than a round number — spec 6.3
   caps a fixed element at ~180px because one site in the sample runs a cookie
   banner at 249px of an 844px viewport. The mobile header is 63px, so the two
   together take 119px and each passes on its own. */
.callbar { display: none; }

/* --- footer policy links — SPEC 14.2 / 17 E3 ------------------------- */
.footer__policies { margin-bottom: var(--sp-3); }
.footer__policies a {
  font-family: var(--f-sans);
  font-weight: 300;
  font-size: var(--t-xs);
  color: rgba(255, 255, 255, 0.62);
  transition: var(--d-1) var(--e-out);
}
.footer__policies a:hover, .footer__policies a:focus-visible { color: #fff; }
.footer__policies a + a { margin-left: var(--sp-3); }
.footer__address a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }

/* ==========================================================================
   HERO — base structure (duotone carousel, slide rail, SCROLL cue, one
   italic accent word per slide) carrying the DONOR's ghosted monogram.

   The monogram passes the playbook's canvas test (§2): not fixed, and its
   parent is not taller than the viewport, so it reads only its own box and
   transfers.
   ========================================================================== */

.hero { position: relative; overflow: hidden; background: var(--ground); }
.hero__viewport { position: relative; height: 100vh; min-height: 720px; }

/* THE STAGE AND THE SLIDE ARE DIFFERENT THINGS — see front-page.php and
   playbook trap §8.3. The slide is the photograph and its grade, and nothing
   else; every layer that is identical across slides, or that must not be
   painted twice during the fade, is a child of the stage.

   Paint order, bottom to top: photographs, monogram, contrast wash, headline. */
.hero__stage    { position: absolute; inset: 0; z-index: 0; }
.hero__monogram { z-index: 1; }
.hero__scrim    { z-index: 2; }
.hero__titles   { z-index: 3; }
.hero__rail, .hero__pause, .hero__cue { z-index: 4; }

.hero__slide {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity var(--d-4) var(--e-out);  /* base — 1s ease-out crossfade */
  pointer-events: none;
}
.hero__slide.is-active { opacity: 1; pointer-events: auto; }

.hero__img {
  position: absolute; inset: 0;
  /* An <img>, not a background — see front-page.php. `object-fit` is the
     element-level equivalent of the `background-size: cover` this replaced;
     `display:block` kills the inline-baseline gap an <img> would otherwise
     leave under itself. */
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center center;
  /* NO `filter` HERE — removed in v1.7.0, and this is the LCP element, so do
     not put one back without re-measuring.

     It used to carry `grayscale(1) contrast(1.05) brightness(1.22)`, the same
     lift the three surviving rules below still carry (773, 1012, 1637). The
     lift exists so the band colour screened over the photograph has something
     to act on; three of the five band colours are dark, and screen over dark
     on dark barely moves anything.

     It came off on a LOOKS call, not a speed one, and the speed case for
     taking it off turned out not to exist. The same hero slide captured with
     and without it, twice, at 1440x820, was indistinguishable — the source
     photographs are already near-monochrome and the coloured screen over them
     does the work the grayscale was supposed to do. That is the reason it is
     gone.

     ⚠ The speed reason on file was WRONG, and this note exists so nobody
     spends a day chasing it again. A v1.6.0 A/B recorded the filter costing
     790ms of LCP (4,076 -> 3,286ms). Re-run on the v1.7.0 export, 5 runs each
     under the same Lighthouse mobile profile, it measures 1,804ms WITH the
     filter and 1,808ms WITHOUT — no difference, and both well under the whole
     4,076ms baseline. The old numbers were an artefact of the machine the
     measurement ran on, not of this rule. Putting the filter back here would
     cost nothing measurable.

     The other three rules keep their filter: all three are below the fold,
     none is in the LCP path, and none was A/B'd for looks. */
}

/* The base's grade is a real DUOTONE: shadows land on the band colour and
   highlights land near white, which is why its slides read light even where
   the photograph underneath is dark.

   Two earlier attempts got this wrong in the same way — grayscale plus a
   multiplied wash, then grayscale plus brightness plus a multiplied wash.
   Multiply can only ever darken, so on the donor's deliberately low-key
   photography both produced a near-black hero with nothing visible on it but
   the headline. Turning up `brightness` is not the fix either; it lifts the
   whole image toward grey rather than mapping its shadows onto a hue.

   SCREEN over a grayscale image is the whole duotone on its own: it maps
   black to the band colour and leaves white at white, which is the base's
   shadow-to-highlight ramp exactly. A second multiplied pass was tried and
   dropped — `mix-blend-mode` on this element makes it a stacking context, so
   a ::after inside it blends against this element rather than against the
   photograph, which is not the layer anyone wanted it to touch. */
.hero__wash {
  position: absolute; inset: 0;
  mix-blend-mode: screen;                       /* shadows -> band colour */
  opacity: 0.6;                                 /* full screen gave a pale band the
                                                   white headline could not sit on;
                                                   the base's own grade is mid-tone */
}
/* The headline sits top-right in a fixed box over a photograph that changes
   every six seconds. Per §8.8, contrast here has to be a CONSTANT rather than
   a function of whichever picture is loaded — so the slide carries its own
   wash and the type never depends on the image behind it.

   Both ends are needed and the first pass only built the top one. Measured on
   the real composite with typecontrast.mjs at a 0.5 top wash and no bottom
   wash:

     .hero__title      worst 2.51  10.1% of area below 4.5
     .hero__title em   worst 1.00  96.6% below 4.5   <- the accent word, gone
     .hero__cue span   worst 1.43   100% below 4.5   <- SCROLL, over the bright floor

   The accent is the base's light lime #b0d37e, which it only ever uses on its
   DARK slides; on a light duotone it has nothing to work against. Darkening
   the wash is the fix that keeps the palette at count — recolouring the accent
   per slide would add tokens to buy back what the ground gave away. */
.hero__scrim {
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(to bottom,
    rgba(14, 31, 48, 0.82) 0%,
    rgba(14, 31, 48, 0.74) 46%,
    rgba(14, 31, 48, 0.10) 68%,
    rgba(14, 31, 48, 0.12) 78%,
    rgba(14, 31, 48, 0.84) 100%);
}
.hero__type { z-index: 100; }
.hero__slide:nth-child(1) .hero__wash { background: var(--teal); }
.hero__slide:nth-child(2) .hero__wash { background: var(--olive); }
.hero__slide:nth-child(3) .hero__wash { background: var(--plum); }
.hero__slide:nth-child(4) .hero__wash { background: var(--stone); }
.hero__slide:nth-child(5) .hero__wash { background: var(--ground); }

/* DONOR — kmm.com's ghosted monogram. Its own is ~50% white, vertically
   centred, bleeding off both edges. Rebuilt in CSS because the type is ours.

   A child of the stage, not of a slide — see the note in front-page.php and
   playbook trap §8.3. */
.hero__monogram {
  position: absolute;
  z-index: 2;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--f-serif);                  /* donor face, donor device */
  font-weight: 300;                             /* Butler 200 was the only weight on
                                                   the page the base does not also
                                                   use; 300 costs nothing here and
                                                   holds the weight count at four */
  font-size: 21vw;                              /* at 34vw the three glyphs each
                                                   overran the viewport and the
                                                   mark read as noise, not a mark */
  line-height: 0.78;
  color: rgba(255, 255, 255, 0.11);
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
}

/* the headline — base's .tagline, re-typeset from the donor's 115px/0.870

   The slide crossfades over a second, and for that second BOTH slides are
   painted. That is right for the photograph and wrong for the type: the first
   build had two headlines superimposed through every transition, which reads
   as a rendering fault rather than a crossfade. The base fades only its
   background layer (`.fading-overlay`) and swaps its `.tagline` outright.

   So the type gets its own timing: out immediately, in only after the picture
   underneath has finished changing. The two runs never overlap. */
.hero__titles { position: absolute; inset: 0; pointer-events: none; }
.hero__type {
  position: absolute;
  right: 0; left: 0; top: 5%;                   /* base — .tagline-holder */
  padding: 0 10%;                               /* base */
  text-align: right;                            /* base */
  opacity: 0;
  transition: opacity var(--d-1) var(--e-out);  /* out immediately */
}
.hero__type.is-active {
  opacity: 1;
  transition: opacity var(--d-2) var(--e-out) var(--d-2);  /* in only after the
                                                              picture has changed */
}
.hero__title {
  display: inline-block;
  position: relative;
  top: 180px;                                   /* base — .home .tagline */
  max-width: 950px;                             /* base — its slide-1 box */
  font-family: var(--f-sans);
  font-weight: 100;                             /* base */
  font-size: var(--t-5xl);                      /* base — 80px */
  line-height: var(--lh-flat);                  /* base — 80px, ratio 1.000 */
  text-transform: uppercase;                    /* base */
  color: #fff;
  text-align: right;
  text-shadow: 0 0 30px rgba(0, 0, 0, 0.45);
}
/* base — exactly one word per slide goes accent + italic */
.hero__title em { color: var(--lime); font-style: italic; }

/* SPEC 4.1 / 5 — the subhead, under the headline it belongs to. The reasoning
   for the POSITION is in front-page.php where the markup is; the short version
   is that the scrim opens a window to the photograph below 46% and white type
   measures 1.45-3.24:1 in it.

   `top: 180px` is not a second guess at the same number — it is the SAME
   number, copied from .hero__title above, and it has to be. The title is
   position: relative, so it is painted 180px below the box it still occupies
   in flow; a following sibling that did not take the identical offset would
   render 180px ABOVE the headline it is meant to sit under.

   24px, not 18, AND THE SIZE IS THE COMPLIANCE, not a preference. Measured on
   the real composite at the box it actually occupies (44-52% of the hero),
   worst pixel of each slide: workbench 4.52, stair 5.43, arcade 12.52, chamber
   5.22, skyline 4.87. Floor 4.52 — which clears the 3.0 this earns as WCAG
   large text and happens to clear the 4.5 for normal text as well, so it holds
   even if the size is ever argued about. The same sentence at 18px at 70%,
   where this first shipped, measured 1.47. The shadow is belt and braces;
   WCAG does not count it.

   margin-left: auto right-aligns the BOX; the type inside is right-aligned by
   .hero__type. Both are needed: without the auto the box fills the column and
   the measure runs the width of the hero. */
.hero__sub {
  position: relative;
  top: 180px;
  max-width: 620px;
  margin: var(--sp-2) 0 0 auto;
  font-family: var(--f-sans);
  font-size: var(--t-lg);
  line-height: var(--lh-read);
  color: #fff;
  text-shadow: 0 0 10px #000, 0 10px 20px #000, 0 20px 30px #000;
}

/* THE HERO CTA — SPEC 4.1, check D7. Restored; the merge dropped it.

   RIGHT 10% is not a guess: it is the same inset .hero__type carries as
   `padding: 0 10%`, so the button's right edge lands on the headline's right
   edge and the two read as one right-aligned column.

   BOTTOM 16%, not a `top`, because the headline is 1-3 lines depending on the
   slide and anything measured down from the top collides on the long ones.
   16% of the 720px floor is 115px, which clears the pause control (34px at
   bottom 20px) and the scroll cue (bottom 12px) without either of them moving.

   pointer-events: auto is LOAD-BEARING — the parent .hero__titles is
   pointer-events: none so the photograph stays draggable, and this element is
   a sibling of it, but the rule is kept here as a guard in case it is ever
   moved inside. Without it the button is visible and unclickable, which is the
   worst of both.

   The IDIOM is the base's own button: a 2px box that inverts on hover, same as
   .form__submit at 1257. The COLOUR is the light variant rather than plum,
   because the ground here is a photograph and plum-on-photo is the one
   combination the contrast pass at 8.7 could not hold across all five slides.
   White fill + navy label is what wp-theme/whitaker-hollis shipped as
   `.btn--light`, so this is the same button it always was. */
.hero__cta {
  position: absolute;
  right: 10%; bottom: 16%;
  z-index: 4;
  pointer-events: auto;
}
.hero__btn {
  display: inline-block;
  padding: var(--sp-2) var(--sp-5);
  border: 2px solid #fff;
  background: #fff;
  color: var(--ground);
  font-family: var(--f-cond);
  font-size: var(--t-md);
  line-height: var(--lh-read);
  text-transform: uppercase;
  transition: var(--d-1) var(--e-out);
}
.hero__btn:hover, .hero__btn:focus-visible { background: transparent; color: #fff; }

/* slide rail — base's .slick-dots, left rail with a 1px hairline through it */
.hero__rail {
  position: absolute;
  left: var(--sp-3); bottom: 40%;               /* base — left 20px, bottom 40% */
  z-index: 200;
}
.hero__rail::before {
  content: "";
  position: absolute; top: 7px; right: 0; left: 0;
  width: 1px; height: 88%;                      /* base */
  margin: 0 auto;
  background: rgba(255, 255, 255, 0.3);         /* base */
}
.hero__rail li { display: block; padding: 18px 0; }  /* base */
.hero__rail button {
  position: relative;
  display: block; width: 10px; height: 10px;
  border-radius: 50%;
  background: #bde0df;                          /* base — its inactive dot */
  transition: var(--d-1) var(--e-out);
}
.hero__rail button[aria-current="true"] { background: var(--lime); }

/* SCROLL cue — base, with its subtleBounce */
.hero__cue {
  position: absolute;
  bottom: 12px; left: 0; right: 0;              /* base — .overlap */
  z-index: 1000;
  margin: 0 auto;
  text-align: center;
  font-family: var(--f-sans);
  font-weight: 300;
  font-size: var(--t-md);
  text-transform: uppercase;
  color: #fff;
}
.hero__cue span {
  /* base — its four-stop shadow, kept because the ground is a photograph */
  text-shadow: 0 0 10px #000, 0 10px 20px #000, 0 20px 30px #000, 0 30px 40px #000;
}
.hero__cue svg { display: block; margin: var(--sp-2) auto 0; width: 24px; }
@keyframes subtleBounce {                        /* base, verbatim */
  0%   { transform: translate3d(0, 0, 0); }
  70%  { transform: translate3d(0, -20px, 0); }
  100% { transform: translate3d(0, 0, 0); }
}
.hero__cue svg { animation: subtleBounce 2s var(--e-io) infinite; }

.hero__pause {
  position: absolute;
  left: var(--sp-3); bottom: var(--sp-3);
  z-index: 200;
  width: 34px; height: 34px;
  color: #fff;
  font-size: var(--t-md);
  line-height: 1;
}

/* the mobile title band lives at the bottom of this file with its media query */

/* ==========================================================================
   INTRO — DONOR module (kmm's .module-intro-a): one centred statement, wide
   measure, nothing else in the band. Re-typeset into the base's 48px
   Roboto Condensed from the donor's 47px Butler 300 / 1.200.
   ========================================================================== */

.intro { background: var(--paper); padding: var(--sp-7) 0; text-align: center; }
.intro__eyebrow {
  font-family: var(--f-cond);
  font-weight: 300;
  font-size: var(--t-2xl);
  line-height: var(--lh-head);
  text-transform: uppercase;
  color: var(--stone);
  margin-bottom: var(--sp-4);
}
.intro__statement {
  font-family: var(--f-cond);
  font-weight: 400;
  font-size: var(--t-3xl);                       /* base — 48px */
  line-height: var(--lh-head);                   /* base — 1.4 */
  text-transform: uppercase;
  color: var(--ground);
  margin: 0 auto;
  max-width: var(--wrap-narrow);
}
.intro__statement em { color: var(--plum); font-style: italic; }
.intro__lede {
  margin: var(--sp-5) auto 0;
  max-width: 823px;                              /* base — its measured prose column */
  font-size: var(--t-sm);
  line-height: var(--lh-read);
}

/* ==========================================================================
   ROSTER — base. Zero gutters, one crop, a scrim over the bottom of each
   card, plum wash on hover. This is the base's single most distinctive band
   and its numbers are copied, not invented.
   ========================================================================== */

.roster { background: var(--paper); padding: var(--sp-7) 0 0; }
.roster .head { margin-bottom: var(--sp-6); }

/* Two consecutive bands on the SAME ground put their two 100px pads back to
   back and the page reads as a 200px hole between a lede and the next head.
   The base's adjacent bands change ground, so it never shows there. Collapse
   the join rather than shrinking the token — the 100px is a copied number. */
.intro + .roster { padding-top: 0; }
/* Same join, second occurrence: on the attorneys route the page head already
   closes on its own 100px, and the roster's 100px behind it is the other half
   of the identical 200px hole. */
main > .roster:first-child { padding-top: 0; }
.band-practices > .wrap { padding-top: var(--sp-7); }
.roster__strip { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0; }  /* base — zero gutters */

.roster__card {
  position: relative;
  display: block;
  min-height: 492px;                             /* base — measured, to the pixel */
  overflow: hidden;
}
.roster__img {
  position: absolute; inset: 0;
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  /* The base's card is 205x492 and its headshots are shot for that ratio.
     Ours are near-square, so `center center` cropped to chins and collars —
     six portraits with no faces in them. The band height is a copied number
     and stays; the crop anchor is what moves. */
  object-position: center 18%;
}
.roster__info {
  position: absolute;
  bottom: 0; left: 0; right: 0;
  z-index: 2;
  padding: var(--sp-3);
  text-align: center;                            /* base — it centres 125 of its 131 text blocks */
  transition: opacity var(--d-2) var(--e-out);   /* base — 500ms */
}
/* These are spans inside an <a> so the markup stays valid; without an explicit
   block they set on one line and the role ran into the name. */
.roster__name, .roster__role, .roster__view { display: block; }
.roster__info::before {
  content: "";
  position: absolute;
  bottom: 0; left: 0;
  width: 100%; height: 170%;                     /* base draws 130%; see below */
  z-index: -1;
  /* The base's scrim is a two-stop ramp from #4b7b7c to transparent over 130%
     of the caption block. Measured on the real composite, our six headshots
     put 15.8% of the name run below 4.5 and 1.3% below 3.0, because the ramp
     reaches its strong end under the role and the NAME sits in the thin part
     over whatever the photograph happens to be. The base has the same defect
     on its lighter portraits — but inheriting a defect is not the same as
     copying a decision (§8.8). Same colour, same direction, a longer ramp
     with a held plateau under the type. */
  background: linear-gradient(0deg,
    var(--teal-deep) 0%,
    var(--teal-deep) 34%,
    rgba(75, 123, 124, 0.72) 58%,
    rgba(75, 123, 124, 0) 100%);
}
.roster__name {
  position: relative;
  font-family: var(--f-serif);                   /* DONOR face; the base sets 30px/1.4 */
  font-weight: 700;
  font-size: var(--t-xl);
  line-height: var(--lh-head);
  color: #fff;
}
.roster__role {
  position: relative;
  font-family: var(--f-cond);
  font-size: var(--t-md);
  line-height: var(--lh-read);
  text-transform: uppercase;
  color: #fff;
}
.roster__hover {
  position: absolute; inset: 0;
  z-index: 3;
  display: flex; align-items: center; justify-content: center;
  padding: var(--sp-3);
  background: rgba(141, 27, 84, 0.9);            /* base — 18 uses, its single most-painted colour */
  color: #fff;
  opacity: 0;
  transition: opacity var(--d-2) var(--e-out);   /* base */
}
.roster__hover p {
  font-size: var(--t-sm);
  line-height: var(--lh-read);
  transform: translateY(40px);                   /* base */
  transition: transform var(--d-3) var(--e-out); /* base — 600ms */
}
.roster__card:hover .roster__hover,
.roster__card:focus-visible .roster__hover { opacity: 1; }
.roster__card:hover .roster__hover p,
.roster__card:focus-visible .roster__hover p { transform: translateY(0); }
.roster__card:hover .roster__info,
.roster__card:focus-visible .roster__info { opacity: 0; }
.roster__view {
  display: inline-block;
  margin-top: var(--sp-3);
  padding: var(--sp-1) var(--sp-3);
  border: 2px solid #fff;
  font-family: var(--f-cond);
  font-size: var(--t-md);
  text-transform: uppercase;
  transition: var(--d-1) var(--e-out);
}
.roster__card:hover .roster__view { background: #fff; color: var(--plum); }

/* ==========================================================================
   PRACTICES — base. Five boxes across at 20%, 188px tall, one band colour
   each, in its order.
   ========================================================================== */

.practices { display: flex; flex-wrap: wrap; }
.practices__item {
  display: flex; align-items: center; justify-content: center;
  width: 20%;                                    /* base */
  height: 188px;                                 /* base — measured */
  padding: 0 var(--sp-3);
  text-align: center;
  transition: opacity var(--d-1) var(--e-out);   /* base — 300ms ease-out */
}
.practices__item:hover { opacity: 0.7; }         /* base */
.practices__item h3 {
  font-family: var(--f-serif);                   /* DONOR face; the base sets 30px/400 */
  font-weight: 400;
  font-size: var(--t-xl);
  line-height: var(--lh-head);
  color: #fff;
}
.practices__item:nth-child(5n+1) { background: var(--plum); }
.practices__item:nth-child(5n+2) { background: var(--teal); }
.practices__item:nth-child(5n+3) { background: var(--olive); }
.practices__item:nth-child(5n+4) { background: var(--stone); }
.practices__item:nth-child(5n+5) { background: var(--ground); }

/* ==========================================================================
   TESTIMONIAL — base's .choose-firm: type over a photograph, 100px band pad,
   140px inset on the quote, the quote marks as corner ornaments.
   ========================================================================== */

.testimonial {
  position: relative;
  padding: var(--sp-7) 0;                        /* base — 100px 0 */
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
}
.testimonial::before {
  /* Desaturate and lift the photograph the same way the hero does, so the two
     photographic bands on the page are graded by one rule rather than two. */
  content: "";
  position: absolute; inset: 0;
  background: inherit;
  background-size: cover;
  background-position: center center;
  filter: grayscale(1) brightness(1.25) contrast(0.9);
}
.testimonial::after {
  /* The scrim is a flat colour, not a gradient, so contrast here is a CONSTANT
     rather than a function of which photograph happens to be behind the type
     (playbook §8.8). At 0.72 it swallowed the photograph entirely and the band
     read as flat navy; 0.55 keeps the picture and still clears AA. */
  content: "";
  position: absolute; inset: 0;
  background: rgba(14, 31, 48, 0.55);
}
.testimonial > * { position: relative; z-index: 1; }
.testimonial .head { color: #fff; }
.testimonial .head em { color: var(--lime); }
.testimonial__outer { position: relative; padding: 0 var(--sp-9); }  /* base — 140px */
.testimonial__quote {
  font-family: var(--f-serif);                   /* DONOR face; the base sets 48px PT Serif */
  font-weight: 300;
  font-size: var(--t-3xl);
  line-height: var(--lh-head);
  color: #fff;
  text-align: center;
  padding-top: var(--sp-6);                      /* base — 50px */
  margin-bottom: 65px;                           /* base */
}
.testimonial__author {
  font-family: var(--f-serif);
  font-size: var(--t-lg);                        /* base — 24px */
  line-height: var(--lh-read);
  color: #fff;
  text-align: center;
}
.testimonial__mark {
  position: absolute;
  width: 96px; height: 91px;                     /* base — measured */
  opacity: 0.5;
  z-index: 0;
  color: #fff;                                   /* the glyph is drawn in
                                                    currentColor now that it is
                                                    an <svg> and not the base's
                                                    white WebP; the nearest
                                                    #fff above this is on a
                                                    SIBLING, so it is set here
                                                    rather than inherited. */
}
.testimonial__mark--l { top: 0; left: 30px; }    /* base */
.testimonial__mark--r { bottom: 50px; right: 30px; }  /* base */

/* ==========================================================================
   ACCORDION — base. 115px band, 2px rules, plum wash on the open row,
   a "+" that becomes "-".
   ========================================================================== */

.experience { padding: var(--sp-8) 0; background: var(--paper); }  /* base — 115px */
.acc__tab { border-bottom: 2px solid var(--rule); }                /* base */
.acc__title {
  display: block;
  width: 100%;
  padding: var(--sp-4) var(--sp-3);                                /* base — 25px 20px */
  text-align: left;
  transition: var(--d-1) var(--e-out);
}
.acc__title h3 {
  position: relative;
  font-family: var(--f-serif);                                     /* DONOR face; base sets 36px */
  font-weight: 400;
  font-size: var(--t-2xl);
  line-height: var(--lh-head);
  color: var(--ink);
  padding-right: var(--sp-5);
}
.acc__title h3::after {
  content: "+";                                                    /* base */
  position: absolute; right: var(--sp-2); top: 0;
  font-size: var(--t-2xl);
  font-weight: 400;
  color: var(--plum);                                              /* base */
}
.acc__title[aria-expanded="true"] h3::after { content: "-"; }      /* base */
.acc__title:hover, .acc__title:focus-visible { background: var(--plum); }   /* base */
.acc__title:hover h3, .acc__title:hover h3::after,
.acc__title:focus-visible h3, .acc__title:focus-visible h3::after { color: #fff; }
.acc__panel { display: none; padding: var(--sp-6) 0; }             /* base — 30px 0, widened to its
                                                                     home value */
.acc__panel.is-open { display: block; }
.acc__panel p { max-width: 823px; }

/* ==========================================================================
   INSIGHTS — base's row, carrying the DONOR's "Recent News & Insights"
   framing and its three-up rhythm.
   ========================================================================== */

.insights { padding: var(--sp-7) 0; background: var(--mist); }     /* donor ground */
.insights__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); }
.insights__item { display: block; padding: var(--sp-6) 0; }        /* base — 50px 0 */
.insights__date {
  font-family: var(--f-cond);
  font-size: var(--t-md);
  line-height: var(--lh-read);
  text-transform: uppercase;
  color: var(--stone);
  margin-bottom: var(--sp-2);
}
.insights__title {
  font-family: var(--f-serif);                                     /* DONOR face; base sets 24px */
  font-weight: 400;
  font-size: var(--t-lg);
  line-height: var(--lh-head);
  color: var(--plum);                                              /* base */
  transition: color var(--d-1) var(--e-out);
}
.insights__item:hover .insights__title { color: var(--teal); }     /* base */

/* ==========================================================================
   FOOTER — base's shape (centred, 40px band, 18px links), on the DONOR's
   navy ground.
   ========================================================================== */

.footer {
  background: var(--ground);                                       /* DONOR value in the base's slot */
  color: #fff;
  text-align: center;                                              /* base */
  padding: var(--sp-5) 0;                                          /* base — 40px 0 */
  background-size: cover;
  background-position: center center;
}
.footer__mark {
  font-family: var(--f-cond);
  font-weight: 300;
  font-size: var(--t-2xl);
  line-height: var(--lh-flat);
  text-transform: uppercase;
  color: #fff;
  margin-bottom: var(--sp-4);
}
.footer__mark b { font-weight: 400; color: var(--lime); }
.footer ul { margin: 0 0 var(--sp-5); }                            /* base */
.footer li { display: inline-block; }                              /* base */
.footer li a {
  display: block;
  padding: 0 14px;                                                 /* base */
  font-size: var(--t-md);                                          /* base — 18px */
  line-height: var(--lh-read);
  color: var(--lime);
}
.footer li a:hover, .footer li a:focus { color: #fff; }            /* base */
.footer__address { font-size: var(--t-sm); line-height: var(--lh-read); color: rgba(255,255,255,0.86); }
.footer__legal {
  margin-top: var(--sp-4);
  font-size: var(--t-xs);
  line-height: var(--lh-read);
  color: rgba(255, 255, 255, 0.8);
}

/* ==========================================================================
   INTERIOR ROUTES — attorneys roster, practice area, contact.

   NO NEW TOKENS. Every value below is either one of the tokens above or a
   structural number copied off the base to the pixel (555, 492, 400, 13/18),
   the same licence the roster card's 492px already takes.

   Three of the base's own interior numbers were re-typeset rather than added:
   its sidebar link is 20px/30 (not a step on the nine-step ladder -> 18px,
   --lh-read), its .content band pad is 95px (-> --sp-7, its own 100px), and
   its interior h4 is 22px (-> --t-lg, 24px).
   ========================================================================== */

/* --- the header on a page with no hero under it ----------------------- */
/* base — `.page-template-template-attorneys .header, .single-attorneys .header
   { background:#fff; border-bottom:2px solid #548e8f }`. A page whose first
   band is white cannot carry white nav type over it, so the base paints the
   header from the first pixel and the §8.9 collapse becomes a change of
   GEOMETRY rather than of colour. See the note in the build record: this is
   what headproof.mjs's `painted` half was not written for. */
.is-solidhead .header             { background: #fff; border-bottom: 2px solid var(--teal); }
.is-solidhead .header__mark       { color: var(--ground); }
.is-solidhead .header__mark b     { color: var(--plum); }
.is-solidhead .header__sub        { color: rgba(14, 31, 48, 0.5); }
.is-solidhead .nav a              { color: var(--ground); }
.is-solidhead .nav a:hover,
.is-solidhead .nav a:focus        { color: #fff; background: var(--ground); }
.is-solidhead .header__toggle     { border-color: var(--ground); color: var(--ground); }

/* --- CURRENT PAGE, header nav and footer nav -------------------------
   Reported by the client: "nav and footer dont reflect the current page."

   The MARKUP was already right — `wp_nav_menu` emits `current-menu-item`
   and `aria-current="page"` on the six top-level routes — and this file had
   no rule for either, so every state rendered identically. That is the whole
   of the first half; the second half is in functions.php, which is what
   marks the SECTION on a detail route (a bio, a practice page, an article),
   because the menu is built from CUSTOM LINKS and WordPress only ever
   matches those on an exact URL.

   The device is the one this build already uses for an active row: a 2px
   underline in that surface's own accent. It is `box-shadow: inset`, not a
   border, so nothing moves by 2px when a row becomes current.

   Three header surfaces, three accents:
     transparent over the hero  white text  -> --lime
     white bar (stuck, solid)   navy text   -> --plum
     plum bar (390, solid)      white text  -> --lime      (in the 700 block)
     open drawer (<=1024)       navy panel  -> --lime, no rule under a
                                               full-width centred link */
.nav .current-menu-item > a,
.nav .current-menu-ancestor > a,
.nav .current-menu-parent > a {
  color: #fff;
  box-shadow: inset 0 -2px 0 var(--lime);
}
.is-solidhead .nav .current-menu-item > a,
.is-solidhead .nav .current-menu-ancestor > a,
.is-solidhead .nav .current-menu-parent > a,
.header.is-stuck .nav .current-menu-item > a,
.header.is-stuck .nav .current-menu-ancestor > a,
.header.is-stuck .nav .current-menu-parent > a {
  color: var(--plum);
  box-shadow: inset 0 -2px 0 var(--plum);
}
/* Hovering the current row still does what hovering any row does. */
.nav .current-menu-item > a:hover,
.nav .current-menu-item > a:focus,
.is-solidhead .nav .current-menu-item > a:hover,
.is-solidhead .nav .current-menu-item > a:focus,
.header.is-stuck .nav .current-menu-item > a:hover,
.header.is-stuck .nav .current-menu-item > a:focus,
.nav .current-menu-ancestor > a:hover,
.nav .current-menu-ancestor > a:focus,
.is-solidhead .nav .current-menu-ancestor > a:hover,
.is-solidhead .nav .current-menu-ancestor > a:focus,
.header.is-stuck .nav .current-menu-ancestor > a:hover,
.header.is-stuck .nav .current-menu-ancestor > a:focus {
  color: #fff;
  background: var(--ground);
  box-shadow: inset 0 -2px 0 var(--lime);
}

/* The footer runs the same menu on navy, where the links are already lime.
   Lime-on-lime cannot mark anything, so the current row takes the footer's
   OTHER state — white — and keeps the lime as the rule under it. That is the
   same pair the header uses, read the other way round. */
.footer .current-menu-item > a,
.footer .current-menu-ancestor > a,
.footer .current-menu-parent > a {
  color: #fff;
  box-shadow: inset 0 -2px 0 var(--lime);
}

/* --- PAGE HEAD, white variant — base's .banner-title ------------------ */
/* base — `.banner-title { padding:100px 0 }`, `h1 { 80px Roboto 100, teal,
   centred }`, `h1 em { plum }`. The header is fixed and this band is the first
   thing under it, so it carries the header's own height as its top margin —
   the base does the same with `.page-id-196 .main { margin-top:140px }`. */
.pagehead {
  margin-top: var(--header-h);
  padding: var(--sp-7) 0;
  background: var(--paper);
  text-align: center;
}
.pagehead__title {
  font-family: var(--f-sans);
  font-weight: 100;                              /* base */
  font-size: var(--t-5xl);                       /* base — 80px */
  line-height: var(--lh-flat);
  text-transform: uppercase;
  text-align: center;                            /* base */
  color: var(--teal);                            /* base — rgb(92,148,149), one teal token */
}
/* base — exactly one word goes accent + italic, the same device as the hero */
.pagehead__title em { color: var(--plum); font-style: italic; }
.pagehead__lede {
  margin: var(--sp-5) auto 0;
  max-width: 823px;                              /* base — its measured prose column */
  font-size: var(--t-md);                        /* base — 18px/28.8 on both interior pages */
  line-height: var(--lh-read);
}

/* --- PAGE HEAD, photograph variant — base's .banner ------------------- */
/* base — `.banner { min-height:555px; background-size:cover }`, the transparent
   header sitting over it (its own capture reads gapAbove: -149). */
.pagehead--photo {
  position: relative;
  margin-top: 0;
  min-height: 555px;                             /* base — measured */
  display: flex;
  align-items: center;
  padding: var(--header-h) 0 var(--sp-7);
  background: var(--ground);
  overflow: hidden;
  /* the wash below is a blend; isolate so it composites against the photograph
     and nothing else, whatever this band happens to be stacked over */
  isolation: isolate;
}
/* THE STAGE AND THE TITLE ARE DIFFERENT THINGS, the same split the hero makes
   and for the same reason (trap §8.3): at 390 the title leaves the photograph
   for a solid band, and it can only do that if it was never inside it. */
.pagehead__stage { position: absolute; inset: 0; }

/* Graded by the SAME rule as the hero and the testimonial, so the three
   photographic bands on this site are one decision rather than three. */
.pagehead__img {
  position: absolute; inset: 0;
  background-size: cover;
  background-position: center center;
  filter: grayscale(1) contrast(1.05) brightness(1.22);
}
.pagehead__wash {
  position: absolute; inset: 0;
  mix-blend-mode: screen;                        /* shadows -> band colour */
  opacity: 0.6;
}
/* §8.8 — the type's contrast has to be a CONSTANT rather than a function of
   which photograph is behind it.

   A flat 0.55 was the first answer, copied off the testimonial band, and the
   white half of the title was fine on it — worst 4.38, 0.2% of area under 4.5.
   The LIME accent word was not: worst 2.60, 10.2% under 4.5 and 2.8% under 3.0,
   because lime is the base's light accent and it only ever uses it on dark
   slides. This is the identical defect the hero hit, on the identical colour.

   Raising the flat scrim until lime cleared would have taken the photograph
   with it — the testimonial band already proved 0.72 swallows the picture. So
   the scrim is the hero's shape instead of the testimonial's: dark where the
   type actually is, open at the edges where it is not. The title sits at
   43%-58% of this band's height, so the plateau covers it and nothing else. */
.pagehead__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(to bottom,
    rgba(14, 31, 48, 0.42) 0%,
    rgba(14, 31, 48, 0.86) 38%,
    rgba(14, 31, 48, 0.86) 64%,
    rgba(14, 31, 48, 0.42) 100%);
}
.pagehead--photo > .wrap { position: relative; z-index: 1; }
/* PART FOUR — search and the 404 are the first routes to carry a lede on the
   photograph variant, and the lede had no colour of its own: it inherited
   `--body` and painted #414042 over the scrim. Both of those routes are on
   band 5, which is the navy, so white clears at 390 too — where the base's
   device moves this whole block off the picture and onto the band's own
   colour, and white on olive or stone would not. */
.pagehead--photo .pagehead__lede { color: #fff; }
.pagehead--photo .pagehead__title {
  color: #fff;
  text-shadow: 0 0 30px rgba(0, 0, 0, 0.45);     /* base — the hero title's own */
}
.pagehead--photo .pagehead__title em { color: var(--lime); }

/* one band colour per practice area, in the base's order — the same colour
   that area's box carries on the home page */
.pagehead--photo[data-band="1"] .pagehead__wash { background: var(--plum); }
.pagehead--photo[data-band="2"] .pagehead__wash { background: var(--teal); }
.pagehead--photo[data-band="3"] .pagehead__wash { background: var(--olive); }
.pagehead--photo[data-band="4"] .pagehead__wash { background: var(--stone); }
.pagehead--photo[data-band="5"] .pagehead__wash { background: var(--ground); }

/* --- INTERIOR BODY — base's .content / .sidebar pair ------------------ */
/* base — `.content, .sidebar { padding-top:95px; padding-bottom:95px }`,
   re-typeset to its own 100px so the rhythm set stays at nine values. */
.page-body { padding: var(--sp-7) 0; background: var(--paper); }
.page-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 400px;   /* base — measured 710 / 397 at 1440 */
  gap: var(--sp-7);
  align-items: start;
}
.page-title {
  font-family: var(--f-cond);
  font-weight: 300;                              /* base */
  font-size: var(--t-4xl);                       /* base — 60px */
  line-height: var(--lh-head);                   /* base — 84/60 = 1.4 where it wraps */
  text-transform: uppercase;                     /* base */
  color: var(--ground);                          /* the donor navy in the base's #353441 slot */
  margin-bottom: var(--sp-4);
}
.prose > p, .prose li {
  font-size: var(--t-md);                        /* base — 18px */
  line-height: var(--lh-read);                   /* base — 28.8/18 = 1.6 */
}
.prose > p { margin-bottom: var(--sp-3); }
.prose h2 {
  font-family: var(--f-cond);
  font-weight: 700;                              /* base */
  font-size: var(--t-xl);                        /* base — 30px */
  line-height: var(--lh-head);                   /* base — 42/30 = 1.4 */
  color: var(--ground);
  margin: var(--sp-6) 0 var(--sp-3);
  scroll-margin-top: var(--header-h);            /* the sidebar links into these */
}
.prose h2:first-child { margin-top: 0; }         /* base — `.content h2:first-child` */
/* base — the block its team page closes on: one centred column, its own measure */
.prose--centred { max-width: 823px; margin: 0 auto; text-align: center; }
.prose ul { margin: 0 0 var(--sp-3) var(--sp-5); }   /* base — 0 0 20px 40px */
.prose li { position: relative; margin-bottom: var(--sp-2); }
/* base draws this marker with a FontAwesome chevron; the kits are bucket 3, so
   it is drawn instead. Same size, same offset, same plum. */
.prose li::before {
  content: "";
  position: absolute; left: -16px; top: 12px;    /* base — left -16px */
  width: 7px; height: 7px;                       /* base — 7px */
  background: var(--plum);                       /* base */
}

/* --- SIDEBAR — base's, and its most distinctive interior device ------- */
.side__head {
  font-family: var(--f-cond);
  font-weight: 700;
  font-size: var(--t-lg);                        /* base — 24px */
  line-height: var(--lh-head);
  text-transform: uppercase;                     /* base */
  color: var(--ground);                          /* base — #353441 */
  margin: 0 0 var(--sp-3);                       /* base — 0 0 20px */
}
.side__list > li {
  position: relative;
  padding: 13px 18px;                            /* base */
  border-bottom: 2px solid var(--rule);          /* base */
}
.side__list > li:first-child { border-top: 2px solid var(--rule); }   /* base */
.side__list a {
  display: block;
  font-family: var(--f-sans);
  font-weight: 300;                              /* base */
  font-size: var(--t-md);                        /* base sets 20px; not a step on the ladder */
  line-height: var(--lh-read);
}
.side__list a:hover, .side__list a:focus-visible { color: var(--plum); }   /* base */
.side__list .is-current > a { color: var(--plum); }                       /* base */
/* base — a plum chevron before every row, from its FontAwesome kit. Drawn. */
.side__list li::before {
  content: "";
  position: absolute; left: 0; top: 22px;
  width: 6px; height: 6px;
  border-top: 2px solid var(--plum);
  border-right: 2px solid var(--plum);
  transform: rotate(45deg);
}
.side__sub { padding: var(--sp-3) 0 var(--sp-5) var(--sp-6); }   /* base — 20px 0 40px 50px */
/* The base puts this 18px indent on the <a> (`.sidebar .section ul li ul li a
   { padding: 0 0 0 18px }`). It is on the LI here instead, which renders
   identically and moves the plum chevron out of the link's own box — inside
   it, the contrast probe samples the ornament along with the type and reports
   0.2% of the run under 3.0 for a link that is a flat 10.22 on white. Trap
   §8.7's shape a third time: the box a probe measures is not always the run. */
.side__sub li { position: relative; border: 0; padding: 0 0 0 18px; }
.side__sub li::before { top: 12px; }

/* --- CONTACT — DONOR module (kmm's .page-template-template-contact) ---
   The base has no contact form at all; the donor's five-field form and its
   office block are the largest single donation on this build. Re-typeset into
   the base's ladder and its rhythm, and the donor's two offices become one
   because this firm has one — the copy is a slot the coherence pass owns too.
   ---------------------------------------------------------------------- */
.contact__lede {
  font-size: var(--t-md);
  line-height: var(--lh-read);
  margin-bottom: var(--sp-6);
  max-width: 823px;                              /* base — its measured prose column */
}
.office { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); align-items: start; }
.office__name {
  font-family: var(--f-serif);                   /* DONOR face — its own "New York" is Butler 30px */
  font-weight: 400;
  font-size: var(--t-xl);                        /* donor — 30px, and a step on the base's ladder */
  line-height: var(--lh-head);
  color: var(--ground);
  margin-bottom: var(--sp-3);
}
.office__address { font-size: var(--t-sm); line-height: var(--lh-read); }
.office__address span { display: block; }        /* they are lines, not a paragraph */
.office__contact { margin-top: var(--sp-3); font-size: var(--t-sm); line-height: var(--lh-read); }
.office__contact a { display: block; color: var(--plum); }
.office__contact a:hover, .office__contact a:focus-visible { color: var(--ground); }
.office__figure { position: relative; }
.office__photo {
  /* A <span> so the markup stays valid inside a text block, and therefore
     inline until told otherwise — the fourth time on this build that an
     un-blocked span has quietly cost a whole element. Without this the
     photograph is 0px tall and the VIEW MAP chip floats beside the lede. */
  display: block;
  height: 240px;
  background-size: cover;
  background-position: center center;
  /* The one image on this site that is NOT put through the duotone. It is the
     footer's slate texture, not a photograph, and the grading rule exists to
     make the PHOTOGRAPHS agree with one another — running a flat texture
     through grayscale only turns an on-palette blue into a grey nothing. */
}
/* THE MAP FRAME. Same 240px box the photograph occupied, so nothing below it
   moves. `border: 0` because a UA draws an inset 2px frame on an iframe by
   default and this build's only rule weight is 2px SOLID -- an inset one is a
   third weight arriving by accident. The mist ground is what shows while the
   tiles are still coming, so the box is never a white hole. */
.office__mapframe {
  display: block;
  width: 100%;
  height: 240px;
  border: 0;
  background: var(--mist);
}

/* donor — a solid chip in a corner of the figure, and it MOVED when the
   figure became a map.

   The donor puts it bottom-right, over a photograph, which a photograph does
   not mind. A map does: OpenStreetMap prints its attribution along the bottom
   of the frame and crediting it is a condition of using the tiles, so the chip
   was sitting on the one thing in the box that is not optional. Its zoom
   control takes the top-right. Top-LEFT is the only corner both leave empty,
   so that is where it goes -- the same chip, one corner over. */
.office__map {
  position: absolute; left: 0; top: 0;
  padding: var(--sp-2) var(--sp-3);
  background: var(--plum);                       /* the base's primary in the donor's chip slot */
  color: #fff;
  font-family: var(--f-cond);
  font-size: var(--t-xs);                        /* donor — 13px; 14px is the base's step */
  line-height: var(--lh-read);
  text-transform: uppercase;                     /* donor */
  transition: var(--d-1) var(--e-out);
}
.office__map:hover, .office__map:focus-visible { background: var(--ground); }

.form__field { margin-bottom: var(--sp-3); }
/* The honeypot's box, off-screen and out of the flow. Not `display:none` --
   some bots skip anything hidden that way, which is the whole point of it. */
.form__hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
/* One line under the conflicts field saying what the firm does with it. The
   form's own quiet register: the disclaimer's size, the body's colour. */
.form__help {
  display: block;
  margin-top: var(--sp-1);
  font-size: var(--t-xs);
  line-height: var(--lh-read);
  color: rgba(14, 31, 48, 0.62);
}
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.form__label {
  display: block;
  font-family: var(--f-cond);
  font-size: var(--t-xs);
  line-height: var(--lh-read);
  text-transform: uppercase;
  color: var(--body);
  margin-bottom: var(--sp-1);
}
.form__req { color: var(--plum); }
.form__input, .form__textarea {
  display: block;
  width: 100%;
  padding: var(--sp-2);
  border: 2px solid var(--rule);                 /* base — every hairline it draws */
  background: var(--mist);                       /* donor ground */
  color: var(--ground);
  font-family: var(--f-sans);
  font-weight: 300;
  font-size: var(--t-sm);
  line-height: var(--lh-read);
  transition: border-color var(--d-1) var(--e-out);
}
.form__input:focus, .form__textarea:focus { outline: 0; border-color: var(--plum); }
.form__textarea { min-height: var(--sp-9); resize: vertical; }
.form__submit {
  display: inline-block;
  margin-top: var(--sp-2);
  padding: var(--sp-2) var(--sp-5);
  border: 2px solid var(--plum);                 /* base — its button idiom is a 2px box that inverts */
  background: var(--plum);
  color: #fff;
  font-family: var(--f-cond);
  font-size: var(--t-md);
  line-height: var(--lh-read);
  text-transform: uppercase;
  transition: var(--d-1) var(--e-out);
}
.form__submit:hover, .form__submit:focus-visible { background: #fff; color: var(--plum); }
/* TRAP §8.7 — a contrast probe works by hiding the type and sampling what is
   behind it, and hiding an element hides its own background too. The chip and
   the button both paint their own plum, so their labels live in a child: hide
   the child and the plum stays painted, which is the only way either of these
   two runs can be measured rather than argued. */
.office__map span, .form__submit span, .bio__area span { display: inline; }
.form__note, .form__sent {
  margin-top: var(--sp-3);
  font-size: var(--t-xs);
  line-height: var(--lh-read);
  color: var(--body);
}
.form__sent { border-left: 2px solid var(--plum); padding-left: var(--sp-2); }

/* the qualifying select — SPEC 7.1. Native control, the input's own box, and
   the arrow drawn in the background rather than fetched. */
.form__select {
  appearance: none;
  padding-right: var(--sp-5);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230e1f30' stroke-width='2.2'%3E%3Cpath d='M3 7.5 12 16.5 21 7.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-2) center;
  background-size: 16px 16px;
}

/* the disclaimer that does the actual work — SPEC 14.1 / 17 E3.
   ABA Formal Op. 10-457 wants it "conspicuously placed to assure that the
   reader is likely to see it BEFORE proceeding", so it sits above the button,
   not under it, and it is not allowed to read as small print: same 16px body
   size as the form labels it follows, on the mist ground, with the plum rule
   the rest of this theme uses to mark something that has to be read. */
.form__disclaimer {
  margin-top: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-left: 2px solid var(--plum);
  background: var(--mist);
  font-family: var(--f-sans);
  font-weight: 300;
  font-size: var(--t-sm);
  line-height: var(--lh-read);
  color: var(--ground);
}

/* what happens next, and what it costs — SPEC 10.1, 10.2 / 17 D5, D6.
   Both checks are new to the scoresheet and both come from Clio's 2024
   secret-shopper study of 500 firms: 30% of shoppers could work out the
   hiring process from the site, 14% could find any pricing. */
.next { margin-top: var(--sp-6); padding-top: var(--sp-5); border-top: 2px solid var(--rule); }
.next__head {
  font-family: var(--f-serif);
  font-weight: 400;
  font-size: var(--t-2xl);
  line-height: var(--lh-tight);
  color: var(--ground);
  margin-bottom: var(--sp-4);
}
.next__steps { counter-reset: none; }
.next__step { display: flex; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.next__n {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  border: 2px solid var(--teal);
  font-family: var(--f-cond);
  font-size: var(--t-md);
  line-height: 1;
  color: var(--teal);
}
.next__body { display: block; }
.next__body strong {
  display: block;
  font-family: var(--f-cond);
  font-weight: 400;
  font-size: var(--t-md);
  line-height: var(--lh-read);
  text-transform: uppercase;
  color: var(--ground);
}
.next__body span {
  display: block;
  font-family: var(--f-sans);
  font-weight: 300;
  font-size: var(--t-sm);
  line-height: var(--lh-read);
  color: var(--body);
}
.next__fees {
  margin-top: var(--sp-4);
  padding: var(--sp-3);
  background: var(--mist);
  font-family: var(--f-sans);
  font-weight: 300;
  font-size: var(--t-sm);
  line-height: var(--lh-read);
  color: var(--ground);
}

/* The §12 same-ground pad collision, in its third location. The white page
   head and `.page-body` are both `--paper` and both carry the 100px band pad,
   so where one follows the other there are 200px of a single colour and
   nothing in it — which on the 404, whose body is five short links, is most of
   what the page contains. Same fix as `main > .roster:first-child`: the second
   band gives up its pad, leaving the head's own 100px as the separation, which
   is the base's figure for one band.

   The photograph variant keeps its pad. There the two bands are different
   grounds, and that is a real edge rather than a doubled one. */
/* `--bio` is excluded with `--photo`: its band is the navy ground, so the
   edge under it is a real one. */
.pagehead:not(.pagehead--photo):not(.pagehead--bio) + main > .page-body:first-child { padding-top: 0; }

/* ==========================================================================
   PART FOUR — the donor's interior.

   Part Three built these six page types from the base alone; the donor's own
   captures for exactly these types (kmm-bio, kmm-practices, kmm-page,
   kmm-e404) went unread. This block is the §2 slot table run again, per route,
   against both references.

   NO NEW TOKENS. Every donor number below is either re-typeset into the base's
   ladder — written out, both halves explicit, §6 — or is a structural number
   already present in this file.

   BUCKET 3, named before the work (§4): the donor's Butler at every heading
   step (the type scale is a one-owner row and stays the base's); its
   `content-tabs-select` <select> at 390 (a UA form control would put a second
   corner radius on routes that have none); its cut-out portrait PNGs (our six
   portraits are rectangular photographs — the composition transfers, the
   silhouette cannot); its vCard and PDF chips (a download that downloads
   nothing is the contact-form lie in a smaller box); its full-bleed photograph
   dividers between prose movements (on a template that renders whatever an
   editor writes, a photograph placed by the template has no subject).
   ========================================================================== */

/* --- BIO BANNER — DONOR (kmm.com/team/<slug>/, its `div.banner`) -------
   The base opens a bio on a WHITE band with the name in it and puts the
   portrait, the role and the contact details in the body's left column. The
   donor puts all four in a navy band above the fold and leaves the body to the
   prose alone. The donor's is the better page and it is section-local — a
   colour ground and a grid inside one band, both "no" rows on §2's table — so
   it transfers, and taking it empties the base's left column of everything but
   prose, which is the point.

   The band is the base's geometry, not the donor's:
     donor  550px band, 125px top pad, portrait 380x475 at margin-bottom -37
     ->     555px (this file's `.pagehead--photo`, the base's own `.banner`),
            `--header-h` top pad, the portrait plate stretched to the band's
            inner height and standing on its bottom edge, which is what the
            donor's negative margin buys.

   Its ground is FLAT navy rather than a photograph. The donor's own is an
   office interior washed until it reads as flat navy (its capture puts the
   image at 23% of the band's cover), we have no office photograph, and the one
   texture we do have is deliberately outside the duotone rule — see the note
   on `office_image` in inc/customizer.php. */
.pagehead--bio {
  position: relative;
  margin-top: 0;
  min-height: 555px;                             /* base — the same band */
  display: flex;
  align-items: flex-end;                         /* the plate stands on the floor */
  padding: var(--header-h) 0 0;
  background: var(--ground);                     /* donor ground, flat */
  overflow: hidden;                              /* donor — the plate is cut by the band */
  text-align: left;
}
/* THE RENDER CAUGHT THIS AND NO ASSERTION DID. `.wrap` is `max-width:1280;
   margin:0 auto`, which centres a BLOCK — but the band is a flex container, so
   the wrap became a flex item, sized to its content, and the whole banner sat
   in a 739px box floating in the middle of the page while the header's own
   wordmark stayed on the 100px grid line. Every count passed: no overflow, no
   new inset, no console error. `.pagehead--photo` has the same shape and never
   showed it, because its only child is centred text and centred-in-1280 and
   centred-in-739 look identical. */
/* THE PLATE COLUMN IS 4:5, AND THAT IS NOT A TASTE CALL.
   Reported by the client: "change rectangle image outline in single attorney
   page and crop photos properly." Both halves are one defect.

   The six portraits were cut ONCE, by site/tools/crop-portraits.mjs, to
   800x1000 -- 4:5, head 0.515 of the frame, eye line 0.32. That is device 1
   of the three that make a mixed-source roster read as commissioned rather
   than bought (site/whitaker-reskin-spec.md Part 5), and it only holds if
   whatever displays the file keeps its ratio.

   This column was 260x448 -- 1:1.72, the DONOR's proportion, which its own
   bio can carry because its portrait is a cut-out with no background to lose.
   Ours is a rectangle. `cover` therefore threw away 27% of every frame's
   width, off both sides, and the six faces stopped sharing a scale the moment
   they were widest -- Priya lost a shoulder, Ross lost an arm.

   358x448 is 4:5 to within a pixel. Nothing is cropped, the eye lines land on
   one line again, and the plate still stands on the band's floor and fills it
   top to bottom. */
.pagehead--bio > .wrap {
  width: 100%;
  display: grid;
  grid-template-columns: 358px minmax(0, 1fr);   /* 358 x 448 = 4:5, the crop's own ratio */
  gap: var(--sp-6);
  align-items: end;
}
.pagehead--bio .bio__portrait {
  height: 448px;                                 /* 555 - --header-h: the plate fills the band */
  margin: 0;
  /* THE OUTLINE. A bare rectangle on a flat navy ground has no edge of its
     own -- it reads as a hole in the band rather than as a plate on it. This
     is the hairline .biorail already draws two inches to its right, at the
     same 2px every rule in this build is drawn at, so it adds a weight to
     nothing. `outline` and not `border`, so the 4:5 box stays 4:5. */
  outline: 2px solid rgba(255, 255, 255, 0.35);
  outline-offset: 0;
}
.pagehead--bio .pagehead__title {
  font-family: var(--f-serif);                   /* donor — its bio h1 is Butler, and the
                                                    serif slot is already the donor's */
  font-weight: 400;
  font-size: var(--t-4xl);                       /* base — 60px, and the donor's h1 is 60 */
  text-align: left;
  text-transform: none;                          /* a person's name is not a label */
  color: #fff;
}
.pagehead--bio .bio__meta { padding-bottom: var(--sp-6); }

/* --- BIO CONTACT RAIL — DONOR (its `.attorney-banner-right` block) -----
   Two columns split by a hairline: the direct line on one side of it, the
   office address on the other, the address in the donor's uppercase. Its own
   lines are prefixed O: / T: / F: — this firm publishes one direct number and
   one office, so the labels are the two it has.

     donor  16px/1.5 sans, label and value on one line, 585px rail
     ->     16px (`--t-sm`) / 1.6 (`--lh-read`), columns sized by their content
            so the rule lands where the longer line ends. */
.biorail {
  display: grid;
  grid-template-columns: max-content max-content;
  justify-content: start;
  gap: var(--sp-5);
  margin-top: var(--sp-4);
}
.biorail > div + div {
  border-left: 2px solid rgba(255, 255, 255, 0.35);   /* donor — a hairline, not a gap */
  padding-left: var(--sp-5);
}
.biorail p {
  margin: 0 0 var(--sp-1);
  font-size: var(--t-sm);
  line-height: var(--lh-read);
  color: #fff;
}
.biorail b {
  font-weight: 400;
  color: rgba(255, 255, 255, 0.7);               /* donor — the label is the quieter half */
  margin-right: var(--sp-2);
}
.biorail a { color: #fff; }
.biorail a:hover, .biorail a:focus-visible { color: var(--lime); }
.biorail__office p { text-transform: uppercase; }   /* donor — its address is set in caps */

/* The donor closes the banner on a row of three square chips (email, vCard,
   PDF). Two of the three download files this build does not have, so the row
   carries the base's practice-area chips instead — the donor's slot, the
   base's cargo. `.bio__area` is unchanged from Part Three. */
.pagehead--bio .bio__areas { margin-top: var(--sp-4); }

/* --- SECTION STRIP — DONOR (its `.content-tabs`) ----------------------
   The donor runs this on every long interior route it has: a mist strip under
   the banner carrying the page's own section names as anchors. It is the one
   device on the donor's bio the base has no answer for — the base's sidebar
   links to SIBLINGS, so on a bio the sections have no navigation whatever, and
   the bio is the longest route on this site.

   It passes the §2 canvas test's cousin: in flow on the donor (its capture
   puts it between the banner's bottom and main's top), not fixed, reading
   nothing but its own box. It transfers.

     donor  88px strip, 16px/1.2 uppercase, active row underlined 3px
     ->     78.8px (25px `--sp-4` pad on the base's 18px/1.6 nav line), 2px
            underline — every rule this build draws is 2px, and a third weight
            for one strip is the mashup tell.

   Only the bio gets it. The practice single is a Part Two route, and moving it
   would move a number this part is not allowed to move. */
.tabs { background: var(--mist); }
.tabs__list {
  display: flex; flex-wrap: wrap;
  gap: 0 var(--sp-6);
  list-style: none; margin: 0; padding: 0;
}
.tabs__list li::before { display: none; }
.tabs a {
  display: block;
  padding: var(--sp-4) 0;
  font-family: var(--f-cond);
  font-size: var(--t-md);
  line-height: var(--lh-read);
  text-transform: uppercase;
  color: var(--ground);
  border-bottom: 2px solid transparent;
  transition: color var(--d-1) var(--e-out);
}
.tabs a:hover, .tabs a:focus-visible { color: var(--plum); border-bottom-color: var(--plum); }
/* The strip is in flow, and the header is fixed at `--header-h`, so every
   target it points at has to clear that much. `.prose h2` already does —
   the base's sidebar links into the same headings — and this is the same
   declaration for the targets that are not headings. */
.tabs__anchor { scroll-margin-top: var(--header-h); }

/* --- BIO BODY --------------------------------------------------------
   The interior grid with different cargo, not a second grid: `.page-grid`,
   `.prose`, `.side` and `.side__list` are the practice page's, unchanged.

   `--sectioned` is the donor's one addition to running prose: a hairline
   between sections rather than white space alone. Its own bio draws it, its
   practice page draws it under the leading head, and `--rule` is already the
   token every hairline on this site uses. Scoped to the bio so the practice
   page's numbers do not move. */
.prose--sectioned h2 {
  margin-top: var(--sp-7);
  padding-top: var(--sp-6);
  border-top: 2px solid var(--rule);
}
.prose--sectioned h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }

.bio__portrait {
  background-size: cover;
  /* At 4:5 in a 4:5 box there is nothing left to bias, so this is now only
     the mobile plate's crop -- see the 700 block, where the band is wide and
     the frame has to give up its bottom. 20% holds the eye line. */
  background-position: 50% 20%;
  background-color: var(--mist);
}
.bio__role {
  font-family: var(--f-cond);
  font-weight: 300;
  font-size: var(--t-md);            /* donor — its role is the small letterspaced label
                                        under the name, not a second headline. The base
                                        sets 30px; this is the donor's decision taken at
                                        the base's own nav step. */
  line-height: var(--lh-read);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.75);
  margin: var(--sp-2) 0 0;
}
.bio__areas { margin-top: var(--sp-3); }
.bio__area {
  display: inline-block;
  margin: 0 var(--sp-1) var(--sp-1) 0;
  padding: var(--sp-1) var(--sp-2);
  background: var(--plum);
  font-family: var(--f-cond);
  font-size: var(--t-xs);
  line-height: var(--lh-read);
  text-transform: uppercase;
  color: #fff;
  transition: background var(--d-1) var(--e-out);
}
a.bio__area:hover, a.bio__area:focus-visible { background: var(--teal); }
.side__back { margin-top: var(--sp-3); }
.side__back a, .article__back a {
  font-family: var(--f-cond);
  font-size: var(--t-md);
  text-transform: uppercase;
  color: var(--plum);
}
.side__back a:hover, .article__back a:hover,
.side__back a:focus-visible, .article__back a:focus-visible { color: var(--ground); }

/* --- PRACTICE BARS — DONOR (kmm.com/practices/) -----------------------
   Both references open this route on a photographic banner and neither opens
   it on a white head, which is what Part Three gave it; that half is a base
   correction the donor happens to agree with. The index itself is the donor's:

     base   five 20%-wide colour boxes stacked into a 400px sidebar rail, with
            the prose beside them
     donor  a centred intro measure, then a two-up grid of wide short bars,
            each a photograph washed dark with its title at the left and a `+`
            at the right

   The donor's wins on one measurable ground: an index has to carry
   `_whm_blurb`, and 248px of usable width inside a 20% box cannot hold a
   sentence. The bar is 620px at 1440.

   The colours are the base's, in the base's order, and they are the same five
   an area's box carries on the home page — so the ground under each bar is the
   ground you land on when you click it.

     donor  bar 80px tall, title 16px bold sans
     ->     `--sp-7` (100px) minimum, title 30px (`--t-xl`) Butler 400 — the
            step and the face `.practices__item h3` already uses, because these
            are the same five boxes in a second shape and not a second design
            of them. A minimum rather than a height, because the bar carries a
            second line the donor's does not. */
.bars { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-5); margin-top: var(--sp-6); }
/* FIVE INTO TWO. The donor's own grids are 6 and 6, so its arrangement never
   has to answer this; ours is five and a two-column grid leaves a hole at the
   bottom right. The hole is the same defect Part Three named on the search
   route — "three-up leaves a ragged last row on any count that is not a
   multiple of three" — and the answer is the same component, wider, rather
   than a second row style. */
.bars__item:last-child:nth-child(odd) { grid-column: 1 / -1; }
.bars__item {
  position: relative;
  display: flex; align-items: center; gap: var(--sp-3);
  min-height: var(--sp-7);
  padding: var(--sp-3) var(--sp-4);
  overflow: hidden;
  isolation: isolate;                            /* the wash composites against the
                                                    photograph and nothing else */
  transition: opacity var(--d-1) var(--e-out);
}
.bars__item:hover { opacity: 0.85; }
/* graded by the SAME rule as the hero, the testimonial and the page head, so
   the photographic bands on this site stay one decision rather than four */
.bars__stage { position: absolute; inset: 0; }
.bars__img {
  position: absolute; inset: 0;
  background-size: cover; background-position: center center;
  filter: grayscale(1) contrast(1.05) brightness(1.22);
}
/* 0.75, not the page head's 0.6, and the scrim below is lighter to pay for it.
   At the head's own settings the five bands came back as five dark greys with a
   hint of hue — which loses the one thing this component is for, that the
   ground under a bar is the ground you land on when you click it. */
.bars__wash { position: absolute; inset: 0; mix-blend-mode: screen; opacity: 0.75; }
/* THE PAGE HEAD'S PLATEAU, ROTATED. A flat scrim was the first answer and
   `typecontrast.mjs` measured it at worst 3.82 with 1.4% of the blurb's run
   under 4.5 — the same failure the page head had, on the same component's
   smaller type. A 100px bar has no top and bottom to open up, but it has a
   left and a right: the type is all in the left three-quarters and the `+` is
   the only thing beyond it. So the plateau runs ACROSS instead of down, dark
   where the type is and open where the photograph should show — which is also
   what the donor's own bars do (its capture darkens the left of every one). */
.bars__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(to right,
    rgba(14, 31, 48, 0.76) 0%,
    rgba(14, 31, 48, 0.76) 76%,
    rgba(14, 31, 48, 0.44) 100%);
}
.bars__item[data-band="1"] .bars__wash { background: var(--plum); }
.bars__item[data-band="2"] .bars__wash { background: var(--teal); }
.bars__item[data-band="3"] .bars__wash { background: var(--olive); }
.bars__item[data-band="4"] .bars__wash { background: var(--stone); }
.bars__item[data-band="5"] .bars__wash { background: var(--ground); }
.bars__text { position: relative; z-index: 1; flex: 1 1 auto; }
.bars__title {
  display: block;
  font-family: var(--f-serif);                   /* donor face, base step */
  font-weight: 400;
  font-size: var(--t-xl);
  line-height: var(--lh-head);
  color: #fff;
}
.bars__blurb {
  display: block;                                /* TRAP §8.17 — a <span>, because it
                                                    lives inside an <a> */
  margin-top: var(--sp-1);
  font-family: var(--f-sans);
  font-size: var(--t-sm);
  line-height: var(--lh-read);
  color: #fff;
}
/* donor — a `+` at the right edge of every bar. Drawn, because its own is a
   FontAwesome glyph and the kits are bucket 3. Two 2px rules crossed, 2px
   being the only rule weight on this site. */
.bars__plus {
  position: relative; z-index: 1;
  flex: 0 0 auto;
  width: 18px; height: 18px;
}
.bars__plus::before, .bars__plus::after { content: ""; position: absolute; background: #fff; }
.bars__plus::before { left: 0; right: 0; top: 8px; height: 2px; }
.bars__plus::after  { top: 0; bottom: 0; left: 8px; width: 2px; }

/* --- LEDE BAND — DONOR (kmm.com/firm/history/, its `.section-found`) ---
   The donor's answer to an untemplated page, and to the top of a long article:
   the opening does not run at reading size across one measure, it splits into
   a large serif statement and the paragraph that expands it, on the mist
   ground, with the ghosted monogram across the bottom.

   The base's answer is one centred 823px measure and nothing else, which is
   what Part Three gave both routes. The donor's is section-local — a colour
   ground and a grid inside one band — so it transfers.

     donor  statement 40px Butler 300 / 1.200, body 18px/1.5, band pad 40px,
            columns 347 : 540 inside 1200
     ->     36px (`--t-2xl`) Butler 400 / 1.4 (`--lh-head`), body 18px
            (`--t-md`) / 1.6 (`--lh-read`), band pad 100px (`--sp-7`, the
            base's own band figure — this band is followed by another of a
            different ground, so the pad is a real edge), 5fr : 7fr.

   The monogram is the donor's own device and is already in this file on the
   hero; here it is dark on light rather than light on dark, which is the
   donor's own treatment of it on this exact band. */
.ledeband {
  position: relative;
  overflow: hidden;
  background: var(--mist);                       /* donor ground */
  padding: var(--sp-7) 0;
}
.ledeband__grid {
  position: relative; z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--sp-6);
  align-items: start;
}
.ledeband__statement {
  margin: 0;
  font-family: var(--f-serif);                   /* donor face, donor device */
  font-weight: 400;
  font-size: var(--t-2xl);
  line-height: var(--lh-head);
  color: var(--ground);
}
.ledeband__body p {
  margin: 0 0 var(--sp-3);
  font-size: var(--t-md);
  line-height: var(--lh-read);
}
.ledeband__body p:last-child { margin-bottom: 0; }
/* one paragraph and then a heading: the band drops to one column rather than
   holding 640px of mist open beside the statement */
.ledeband__grid--solo { grid-template-columns: minmax(0, 1fr); }
.ledeband__grid--solo .ledeband__statement { max-width: var(--wrap-narrow); }
.ledeband__mark {
  position: absolute;
  left: 50%; bottom: -0.2em;
  transform: translateX(-50%);
  font-family: var(--f-serif);
  font-weight: 300;
  font-size: 21vw;                               /* the hero monogram's own size */
  line-height: 0.78;
  color: rgba(14, 31, 48, 0.05);                 /* donor — the ground's own hue at a few
                                                    per cent, not a grey */
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
}

/* --- SITEMAP — DONOR (kmm.com's 404) ---------------------------------
   The donor's 404 is a sitemap: every route it has, grouped under a heading
   per group. The base's is a banner and an apology. Part Three wrote five
   hand-listed links, which is the base's shape with the donor's capture
   unopened.

   The rows are `.side__head` and `.side__list` — the base's most distinctive
   interior device, unchanged — so this is the donor's composition in the
   base's component, and it costs no new type, no new rule weight and no new
   colour.

   The search route takes the same list, grouped by post type, because a result
   list and a sitemap are the same object. There is no donor capture of a
   search page; that route's donation is the 404's, used twice, and the notes
   say so. */
.sitemap { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-6) var(--sp-7); text-align: left; }
.sitemap__group { min-width: 0; }
.sitemap .side__head { margin-top: 0; }
/* The form keeps the base's 823px measure and gives up its centring: on both
   routes that carry it the block underneath is the full-width sitemap, and a
   centred form over a flush-left list is two left edges 208px apart. */
.search__form { max-width: 823px; margin: 0 0 var(--sp-6); text-align: left; }
.searchform__row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp-2); }
.searchform .form__label { text-align: left; }

/* --- INSIGHTS, the two ends the home row was missing ------------------ */
/* `--single` is index.php's, not search's. Part Four moved the search route
   onto the donor's grouped list, and the one-column card variant would have
   gone with it if the required fallback did not still use it — an archive or a
   feed with no more specific template is the only thing that reaches it. */
.insights__grid--single { grid-template-columns: 1fr; gap: 0; }
.insights__grid--single .insights__item { border-bottom: 2px solid var(--rule); }
.insights__lede {
  display: block;                    /* TRAP §8.17 again — same shape, same fix */
  margin-top: var(--sp-2);
  font-size: var(--t-sm);
  line-height: var(--lh-read);
  color: var(--body);
}
/* An article is read down its measure, not centred across it. It keeps
   `--centred`'s 823px and drops its alignment. */
.prose--article { text-align: left; }
.prose--article .insights__date { margin-bottom: var(--sp-3); }
.article__back { margin-top: var(--sp-6); }

/* ==========================================================================
   REVEAL — bucket 2. The base fades each band up on entry with its own
   .animated fadeInUp; rebuilt against native scroll on the base's curve.
   ========================================================================== */

.reveal { opacity: 0; transform: translateY(36px); transition: opacity var(--d-3) var(--e-out), transform var(--d-3) var(--e-out); }
.reveal.is-in { opacity: 1; transform: none; }

/* ==========================================================================
   MOBILE — 390. The base's ladder caps at 35px and its hero title moves OFF
   the photograph into a solid band of that slide's own colour.
   ========================================================================== */

@media (max-width: 1024px) {
  .roster__strip { grid-template-columns: repeat(3, 1fr); }
  .insights__grid { grid-template-columns: repeat(2, 1fr); }
  .practices__item { width: 33.3333%; }
  .testimonial__outer { padding: 0 var(--sp-6); }

  /* the sidebar drops under the column it annotates rather than shrinking —
     at 400px fixed it would eat the measure long before it ran out of room */
  .page-grid { grid-template-columns: 1fr; gap: var(--sp-6); }
  /* the donor runs its own bar grid two-up to 1024 and one-up under it */
  .bars { grid-template-columns: 1fr; }
  .ledeband__grid { grid-template-columns: 1fr; gap: var(--sp-4); }
  .sitemap { grid-template-columns: 1fr; }
  /* the plate stops being a column and becomes the band's left third */
  .pagehead--bio > .wrap { grid-template-columns: 200px minmax(0, 1fr); gap: var(--sp-5); }

  /* The nav collapses HERE, not at 700.
     These five rules were in the 700 block, which left 701–1100 showing the
     desktop nav in a bar that cannot hold it: the wordmark plus five items
     overflowed by 304px at 768, on every route, since the home page was built.
     The rest of the 700 block — the plum bar, the type ladder, the title
     bands — is a phone design and stays at 700; only the nav needed the
     wider gate, which is why it moved rather than the block. */
  .header__toggle { display: block; }
  .nav { display: none; }

  /* SPEC 1.1 / 17 A1. The tel drops to the icon alone the moment the nav
     collapses. At 390 the wordmark box is 328px and the toggle is 40, so the
     number as type would not fit on the row and 8/8 of the teardown put SOME
     callable thing in that fold. The link keeps its 40px target and its
     accessible name comes from the number, which is still in the markup. */
  .header__tel { order: 0; padding: var(--sp-2); }   /* logo, call, menu — call before menu */
  .header__telnum { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .nav.is-open {
    display: block;
    position: absolute; top: 100%; left: 0; right: 0;
    background: var(--ground);
    padding: var(--sp-3) 0;
  }
  .nav.is-open ul { display: block; }
  .nav.is-open a { text-align: center; color: #fff; }
  /* In the drawer the link is full width and centred, so an underline would
     run the whole panel. The accent alone carries it. */
  .nav.is-open .current-menu-item > a,
  .nav.is-open .current-menu-ancestor > a,
  .nav.is-open .current-menu-parent > a { color: var(--lime); box-shadow: none; }
  .side { max-width: 823px; }
}

@media (max-width: 700px) {

  /* THE STICKY CALL BAR — SPEC 6.1 / 17 A3. Phone only.

     56px. Spec 6.3 caps a fixed element at ~180px because one site in the
     teardown runs a cookie banner at 249px of an 844px viewport; the mobile
     header is 63px, so the pair take 119px and each passes on its own.

     `.footer` gets the same 56px of bottom padding so the bar never sits on
     top of the last line of the page. */
  .callbar {
    display: flex;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 10001;
    height: 56px;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    background: var(--plum);
    color: #fff;
    font-family: var(--f-cond);
    font-size: var(--t-md);
    line-height: 1;
    text-transform: uppercase;
  }
  .callbar:focus-visible { outline: 3px solid var(--lime); outline-offset: -3px; }
  .footer { padding-bottom: calc(var(--sp-5) + 56px); }

  :root {
    --t-5xl: 35px;    /* base — its whole top end collapses to 35 at 390 */
    --t-4xl: 32px;
    --t-3xl: 30px;
    --t-2xl: 24px;
    --t-xl:  24px;
    --sp-7:  var(--sp-6);
    --sp-8:  var(--sp-6);
    --sp-9:  var(--sp-3);
    --header-h: 63px;   /* measured, same as at 1440: this is OUR bar, not the base's */
  }

  /* base — the mobile header is a SOLID plum bar, not a transparent overlay */
  .header { position: fixed; background: var(--plum); padding: var(--sp-2) 0; }
  .header.is-stuck { background: #fff; }
  .header__mark { font-size: var(--t-2xl); }
  .header__sub { font-size: var(--t-xs); }

  /* base — THE DEVICE: the title leaves the photograph and sits in a solid
     band of the slide's own colour underneath it.

     The stage/title split built for the desktop crossfade pays for itself
     here: the band is simply the titles block dropped back into normal flow
     under the stage, and no markup changes to get it. */
  .hero__viewport { height: auto; min-height: 0; }
  .hero__stage { position: relative; inset: auto; height: 58vw; min-height: 260px; }
  .hero__monogram { top: 29vw; font-size: 46vw; }

  /* the band is flat colour, so it carries its own contrast and the
     photograph's wash is not doing that job any more */
  .hero__scrim { display: none; }

  .hero__titles { position: relative; inset: auto; pointer-events: auto; }
  .hero__type {
    position: relative;
    inset: auto;
    display: none;
    opacity: 1;
    transition: none;
    padding: var(--sp-5) var(--sp-3) 56px;
    text-align: center;
  }
  .hero__type.is-active { display: block; opacity: 1; transition: none; }
  .hero__title {
    top: 0;
    max-width: none;
    text-align: center;
    text-shadow: none;                 /* the band is flat colour — no photograph under it */
  }
  .hero__titles .hero__type:nth-child(1) { background: var(--teal); }
  .hero__titles .hero__type:nth-child(2) { background: var(--olive); }
  .hero__titles .hero__type:nth-child(3) { background: var(--plum); }
  .hero__titles .hero__type:nth-child(4) { background: var(--stone); }
  .hero__titles .hero__type:nth-child(5) { background: var(--ground); }

  /* THE ACCENT COLOUR IS A FUNCTION OF THE BAND, and the base already knew it.
     Its stylesheet carries two: `.tagline em` in lime for the slides whose
     ground is a dark photograph, and `.tagline em.pink` in plum for the ones
     whose ground is a light colour band. The first build implemented only the
     lime half, so on the olive band at 390 the accent word measured against
     its own ground and effectively disappeared.

     Dark bands keep the lime; light bands take the donor navy, which is
     already a token. No colour is added to buy this back. */
  .hero__titles .hero__type:nth-child(1) em,
  .hero__titles .hero__type:nth-child(2) em,
  .hero__titles .hero__type:nth-child(4) em { color: var(--ground); }
  .hero__titles .hero__type:nth-child(3) em,
  .hero__titles .hero__type:nth-child(5) em { color: var(--lime); }

  /* THE CTA LEAVES THE PHOTOGRAPH TOO. Same move the titles make: the hero is
     no longer a full-height picture with things floating on it, so the button
     drops back into normal flow under the colour band.

     The COLOURS do not change and do not need to. `.hero` paints var(--ground)
     at 347, and .hero__viewport is height:auto here, so the strip under the
     band is navy, not paper — white fill on navy is the same pairing it has at
     1440. Centred, because the band above it is centred here and right-aligned
     there.

     ⚠ THE 56px BOTTOM IS THE PAUSE CONTROL'S ROOM, and it is the same 56px
     .hero__type reserves above for the same reason. MEASURED, 375x812: the
     pause is absolute against .hero__viewport, so adding this block to the
     flow moved the viewport's bottom edge down and took the pause with it —
     34px tall at bottom:10px, it landed on 538-572 while the button ran
     490-542 at left 48. A 6x4px corner overlap on the one control that stops
     the carousel. At 40px (--sp-5) it clips; at 56 the pause clears the button
     by 12px. Re-test at 375 and 360 before changing this number. */
  .hero__cta {
    position: static;
    padding: var(--sp-4) var(--sp-3) 56px;
    text-align: center;
  }
  /* The subhead comes down with its headline into the colour band. No
     photograph under it here, so the shadow that buys contrast at 1440 is just
     dirt on a flat ground — the same call .hero__title makes four rules up —
     and `top: 180px` goes with the title's, which is also zeroed here.

     CONTRAST IS THE HEADLINE'S, EXACTLY: same white, same five flat grounds,
     and at 24px this is still WCAG large text, so it is held to the same 3.0
     the 35px title is. Measured at 375 — teal 3.81, olive 3.11, plum 8.69,
     stone 4.36, ground 16.70. Olive is the floor and it has always been the
     floor; it is the band the accent-colour rule below was written for.
     ⚠ 3.11 has 0.11 of headroom. Do not drop this below 24px — at 23px it
     stops being large text, the bar becomes 4.5, and three of the five bands
     fail on the spot. */
  .hero__sub {
    top: 0;
    max-width: none;
    margin: var(--sp-3) auto 0;
    text-align: center;
    text-shadow: none;
  }

  /* The base shows no slide dots at 390 at all — just the pause control. Ours
     were sitting over the brightest part of the photograph. */
  .hero__rail { display: none; }
  .hero__cue { display: none; }
  .hero__pause { bottom: var(--sp-2); left: var(--sp-3); }

  .roster__strip { grid-template-columns: 1fr; }     /* base — full-bleed one column at 390 */
  .roster__card { min-height: 380px; }
  .insights__grid { grid-template-columns: 1fr; gap: 0; }
  .insights__item { padding: var(--sp-4) 0; border-bottom: 2px solid var(--rule); }
  .practices__item { width: 50%; height: 140px; }
  .testimonial__mark { display: none; }
  .footer li a { padding: var(--sp-1) 14px; }

  /* --- interior routes at 390 ---------------------------------------- */

  /* base — its interior header at 390 is the SAME solid plum bar the home page
     gets, not the white desktop one. Both of its captures show it. */
  .is-solidhead .header           { background: var(--plum); border-bottom: 0; }
  .is-solidhead .header__mark,
  .is-solidhead .nav a            { color: #fff; }
  .is-solidhead .header__mark b   { color: var(--lime); }
  .is-solidhead .header__sub      { color: rgba(255, 255, 255, 0.8); }
  .is-solidhead .header__toggle   { border-color: #fff; color: #fff; }
  /* On the plum bar the desktop's plum marker would be invisible, so the
     current row takes the same white + lime pair the hero header uses. */
  .is-solidhead .nav .current-menu-item > a,
  .is-solidhead .nav .current-menu-ancestor > a,
  .is-solidhead .nav .current-menu-parent > a { color: #fff; box-shadow: inset 0 -2px 0 var(--lime); }
  .is-solidhead .header.is-stuck  { background: #fff; }
  .is-solidhead .header.is-stuck .header__mark,
  .is-solidhead .header.is-stuck .nav a       { color: var(--ground); }
  .is-solidhead .header.is-stuck .header__mark b { color: var(--plum); }
  .is-solidhead .header.is-stuck .header__sub { color: rgba(14, 31, 48, 0.5); }
  .is-solidhead .header.is-stuck .header__toggle { border-color: var(--ground); color: var(--ground); }
  .is-solidhead .header.is-stuck .nav .current-menu-item > a,
  .is-solidhead .header.is-stuck .nav .current-menu-ancestor > a,
  .is-solidhead .header.is-stuck .nav .current-menu-parent > a { color: var(--plum); box-shadow: inset 0 -2px 0 var(--plum); }

  /* base — THE DEVICE, and it is the same one the hero uses: the title leaves
     the photograph and sits in a solid band of that page's own colour under it.
     bick-practice-mobile.webp is exactly this, in plum. */
  .pagehead--photo {
    display: block;
    min-height: 0;
    padding: 0;
    isolation: auto;                             /* nothing blends over the band */
  }
  .pagehead__stage { position: relative; height: 58vw; min-height: 200px; }
  .pagehead--photo .pagehead__scrim { display: none; }   /* the band carries its own contrast now */
  .pagehead--photo > .wrap { padding-top: var(--sp-5); padding-bottom: var(--sp-5); }
  .pagehead--photo .pagehead__title { text-shadow: none; }

  .pagehead--photo[data-band="1"] > .wrap { background: var(--plum); }
  .pagehead--photo[data-band="2"] > .wrap { background: var(--teal); }
  .pagehead--photo[data-band="3"] > .wrap { background: var(--olive); }
  .pagehead--photo[data-band="4"] > .wrap { background: var(--stone); }
  .pagehead--photo[data-band="5"] > .wrap { background: var(--ground); }

  /* The accent colour is a function of the band, exactly as it is in the hero:
     the base carries `.tagline em` in lime for its dark grounds and
     `.tagline em.pink` for its light ones. Light bands take the donor navy. */
  .pagehead--photo[data-band="2"] .pagehead__title em,
  .pagehead--photo[data-band="3"] .pagehead__title em,
  .pagehead--photo[data-band="4"] .pagehead__title em { color: var(--ground); }
  .pagehead--photo[data-band="1"] .pagehead__title em,
  .pagehead--photo[data-band="5"] .pagehead__title em { color: var(--lime); }

  .form__row { grid-template-columns: 1fr; gap: 0; }
  .office { grid-template-columns: 1fr; gap: var(--sp-3); }
  .office__photo, .office__mapframe { height: 200px; }
  /* THE BIO BANNER AT 390 — the base's device on the donor's composition.
     The donor keeps the whole banner on the navy and centres the portrait over
     the type. The base's rule for every photographic band on this site is that
     the TYPE leaves the picture for a solid band of the page's own colour
     under it, and it is already written above for `.pagehead--photo`. The plate
     is the picture here, so the plate becomes the band and the name, the role,
     the rail and the chips sit on the navy beneath it — which is also, by
     arithmetic rather than by copying, what the donor's own 390 capture does. */
  .pagehead--bio {
    display: block;
    min-height: 0;
    padding: 0;
  }
  .pagehead--bio > .wrap { display: block; padding-bottom: var(--sp-6); }
  /* 82vw, not the `.pagehead__stage`'s 58vw. A landscape band is right for a
     photograph of a place and wrong for a photograph of a person: at 58vw the
     plate cropped to forehead-and-chin. The donor's own 390 capture gives the
     portrait 380px of a 1051px banner, and 82vw is 320px here. */
  /* 4:5 HERE TOO. 82vw against a full-bleed 100vw was a LANDSCAPE box holding
     a portrait frame, and `cover` answered it the only way it can: it threw
     away the top of the head and the shoulders and left a face crop. 125vw is
     the same 4:5 the desktop plate now uses, so the phone and the laptop show
     the same photograph rather than two different ones.
     No outline: the plate is edge to edge here by design, and an outline on a
     box that touches the viewport is a line against the bezel. */
  .pagehead--bio .bio__portrait { height: 125vw; min-height: 325px; margin: 0 calc(var(--gutter) * -1) var(--sp-5); outline: none; }
  .pagehead--bio .pagehead__title { font-size: var(--t-2xl); }
  .pagehead--bio .bio__meta { padding-bottom: 0; }
  /* the vertical hairline becomes a horizontal one, which is the donor's own
     390 answer to the same problem */
  .biorail { grid-template-columns: 1fr; gap: var(--sp-3); }
  .biorail > div + div {
    border-left: 0;
    border-top: 2px solid rgba(255, 255, 255, 0.35);
    padding-left: 0;
    padding-top: var(--sp-3);
  }
  .tabs__list { gap: 0 var(--sp-4); }
  .tabs a { padding: var(--sp-3) 0; }
  .ledeband__statement { font-size: var(--t-xl); }
  .ledeband__mark { display: none; }   /* 21vw of monogram under 390px of type is noise */
  .searchform__row { grid-template-columns: 1fr; }
}

/* ==========================================================================
   REDUCED MOTION — playbook §5.9. Disabling the animation must not disable
   the thing that made the content visible.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .reveal { opacity: 1 !important; transform: none !important; }
  .hero__slide { opacity: 1; }
  .hero__cue svg { animation: none; }
}
