/* Bella Law PLLC. One stylesheet, no framework, no build step.
   Tokens from bella-law/website/design-brief-the-grove.md section 5.
   Type from bella-law/assets/brand-spec.md, given the air the brief asks for. */

@import url('../fonts/fonts.css');

:root {
  /* Palette. Spec colours unchanged; --ochre is the one addition. */
  --cream:        #F7F5EF;
  --forest:       #1C4632;
  --olive:        #8AB441;
  --ink:          #141E18;
  --ochre:        #B99A6B;
  --stone:        #D8E3D9;
  --forest-pale:  #EBF1EC;
  /* Was #546158, which measured 5.97:1 on cream. It passes AA and misses the 7:1 target the
     2026-09-21 craft research recommends for body copy at the luxury end, where low-contrast
     grey is the most common single failure. Same hue and saturation, darker. Now 7.48:1. */
  --secondary:    #47524A;

  /* THE OLIVE PROBLEM, measured 2026-09-21.
     --olive on cream is 2.22:1. It was the colour of every eyebrow, every step number, every
     phase number and every form label on the site, at 11px uppercase. That is not a near miss
     against the 4.5:1 floor, it is under half of it, and it reads as faint rather than quiet.
     --olive on forest is 4.41:1, which is also short of the floor.
     The brand colour is not being abandoned. It keeps its exact hue (81.9deg) and saturation
     (0.469) and moves only in lightness, in two directions: one for small text on cream, one
     for small text on forest. --olive itself is unchanged and stays what it always was, the
     colour of the hairline rules and the logo accent, where contrast rules do not apply. */
  --olive-ink:    #455A20;   /* small text on cream:  7.04:1 */
  --olive-lift:   #A5CC55;   /* small text on forest: 5.77:1 */
  --accent-text:  var(--olive-ink);

  /* The sea's silver-blue lives only in footage, never as a UI colour.
     That discipline is what keeps this a law firm and not a resort. */

  --serif: 'Playfair Display', Georgia, serif;
  --sans:  'DM Sans', system-ui, -apple-system, sans-serif;
  --mono:  'DM Mono', ui-monospace, monospace;

  --measure: 66ch;
  --gutter: clamp(1.25rem, 5vw, 4rem);
  --section: clamp(4rem, 10vw, 8rem);
}

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  font-synthesis: none;
  text-rendering: optimizeLegibility;
}

/* Type scale. Desktop first value, mobile floor, fluid between. */
h1, h2, h3 { margin: 0 0 0.5em; font-weight: 400; }

/* Headings break evenly instead of leaving one orphaned word on the last line.
   This is what makes a display line "fall soft" rather than land ragged. */
h1, h2, .band__line, .quotes blockquote p { text-wrap: balance; }

h1 {
  font-family: var(--serif);
  /* Roman, not italic, from 2026-09-20. Playfair's roman has vertical stress that sits with
     the architecture in the hero frame; the italic's diagonal stress cut across it and read
     editorial rather than like counsel. .page-hero h1 keeps its own italic, so this is the
     homepage hero only. */
  font-style: normal;
  /* Sized for a two-sentence headline. At the old 4.5rem with a 15ch measure,
     a twelve-word line broke to five, and the type stopped being a statement
     and became a column. */
  font-size: clamp(2.125rem, 4.4vw, 3.625rem);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--forest);
}

h2 {
  font-family: var(--serif);
  font-size: clamp(1.75rem, 3vw, 2.5rem);    /* 28px -> 40px */
  line-height: 1.2;
  color: var(--forest);
}

h3 { font-family: var(--sans); font-weight: 600; font-size: 1.125rem; }

p { margin: 0 0 1.25em; max-width: var(--measure); }

/* The eyebrow is a <p>, so it inherited the 66ch reading measure. At 11px mono
   that is about 435px, which orphaned the last word of a three-part label. A
   label is not prose and does not want a reading measure. */
.eyebrow {
  max-width: none;
  text-wrap: balance;
  font-family: var(--mono);
  font-size: 0.6875rem;                       /* 11px */
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--accent-text);
  margin: 0 0 1rem;
}

.stat {
  font-family: var(--serif);
  font-size: clamp(2.25rem, 4.5vw, 3.5rem);   /* 36px -> 56px */
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

a { color: var(--forest); text-decoration-thickness: 1px; text-underline-offset: 0.2em; }

/* Focus is visible and on brand. Never removed. */
:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 3px; }

.skip {
  position: absolute; left: -9999px;
  background: var(--forest); color: var(--cream);
  padding: 0.75rem 1rem; z-index: 100;
}
.skip:focus { left: var(--gutter); top: 0.5rem; }

.wrap { max-width: 1200px; margin-inline: auto; padding-inline: var(--gutter); }

/* Buttons. One primary, one quiet. Never more than one primary in view. */
.btn {
  display: inline-block;
  font-family: var(--sans); font-weight: 500; font-size: 1rem;
  padding: 0.9rem 1.75rem;
  background: var(--forest); color: var(--cream);
  text-decoration: none; border: 1px solid var(--forest);
  /* The press response is taken from bellalawpllc.com, which gives its buttons a 60ms
     transform on :active. It is the one micro-interaction on that site worth keeping, and
     60ms sits inside the 100-150ms band the 2026-09-21 craft research gives for micro
     interactions. A button that does not acknowledge a press feels broken on a touch screen. */
  transition: background 120ms ease, transform 60ms ease-in;
}
.btn:hover { background: var(--ink); }
.btn--quiet { background: transparent; color: var(--forest); border-color: var(--ochre); }
.btn--quiet:hover { background: var(--forest-pale); }

/* Hero. The poster is the LCP element; the video is decoration that arrives later. */
.hero { position: relative; min-height: 92svh; display: grid; align-items: end; overflow: hidden; }
.hero__media { position: absolute; inset: 0; }
.hero__media img, .hero__media video {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* The video cross-fades in over the poster once it can play through, and fades
   back out if it stalls. The poster underneath is never removed, so there is no
   moment where the hero is blank. */
.hero__media video { position: absolute; inset: 0; opacity: 0; transition: opacity 900ms ease; }
.hero__media video.is-ready { opacity: 1; }
/* Two scrims, not one. The poster is a pale sunrise, so a single bottom gradient
   leaves the headline sitting on the brightest part of the frame. That is exactly
   how the old site's hero failed. The vertical gradient anchors the text block;
   the horizontal one darkens the left third where the copy actually lives. */
/* The scrim carried .30 at 55% of the height and .06 at 78%, and the eyebrow sits at the top
   of the content block, right where those two stops meet. Over the pale sunrise on the right
   of the frame the combined darkening came to roughly a quarter, which is not enough behind
   11px letterspaced mono: measured by eye on 2026-09-21, the last two words of the eyebrow
   were not readable. The vertical ramp is extended rather than deepened, so the film keeps its
   light and only the band the text occupies gains ground. */
.hero__scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(to top,
      rgba(16,26,20,.80) 0%, rgba(16,26,20,.64) 28%,
      rgba(16,26,20,.46) 55%, rgba(16,26,20,.22) 78%, transparent 100%),
    linear-gradient(to right,
      rgba(16,26,20,.48) 0%, rgba(16,26,20,.26) 45%, rgba(16,26,20,.05) 72%, transparent 88%);
}
.hero__content { position: relative; padding-block: var(--section) 3.5rem; color: var(--cream); }
.hero__content h1 {
  /* 19.75ch in roman == the 21ch the italic measured. Without this the block shifts left. */
  color: var(--cream); max-width: 19.75ch;
  text-shadow: 0 1px 24px rgba(16,26,20,.45);
}
.hero__sub { font-size: 1.0625rem; max-width: 46ch; color: var(--cream); opacity: .95;
  text-shadow: 0 1px 16px rgba(16,26,20,.45); }
/* The h1 and the sub-line both carried a text-shadow and these two did not, which is why the
   smallest type on the page was the hardest to read on the brightest part of the frame. */
.hero__note { font-family: var(--mono); font-size: 0.6875rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--cream); opacity: .92; margin-top: 1rem;
  text-shadow: 0 1px 14px rgba(16,26,20,.6); }

@media (prefers-reduced-motion: reduce) {
  .hero__media video { display: none; }
  * { animation: none !important; transition: none !important; }
}

/* The only scroll animation on this site: one olive hairline per section. */
.rule { height: 1px; background: var(--olive); width: 0; transition: width 900ms ease; }
.rule.is-in { width: 100%; }

/* ---------------------------------------------------------------------------
   Page furniture. Everything below is used by index.html and the interior
   templates. One stylesheet, no framework, no build step.
   --------------------------------------------------------------------------- */

/* Header. A hairline of cream. The video owns the viewport beneath it. */
.site-header { position: absolute; inset: 0 0 auto; z-index: 10; padding-block: 1.5rem; }
.site-header__inner { display: flex; align-items: center; justify-content: space-between; gap: 2rem; }
.lockup { text-decoration: none; display: block; color: var(--cream); }
.lockup__mark { font-family: var(--serif); font-size: 1.5rem; line-height: 1; letter-spacing: -0.01em; display: block; }
.lockup__line { font-family: var(--mono); font-size: 0.625rem; text-transform: uppercase; letter-spacing: 0.18em; opacity: .85; display: block; margin-top: .3rem; }
.nav { display: flex; align-items: center; gap: 1.75rem; }
.nav a { color: var(--cream); text-decoration: none; font-size: .9375rem; }
.nav a:not(.btn):hover { text-decoration: underline; text-underline-offset: .35em; }
/* The header sits over a pale sunrise. A transparent outline button disappears into it,
   which is exactly how the old site's hero failed. Solid ground, plus a soft shadow
   behind the whole header so the nav links hold at any frame of the video. */
/* nowrap is unconditional. It used to apply only below 860px, so adding a fourth nav link on
   2026-09-21 made the button break to two lines between roughly 880 and 1050 and grow the header
   by 10px. That is the same two-line button failure recorded at the small-screen block below. */
.btn:active { transform: translateY(1px); }
@media (prefers-reduced-motion: reduce) { .btn:active { transform: none; } }
.btn--sm { white-space: nowrap; padding: .6rem 1.1rem; font-size: .875rem; background: rgba(20,30,24,.42);
  border-color: rgba(247,245,239,.55); color: var(--cream); backdrop-filter: blur(6px); }
.btn--sm:hover { background: rgba(20,30,24,.66); border-color: var(--cream); }
.site-header::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgba(16,26,20,.45) 0%, rgba(16,26,20,.18) 60%, transparent 100%);
}
.site-header__inner { position: relative; }
.lockup, .nav a { text-shadow: 0 1px 12px rgba(16,26,20,.5); }
.btn--light { background: var(--cream); color: var(--forest); border-color: var(--cream); }
.btn--light:hover { background: #fff; }
/* The rule that used to live here hid .nav a:not(.btn) below 940px and put nothing in its
   place. It is replaced by the navigation panel at the end of this file. */

/* The citation sits directly under the claim it supports, above the call to
   action, so a reader who checks things finds the source before the ask. */
.hero__cite {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .06em;
  color: var(--cream); opacity: .82; margin: 1rem 0 0; max-width: 74ch;
  line-height: 1.7;
  text-shadow: 0 1px 16px rgba(16,26,20,.5);
}
.hero__cite em { font-style: italic; }
.hero__cta { margin-top: 1.5rem; }
.eyebrow--light { color: var(--cream); opacity: .96;
  text-shadow: 0 1px 14px rgba(16,26,20,.6), 0 0 32px rgba(16,26,20,.4); }

/* Sections */
.section { padding-block: var(--section); }
.section--pale { background: var(--forest-pale); }
.section--deep { background: var(--forest); color: var(--cream); }
.section--deep h2 { color: var(--cream); }
/* Narrow text blocks centre on the page's axis. Left-floating them inside a centred
   1200px wrap left them anchored to nothing: not the margin, not the middle. */
.measure { max-width: 62ch; margin-inline: auto; }
/* 20ch was too narrow: headlines broke to four lines and read as a column, not a
   statement. 26ch holds most of them to two or three. */
.section h2 { max-width: 26ch; }
.section--deep h2 { max-width: 28ch; }
.closing h2 { max-width: none; }
/* Inside a centred measure block the heading centres with it rather than hugging
   the left edge of a column that is itself centred. */
.measure h2, .measure .eyebrow { max-width: none; }

/* Operator bar. Four facts, no adjectives. */
.bar { background: var(--forest); color: var(--cream); padding-block: 1.25rem; }
.bar__inner { display: flex; flex-wrap: wrap; gap: .5rem 2.5rem; justify-content: space-between;
  font-family: var(--mono); font-size: .6875rem; text-transform: uppercase; letter-spacing: .12em; }

/* Numbered steps */
.steps { list-style: none; margin: 3rem 0 0; padding: 0; display: grid; gap: 3rem; }
@media (min-width: 900px) { .steps { grid-template-columns: repeat(3, 1fr); gap: 3.5rem; } }
.steps li { border-top: 1px solid var(--stone); padding-top: 1.5rem; }
.steps__n { font-family: var(--mono); font-size: .6875rem; letter-spacing: .12em; color: var(--accent-text); display: block; margin-bottom: 1rem; }
.steps h3 { margin-bottom: .6rem; }
/* One heading wrapping to a second line dropped its paragraph below the neighbours. Reserve the
   second line for all of them, the same device used on .quotes figcaption. */
/* Headings in a three-column row must reserve the same height or the bodies beneath them drift
   apart. Two lines is enough on wide screens; between 900 and 1199 the columns narrow and the
   longest heading takes three. Reserved per band rather than guessing one value for both. */
@media (min-width: 900px)  { .steps h3 { min-height: 4.8em; } }   /* three lines at line-height 1.6 */
/* Reserving heading height is not enough for the practice cards, whose bodies also differ in
   length, so the trailing link still drifted up to 55px between 900 and 1100. Grid items stretch
   to equal height, so pushing the link to the foot of the card lands all three on one line at
   any width. */
.card { display: flex; flex-direction: column; }
.card__more { margin-top: auto; margin-bottom: 0; }
@media (min-width: 1200px) { .steps h3 { min-height: 3.2em; } }   /* two lines at line-height 1.6 */
.steps p { margin: 0; }
/* CTA under the steps grid. Left-aligned with the heading rather than centred, because this
   section is a left-aligned grid and not a band. */
.steps__cta { margin: 3rem 0 0; max-width: none; }

/* Practice cards */
.cards { display: grid; gap: 2.5rem; margin-top: 3rem; }

@media (min-width: 900px) { .cards { grid-template-columns: repeat(3, 1fr); } }
.card { border-top: 1px solid var(--stone); padding-top: 1.5rem; }
.card h3 { font-family: var(--serif); font-weight: 400; font-size: 1.375rem; line-height: 1.25; margin-bottom: .75rem; }
.card h3 a { text-decoration: none; }
.card h3 a:hover { text-decoration: underline; text-underline-offset: .2em; }
.card p { margin-bottom: .9em; }
.card__detail { color: var(--secondary); font-size: .9375rem; }
.card__more a { font-family: var(--mono); font-size: .75rem; letter-spacing: .06em; text-decoration: none; }
.card__more a:hover { text-decoration: underline; text-underline-offset: .3em; }

/* Proof band */
.proof { background: var(--forest); color: var(--cream); padding-block: var(--section); }
/* margin-bottom was 3.5rem, to clear the .proof__body paragraphs that used to sit under the
   rail. Those went with the testimonials on 2026-09-22 and the margin stayed, leaving the
   forest band 56px heavier at the bottom than the top at every width. It is only needed when
   something actually follows the rail. */
.proof__stats { list-style: none; margin: 0; padding: 0; display: grid; gap: 2rem; }
.proof__stats:has(+ *) { margin-bottom: 3.5rem; }
/* And if a figure ever does wrap to two lines, the labels stay on one baseline instead of one
   of them dropping below the other three. */
.proof__stats li { justify-content: flex-end; }
.proof__stats li { display: flex; flex-direction: column; gap: .5rem; }

/* THE FOUR LABELS SIT ON ONE BASELINE, whatever the figures are.
   Each figure used to own its own column box, so when one of them wrapped to two lines its
   label dropped below the other three: measured at 32px low at 768 and 46px at 1280 while the
   fourth figure read "$5M to $100M". Shortening that figure hid the symptom and left the
   fragility, because the next long figure would do it again.
   Instead the list becomes a two-row grid and the li stops being a box: `display: contents`
   promotes each figure and its label into the grid itself, so every figure sits in row one and
   every label in row two. A figure may now wrap to three lines and the labels still line up.
   Below 760 the rail is a single column and the li goes back to being a box, because there the
   figure and its label do belong together in reading order. */
@media (min-width: 760px) {
  .proof__stats {
    grid-template-columns: repeat(4, 1fr);
    grid-template-rows: auto auto;
    grid-auto-flow: column;
    row-gap: .5rem;
    column-gap: 2rem;
  }
  .proof__stats li { display: contents; }
}
.proof .stat { color: var(--cream); font-size: clamp(2rem, 3.6vw, 3rem); line-height: 1; }
.proof__label { font-family: var(--mono); font-size: .6875rem; text-transform: uppercase; letter-spacing: .12em; opacity: .92; }
/* .proof__body carries .measure, whose margin-inline:auto centred it inside a left-aligned
   section. The stat rail above starts at the wrap edge, so the two disagreed by 164px. */
.proof__body { margin-inline: 0; }
.proof__body p { color: var(--cream); opacity: .92; }

/* Portrait row */
.portrait-row { display: grid; gap: 2.5rem; align-items: start; }
@media (min-width: 900px) {
  .portrait-row { grid-template-columns: 5fr 7fr; gap: 4rem; }
  /* Optical alignment, not box alignment. The boxes already line up; the man does not,
     because the frame holds 8.8% of its height as cream above his crown. The frame is 4:5
     by aspect-ratio, so height = width x 1.25 and that 8.8% of height is 11% of width, which
     is what a percentage margin resolves against. Lifting by 11% puts his crown on the first
     line of text at every column width. If the portrait is ever recropped with different
     headroom, this number changes with it. */
  .portrait-row__img { margin-top: -11%; }
}

/* The bio page is the portrait's own page, so it carries the frame 10% larger than the
   homepage card does. 5.5fr of 12 is 462px against the homepage's 420px inside the same
   1008px of content. The lift above is a ratio, so it scales with this and the crown stays
   on the first line of text without a second number. */
@media (min-width: 900px) {
  .portrait-row--lg { grid-template-columns: 5.5fr 6.5fr; }
}
.portrait-row__img img { width: 100%; height: auto; display: block; filter: saturate(.92);
  aspect-ratio: 4 / 5; object-fit: cover; }
.portrait-row__body h2 { margin-bottom: .75rem; }

/* Negations. Trust stated as what we will not do. */
.negations { list-style: none; margin: 2.5rem 0 0; padding: 0; }
.negations li { border-top: 1px solid rgba(247,245,239,.22); padding: 1.1rem 0; max-width: none; }
.negations li:last-child { border-bottom: 1px solid rgba(247,245,239,.22); }

/* Client matters */
.quotes { display: grid; gap: 2.5rem; margin-top: 3rem; }
@media (min-width: 900px) { .quotes { grid-template-columns: repeat(3, 1fr); } }
/* Figures stretch to equal height in the grid but their content is top-aligned, so a shorter
   quote lifted its attribution 27px above the other two. Push the caption to the foot of the
   cell and all three sit on one line. */
.quotes figure { margin: 0; border-top: 1px solid var(--stone); padding-top: 1.5rem;
  display: flex; flex-direction: column; }
.quotes figcaption { margin-top: auto; }
.quotes blockquote { margin: 0 0 1rem; }
.quotes blockquote p { font-family: var(--serif); font-size: 1.125rem; line-height: 1.5; margin: 0; }
.quotes figcaption { font-family: var(--mono); font-size: .6875rem; text-transform: uppercase; letter-spacing: .1em; color: var(--secondary); }
.fineprint { font-family: var(--mono); font-size: .6875rem; line-height: 1.7; color: var(--secondary); margin-top: 2.5rem; max-width: 70ch; }

/* Offer band */
.band { background: var(--forest); color: var(--cream); padding-block: clamp(3.5rem, 8vw, 6rem); text-align: center; }
.band__line { font-family: var(--serif); font-style: normal; font-size: clamp(1.75rem, 4vw, 3rem); line-height: 1.2; margin: 0 auto 1rem; max-width: 20ch; }
.band__sub { font-family: var(--sans); font-size: 1.0625rem; line-height: 1.55;
  color: var(--cream); opacity: .86; max-width: 44ch; margin: 0 auto 2rem; }
/* The band's button sits in an unclassed <p>, so it inherits the 66ch reading measure from
   line 73. Without this the paragraph is a left-flush box and text-align:center centres the
   button inside that box rather than inside the section, landing it ~160px left of centre.
   Same fix as .closing p below. */
.band p { margin-inline: auto; }

/* FAQ. Native details, no JavaScript. */
.faq { margin-top: 2.5rem; }
.faq details { border-top: 1px solid var(--stone); }
.faq details:last-child { border-bottom: 1px solid var(--stone); }
.faq summary {
  cursor: pointer; list-style: none; padding: 1.25rem 2rem 1.25rem 0; position: relative;
  font-family: var(--sans); font-weight: 500; font-size: 1.0625rem;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ''; position: absolute; right: .35rem; top: 50%; width: .625rem; height: .625rem;
  border-right: 1px solid var(--forest); border-bottom: 1px solid var(--forest);
  transform: translateY(-70%) rotate(45deg); transition: transform 180ms ease;
}
.faq details[open] summary::after { transform: translateY(-30%) rotate(-135deg); }
.faq details > div { padding-bottom: 1.5rem; }
.faq details > div p { margin: 0; }

/* Closing */
.closing { text-align: center; }
.closing .measure { margin-inline: auto; }
.closing p { margin-inline: auto; }
.closing__actions { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: center; justify-content: center; margin-top: 2rem; }
.closing__actions { gap: 2rem; }
a[href^='tel:'] { white-space: nowrap; }
.closing__tel {
  font-family: var(--mono); font-size: .875rem; letter-spacing: .06em;
  text-decoration: none; color: var(--secondary); border-bottom: 1px solid var(--stone);
  padding-bottom: .25rem;
}
.closing__tel:hover { color: var(--forest); border-bottom-color: var(--olive); }

/* Footer */
.site-footer { background: var(--ink); color: var(--cream); padding-block: var(--section) 3rem; }
.site-footer__cols { display: grid; gap: 2.5rem; }
@media (min-width: 760px) { .site-footer__cols { grid-template-columns: 1.3fr 1fr 1fr 0.9fr 1.4fr; gap: 2.5rem; } }
.lockup__mark--footer { margin: 0 0 .75rem; }
.footer__tag { font-family: var(--mono); font-size: .6875rem; text-transform: uppercase; letter-spacing: .12em; line-height: 2; opacity: .75; }
.footer__office { display: block; font-family: var(--mono); font-size: .625rem;
  text-transform: uppercase; letter-spacing: .12em; color: var(--accent-text); margin-bottom: .3rem; }
.footer__h { font-family: var(--mono); font-size: .6875rem; text-transform: uppercase; letter-spacing: .12em; color: var(--accent-text); font-weight: 400; margin-bottom: 1rem; }
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li { margin-bottom: .6rem; }
.site-footer a { color: var(--cream); text-decoration: none; font-size: .9375rem; }
.site-footer a:hover { text-decoration: underline; text-underline-offset: .3em; }
.site-footer address { font-style: normal; font-size: .9375rem; line-height: 1.7; opacity: .85; }

/* The admissions rail. Set in mono at caption size so it reads as considered,
   not bolted on. It appears on every page of the site. */
.rail { margin-top: 4rem; padding-top: 2rem; border-top: 1px solid rgba(247,245,239,.18); }
/* 70% cream on forest composited to about 5.4:1. This is the Attorney Advertising notice and
   the Florida non-admission statement, which are the two blocks on the page a regulator reads.
   They are quiet by size and by face, not by being hard to see. */
.rail p { font-family: var(--mono); font-size: .6875rem; line-height: 1.9; opacity: .88; max-width: 92ch; }
.rail__links { display: flex; flex-wrap: wrap; gap: 1.25rem; opacity: .88; }
.rail__links a { font-family: var(--mono); font-size: .6875rem; }

/* Portrait. Chosen 2026-09-21. The frame's ground matches the portrait's own matted
   background, so the image has no visible edge against the page. Provenance:
   bella-law/website/portrait/README.md. */
.portrait-row__img { position: relative; background: var(--cream); }

/* Section rhythm. When two sections of the same ground colour stack, the second
   drops its top padding so the page does not open a gap taller than its content. */
.section + .section { padding-top: calc(var(--section) * 0.72); }
.section--pale + .section--pale,
.section + .section--deep { padding-top: var(--section); }
.closing { padding-block: clamp(4rem, 9vw, 7rem); }

/* ---------------------------------------------------------------------------
   Small screens. The header used to shed its button here, on the argument that the hero
   call to action sat directly beneath it. That argument only ever held on the homepage.
   Every interior page has no hero, so below 620px those pages carried no call to action in
   the chrome and, below 940px, no navigation either. The button now shrinks rather than
   disappearing, and the links move into a panel.
   --------------------------------------------------------------------------- */
@media (max-width: 620px) {
  .site-header { padding-block: 1.1rem; }
  .lockup__mark { font-size: 1.3125rem; }
  .lockup__line { font-size: .5625rem; letter-spacing: .14em; white-space: nowrap; }
  .hero { min-height: 100svh; }
  .hero__content { padding-block: 0 2.75rem; }
  .hero__note { font-size: .625rem; }
  .bar__inner { gap: .55rem; }
  .proof__stats { gap: 1.5rem; }
  .steps li, .card, .quotes figure { padding-top: 1.25rem; }
}

/* Between 620 and 860 the nav links are already hidden; keep the button but
   stop it breaking across two lines. */
@media (max-width: 860px) {
  .btn--sm { white-space: nowrap; padding: .55rem .9rem; font-size: .8125rem; }
}

/* Epigraph attribution under a quoted heading. Mono and quiet, same register as the hero
   citation, so the quote carries the weight and the source does not compete with it. The
   italic on the work's title is a citation convention, like the journal name in the hero. */
/* Epigraph under a declarative heading. The quote sits in the body face so it reads as a
   quotation rather than a caption; the source drops to mono and secondary so it does not
   compete with the heading above it. Replaces .attrib, which only this section used. */
.epigraph { margin: -0.25rem 0 2.25rem; padding-left: 1.25rem; border-left: 1px solid var(--stone); }
.epigraph p { margin: 0 0 .4rem; color: var(--secondary); max-width: 46ch; }
/* Was --secondary at 80% opacity, which composited to 3.83:1 on cream and failed the floor.
   The colour alone carries the recession now. */
.epigraph footer { font-family: var(--mono); font-size: .6875rem; letter-spacing: .04em;
  color: var(--secondary); }
.epigraph footer em { font-style: italic; }

/* Quote attributions sat on different baselines when one wrapped to a second
   line. Reserve the second line for all three so the row reads level. */
@media (min-width: 900px) {
  .quotes figcaption { min-height: 3.2em; }  /* two lines at line-height 1.6 */
}

/* Cap the frame so it does not outgrow the copy beside it and open a gap beneath.
   Written when the portrait was a placeholder; it still binds, because it is what
   held the bio page's larger frame at 420px until the line below was added. The bio
   page gets 462px, which is the 10% its 5.5fr column asks for. */
@media (min-width: 900px) {
  .portrait-row__img { max-width: 420px; }
  .portrait-row--lg .portrait-row__img { max-width: 462px; }
}

/* ---------------------------------------------------------------------------
   Interior pages. No full-bleed video, so the header sits on solid ground and
   the page opens on type rather than image.
   --------------------------------------------------------------------------- */
.site-header--solid { position: static; background: var(--forest); }
.site-header--solid::before { display: none; }
.site-header--solid .lockup, .site-header--solid .nav a { text-shadow: none; }
.site-header--solid .btn--sm { background: transparent; border-color: rgba(247,245,239,.45); backdrop-filter: none; }
.site-header--solid .btn--sm:hover { background: rgba(247,245,239,.12); }
.nav a[aria-current="page"] { border-bottom: 1px solid var(--olive); padding-bottom: .2rem; }

.page-hero { padding-block: clamp(3.5rem, 8vw, 6rem) clamp(2.5rem, 5vw, 4rem); }
.page-hero h1 {
  /* Roman sitewide from 2026-09-20. 16.9ch in roman is the width 18ch measured in italic,
     so the existing line breaks hold. */
  color: var(--forest); font-style: normal;
  font-size: clamp(2.25rem, 4.5vw, 3.5rem); max-width: 16.9ch;
}
.crumbs { font-family: var(--mono); font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--secondary); margin-bottom: 1.5rem; }
.crumbs a { color: var(--secondary); text-decoration: none; }
.crumbs a:hover { color: var(--forest); text-decoration: underline; text-underline-offset: .3em; }
.lede { font-size: 1.1875rem; line-height: 1.65; color: var(--ink); }

/* A paragraph that keeps the reading measure inside a full-width section. */
.measure-p { max-width: 62ch; }
.section h3 { margin-top: 2.25rem; font-family: var(--serif); font-weight: 400;
  font-size: 1.3125rem; color: var(--forest); }
.section--deep h3 { color: var(--cream); }

/* Data table. Answer engines read tables well, and a seller reads a range faster
   than a paragraph describing one. */
.table-wrap { overflow-x: auto; margin-top: 2.5rem; }
.data { width: 100%; border-collapse: collapse; font-size: .9375rem; min-width: 640px; }
.data caption { text-align: left; font-family: var(--mono); font-size: .6875rem;
  text-transform: uppercase; letter-spacing: .12em; color: var(--secondary); padding-bottom: 1rem; }
.data th, .data td { text-align: left; padding: 1rem 1.25rem 1rem 0; border-bottom: 1px solid var(--stone); vertical-align: top; }
.data thead th { font-family: var(--mono); font-size: .625rem; text-transform: uppercase;
  letter-spacing: .12em; color: var(--accent-text); font-weight: 400; border-bottom-color: var(--forest); }
/* nowrap used to be the default here, written for the subsector table whose first two columns
   are a short name and a multiple. Two later tables carry prose in those cells, and nowrap forced
   them to 1,134px and 1,334px inside a 1,072px column, so they scrolled sideways on a 1440 desktop.
   Wrapping is now the default and nowrap is opt-in via .data--figures. */
.data tbody th { font-weight: 500; padding-right: 2rem; }
.data td:nth-child(2) { font-family: var(--serif); font-size: 1.125rem; padding-right: 2rem; }
.data--figures tbody th, .data--figures td:nth-child(2) { white-space: nowrap; }

/* Definition list for the regulatory layer. */
.defs { margin-top: 2.5rem; }
.defs dl { margin: 0; display: grid; gap: 0; }
@media (min-width: 900px) { .defs dl { grid-template-columns: 22rem 1fr; } }
.defs dt { font-weight: 500; border-top: 1px solid var(--stone); padding: 1.25rem 2rem 1.25rem 0; }
.defs dd { margin: 0; border-top: 1px solid var(--stone); padding: 1.25rem 0; color: var(--secondary); }
@media (max-width: 899px) {
  .defs dd { border-top: 0; padding-top: 0; padding-bottom: 1.5rem; }
}

/* Phases */
.phases { list-style: none; margin: 3rem 0 0; padding: 0; display: grid; gap: 0; }
.phases li { display: grid; gap: 1rem; border-top: 1px solid var(--stone); padding: 1.75rem 0; }
@media (min-width: 760px) { .phases li { grid-template-columns: 5rem 1fr; gap: 2rem; } }
.phases li:last-child { border-bottom: 1px solid var(--stone); }
.phases__n { font-family: var(--mono); font-size: .6875rem; letter-spacing: .12em; color: var(--accent-text); }
.phases h3 { margin: 0 0 .35rem; }
.phases__t { font-family: var(--mono); font-size: .6875rem; text-transform: uppercase;
  letter-spacing: .1em; color: var(--secondary); margin-bottom: .9rem; }
.phases p:last-child { margin-bottom: 0; }

/* Matters */
.matters { margin-top: 2.5rem; }
.matters article { border-top: 1px solid rgba(247,245,239,.22); padding: 1.5rem 0; }
.matters article:last-of-type { border-bottom: 1px solid rgba(247,245,239,.22); }
.matters h3 { margin: 0 0 .6rem; font-size: 1.1875rem; }
.matters p { margin: 0; opacity: .92; }
.fineprint--light { color: var(--cream); opacity: .85; }

/* The paragraph following a table needs air; the table's last border reads as a
   rule and the text was sitting on it. Playfair renders lowercase x as a small
   cap, so multiples are set in the sans where 8x reads as 8x. */
.table-wrap + .measure-p { margin-top: 2rem; }
.data td:nth-child(2) { font-family: var(--sans); font-size: 1rem; font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------------------
   The real logo, and a header that stays.
   --------------------------------------------------------------------------- */

/* The logo is inlined rather than referenced. An external SVG in an <img> is
   blocked by Chrome over file:// (the same CORS rule that blocks the fonts), it
   costs a request, and it cannot be recoloured by CSS. Inline solves all three.
   The two-tone survives via custom properties, so one piece of markup serves a
   cream ground and a forest one. */
:root { --logo-word: #124f3a; --logo-sub: #66916d; --logo-accent: #7c993d; }
.site-header, .site-footer, .section--deep, .proof, .band, .nav, .connect {
  --logo-word: var(--cream); --logo-sub: var(--cream); --logo-accent: #9BC24A;
  --accent-text: var(--olive-lift);
}
.logo { display: block; height: 100%; width: auto; }
.lockup__img { display: block; height: 59px; }
.footer__logo { display: block; height: 44px; margin-bottom: .9rem; }
@media (max-width: 620px) { .lockup__img { height: 48px; } }

/* Sticky header. Transparent over the hero so the film owns the viewport, then
   solid forest once the page scrolls, so the wordmark and nav never sit on an
   unpredictable frame of video. `position: fixed` rather than `sticky` because
   the header starts overlapping the hero rather than preceding it in flow. */
.site-header {
  position: fixed; inset: 0 0 auto; z-index: 50;
  transition: background-color 320ms ease, padding 320ms ease, box-shadow 320ms ease;
}
.site-header--solid { position: fixed; background: var(--forest); }

.site-header.is-stuck {
  background: var(--forest);
  padding-block: .85rem;
  box-shadow: 0 1px 0 rgba(247,245,239,.12), 0 8px 30px rgba(16,26,20,.18);
}
/* The scrim exists only to lift the header off the video. Once the header has a
   ground of its own it is redundant and would darken the bar. */
.site-header.is-stuck::before { opacity: 0; }
.site-header::before { transition: opacity 320ms ease; }
.site-header.is-stuck .lockup, .site-header.is-stuck .nav a { text-shadow: none; }
.site-header.is-stuck .lockup__img { height: 48px; }
.site-header.is-stuck .btn--sm { background: transparent; backdrop-filter: none; }

/* Interior pages have no hero, so their header is solid from the first pixel and
   the page must start below it rather than underneath it. */
.site-header--solid { padding-block: 1.1rem; }
body:has(.site-header--solid) { padding-top: 84px; }
@media (max-width: 620px) { body:has(.site-header--solid) { padding-top: 70px; } }

#top-sentinel { position: absolute; top: 0; height: 1px; width: 1px; }

@media (prefers-reduced-motion: reduce) { .site-header { transition: none; } }

/* ---------------------------------------------------------------------------
   Every rule on the site draws itself from left to right as it enters view.

   Three things were wrong in the first pass and each had its own cause.

   TOO FAST: 1000ms sounds slow, but the easing was cubic-bezier(.22,.61,.36,1),
   a hard ease-out that spends most of its travel in the first fifth of the
   duration. Now 1500ms on a gentler curve that keeps moving through the middle.

   STARTED TOO SOON: the line sits at the TOP of its element, but the observer
   fired at 15% of the element's height. On a tall card the line had been on
   screen for a while before it drew. Now threshold 0 with a -22% bottom margin,
   so a line draws as it crosses into the lower-middle of the viewport.

   BARELY VISIBLE: --stone (#D8E3D9) on cream is almost no contrast. The line now
   DRAWS in olive, which you can see, then settles to the quiet rule colour once
   it has arrived. The motion is legible and the resting state stays calm.
   --------------------------------------------------------------------------- */

:root {
  --line-rest: #C4D2C6;            /* the quiet state, a step darker than --stone */
  --line-draw: var(--olive);       /* the visible state, while it is drawing */
  --line-rest-dark: rgba(247,245,239,.30);
  --line-ease: cubic-bezier(.42,.02,.24,1);
  --line-time: 1500ms;
}

.card, .steps li, .quotes figure, .phases li, .negations li,
.faq details, .matters article, .defs dt, .defs dd {
  position: relative;
  border-top-color: transparent !important;
}
.card::before, .steps li::before, .quotes figure::before, .phases li::before,
.negations li::before, .faq details::before, .matters article::before,
.defs dt::before, .defs dd::before {
  content: ''; position: absolute; top: -1px; left: 0; right: 0; height: 1px;
  background: var(--line-draw);
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--line-time) var(--line-ease),
              background-color 900ms ease var(--line-time);
}
.card.is-in::before, .steps li.is-in::before, .quotes figure.is-in::before,
.phases li.is-in::before, .negations li.is-in::before, .faq details.is-in::before,
.matters article.is-in::before, .defs dt.is-in::before, .defs dd.is-in::before {
  transform: scaleX(1);
  background: var(--line-rest);
}
.section--deep .negations li.is-in::before,
.matters article.is-in::before { background: var(--line-rest-dark); }

/* Closing rule on the last item of a stacked list, a beat behind its sibling. */
.negations li:last-child, .faq details:last-child,
.matters article:last-of-type, .phases li:last-child {
  border-bottom-color: transparent !important;
}
.negations li:last-child::after, .faq details:last-child::after,
.matters article:last-of-type::after, .phases li:last-child::after {
  content: ''; position: absolute; bottom: -1px; left: 0; right: 0; height: 1px;
  background: var(--line-draw);
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--line-time) var(--line-ease) 200ms,
              background-color 900ms ease calc(var(--line-time) + 200ms);
}
.negations li.is-in:last-child::after, .faq details.is-in:last-child::after,
.matters article.is-in:last-of-type::after, .phases li.is-in:last-child::after {
  transform: scaleX(1); background: var(--line-rest);
}
.section--deep .negations li.is-in:last-child::after,
.matters article.is-in:last-of-type::after { background: var(--line-rest-dark); }

/* Row stagger, widened so three cards read as three strokes rather than one. */
.cards .card:nth-child(2)::before, .steps li:nth-child(2)::before,
.quotes figure:nth-child(2)::before { transition-delay: 0ms, var(--line-time); }
.cards .card:nth-child(2).is-in::before, .steps li:nth-child(2).is-in::before,
.quotes figure:nth-child(2).is-in::before { transition-delay: 180ms, calc(var(--line-time) + 180ms); }
.cards .card:nth-child(3).is-in::before, .steps li:nth-child(3).is-in::before,
.quotes figure:nth-child(3).is-in::before { transition-delay: 360ms, calc(var(--line-time) + 360ms); }

/* The table's rules draw the same way, each row a beat after the one above. */
.data tbody tr { position: relative; }
.data th, .data td { border-bottom-color: transparent !important; }
.data tbody tr::after {
  content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 1px;
  background: var(--line-draw); transform: scaleX(0); transform-origin: left center;
  transition: transform var(--line-time) var(--line-ease),
              background-color 900ms ease var(--line-time);
}
.data tbody tr.is-in::after { transform: scaleX(1); background: var(--line-rest); }
.data tbody tr:nth-child(2).is-in::after { transition-delay: 120ms, calc(var(--line-time) + 120ms); }
.data tbody tr:nth-child(3).is-in::after { transition-delay: 240ms, calc(var(--line-time) + 240ms); }
.data tbody tr:nth-child(4).is-in::after { transition-delay: 360ms, calc(var(--line-time) + 360ms); }
.data tbody tr:nth-child(5).is-in::after { transition-delay: 480ms, calc(var(--line-time) + 480ms); }
.data thead th { border-bottom-color: var(--forest) !important; }

/* Standalone hairlines: same timing, same olive-then-settle. */
.rule {
  background: var(--line-draw);
  transition: width var(--line-time) var(--line-ease),
              background-color 900ms ease var(--line-time);
}
.rule.is-in { background: var(--olive); }

@media (prefers-reduced-motion: reduce) {
  .card::before, .steps li::before, .quotes figure::before, .phases li::before,
  .negations li::before, .faq details::before, .matters article::before,
  .defs dt::before, .defs dd::before, .data tbody tr::after,
  .negations li:last-child::after, .faq details:last-child::after,
  .matters article:last-of-type::after, .phases li:last-child::after {
    transform: scaleX(1); background: var(--line-rest); transition: none;
  }
  .rule { width: 100%; background: var(--olive); transition: none; }
}

/* ---------------------------------------------------------------------------
   The enquiry form.

   Two steps only when JavaScript runs. Without it both fieldsets show and the
   single Send button submits everything, so the form works for every visitor
   and passes the no-JS gate. Multi-step converts 14% better at equal field
   count, which is worth having but not at the price of an unusable form.
   --------------------------------------------------------------------------- */

.form-layout { display: grid; gap: 3rem; }
@media (min-width: 940px) { .form-layout { grid-template-columns: 1.55fr 1fr; gap: 5rem; } }

.enquiry { max-width: 34rem; }
.enquiry fieldset { border: 0; margin: 0; padding: 0; }
.enquiry legend {
  font-family: var(--serif); font-size: 1.5rem; color: var(--forest);
  margin-bottom: 2rem; padding: 0; display: block;
}
.step__n {
  display: block; font-family: var(--mono); font-size: .625rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--accent-text); margin-bottom: .6rem;
}

.field { margin-bottom: 1.75rem; }
.field__label {
  display: block; font-family: var(--mono); font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--secondary); margin-bottom: .7rem;
}
.field__opt { text-transform: none; letter-spacing: .02em; opacity: .7; }
/* The form marks its OPTIONAL fields, so everything unmarked is required. That convention
   breaks on a checkbox: a required consent box sitting next to an optional newsletter box
   looks identical, and the reader only learns the difference when the browser refuses to
   submit. Both are now labelled. */
.field__req {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent-text); margin-right: .5rem;
}
.field--check .field__opt { font-family: var(--mono); font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; margin-right: .5rem; }
.field__help { font-size: .875rem; color: var(--secondary); margin: .6rem 0 0; }

.enquiry input[type="text"], .enquiry input[type="email"], .enquiry input[type="tel"],
.enquiry select, .enquiry textarea {
  width: 100%; font: inherit; color: var(--ink);
  background: transparent; border: 0; border-bottom: 1px solid var(--stone);
  padding: .65rem 0; border-radius: 0;
  transition: border-color 200ms ease;
}
.enquiry textarea { resize: vertical; }
.enquiry select { appearance: none; background-image:
  linear-gradient(45deg, transparent 50%, var(--forest) 50%),
  linear-gradient(135deg, var(--forest) 50%, transparent 50%);
  background-position: calc(100% - 14px) calc(1.1em), calc(100% - 9px) calc(1.1em);
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; padding-right: 2rem; }
.enquiry input:focus, .enquiry select:focus, .enquiry textarea:focus {
  outline: none; border-bottom-color: var(--olive); border-bottom-width: 2px; padding-bottom: calc(.65rem - 1px);
}

/* Radio group. The whole row is the target, not a four-pixel circle. */
.choices { display: grid; gap: 0; }
.choices label {
  display: flex; align-items: flex-start; gap: .85rem; cursor: pointer;
  padding: .85rem 0; border-bottom: 1px solid var(--stone);
}
.choices label:first-child { border-top: 1px solid var(--stone); }
.choices input { accent-color: var(--forest); margin-top: .25rem; flex: none; }
.choices label:hover span { color: var(--forest); }

.field--check label { display: flex; align-items: flex-start; gap: .85rem; cursor: pointer; font-size: .9375rem; }
.field--check input { accent-color: var(--forest); margin-top: .3rem; flex: none; }

.step__next, .step__submit { margin: 2.25rem 0 0; }
.form__note {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .06em;
  color: var(--secondary); margin-top: 1.25rem;
}

/* Honeypot: off-screen, never focusable, invisible to assistive tech. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Errors appear only after the visitor has tried to continue. */
.enquiry .show-errors :invalid, .show-errors .choices:has(:invalid) { border-bottom-color: var(--ochre); }

/* Without JavaScript the "Continue" button has nothing to do, so it is hidden and
   both steps stand as one form. */
.enquiry:not(.is-stepped) .step__next { display: none; }
.enquiry:not(.is-stepped) .step[data-step="2"] { margin-top: 3.5rem; }

/* Aside */
.form-aside { padding-top: .5rem; }
.aside__tel { font-family: var(--serif); font-size: clamp(1.75rem, 3vw, 2.25rem); margin: 0 0 .5rem; }
.aside__tel a { text-decoration: none; }
.aside__tel a:hover { text-decoration: underline; text-underline-offset: .18em; }
.aside__small { font-size: .9375rem; color: var(--secondary); }
.aside__h { font-family: var(--mono); font-size: .6875rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--accent-text); margin: 0 0 1.1rem; }
.aside__addr { font-style: normal; font-size: .9375rem; line-height: 1.7; color: var(--secondary); margin-bottom: 1.5rem; }
.aside__addr strong { color: var(--ink); font-weight: 500; }
.form-aside .rule { margin: 1.75rem 0; }

/* ---------------------------------------------------------------------------
   THE NAVIGATION PANEL. Added 2026-09-21.

   WHAT WAS WRONG. Two rules in this file hid the navigation on small screens and
   put nothing in their place: `.nav a:not(.btn) { display: none }` below 940px,
   and `.site-header .btn--sm { display: none }` below 620px. Measured at 390,
   768 and 940, the header contained the wordmark and nothing else. A visitor on
   a phone could not reach a practice page, a bio, or the contact page from the
   chrome of any page on the site. About 60% of enquiries in this category arrive
   on a handset, so this was the site's worst defect and it was invisible in every
   desktop review.

   WHY IT IS A CHECKBOX. Every word and every link on this site must work with
   JavaScript disabled; the no-JS parity gate in scripts/site-check.mjs enforces
   it for content and the navigation is not an exception. `:checked` costs nothing
   and cannot break. The input stays focusable while clipped, so the panel opens
   from the keyboard with no script at all.

   MOTION follows the durations from the 2026-09-21 craft research: 280ms for a
   standard transition, ease-out on entry. `visibility` is delayed on close so the
   links are untabbable when the panel is shut and the fade still runs.
   --------------------------------------------------------------------------- */

/* Desktop is the row that was always there. The toggle, its label, and the
   panel-only links do not exist above the breakpoint. */
.navtoggle, .navbtn { display: none; }
.nav__tel { display: none; }

/* THE DROPDOWNS, WITH NO SCRIPT.
   `.nav__more { display: none }` used to sit on the line above and hid About and Contact at
   every desktop viewport, so the homepage header offered no route to the About page at all.
   Babak found it 2026-09-24. The class is gone and those links are in the row now.

   Open on hover and on focus-within, so a mouse and a keyboard both work and neither needs
   JavaScript. The panel has no vertical gap under its parent: a gap is a dead zone the pointer
   crosses, and the panel would close under the cursor on the way down. Padding inside the panel
   does the visual spacing instead. */
.nav__group { position: relative; }
.nav__label { display: none; }
.nav__top::after {
  content: ''; display: inline-block; width: .32em; height: .32em; margin-left: .45em;
  border-right: 1px solid currentColor; border-bottom: 1px solid currentColor;
  transform: translateY(-.15em) rotate(45deg); opacity: .7;
}
.nav__panel {
  position: absolute; top: 100%; left: -1.25rem; z-index: 70;
  display: flex; flex-direction: column; gap: .85rem;
  min-width: 15rem; padding: 1.1rem 1.25rem 1.2rem;
  background: var(--forest); border-top: 2px solid var(--olive);
  box-shadow: 0 14px 34px rgba(16,26,20,.28);
  opacity: 0; visibility: hidden; transform: translateY(-.4rem);
  transition: opacity 180ms ease-out, transform 180ms ease-out, visibility 0s linear 180ms;
}
.nav__group:hover .nav__panel,
.nav__group:focus-within .nav__panel {
  opacity: 1; visibility: visible; transform: none;
  transition: opacity 180ms ease-out, transform 180ms ease-out, visibility 0s;
}
.nav__panel a { text-shadow: none; white-space: nowrap; }
@media (prefers-reduced-motion: reduce) {
  .nav__panel { transition: opacity 1ms linear, visibility 0s linear 1ms; transform: none; }
  .nav__group:hover .nav__panel,
  .nav__group:focus-within .nav__panel { transition: opacity 1ms linear, visibility 0s; }
}

/* Clipped but focusable. Not `display:none` and not `hidden`, either of which
   would take it out of the tab order and lose keyboard operation. */
.navtoggle {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.navbtn__bars { display: block; width: 22px; height: 12px; position: relative; }
.navbtn__bars i {
  position: absolute; left: 0; width: 100%; height: 1.5px; background: currentColor;
  transition: transform 280ms cubic-bezier(.2,.7,.3,1), opacity 160ms ease;
}
.navbtn__bars i:nth-child(1) { top: 0; }
.navbtn__bars i:nth-child(2) { top: 5.25px; }
.navbtn__bars i:nth-child(3) { top: 10.5px; }
.navbtn__txt--close { display: none; }

@media (max-width: 1180px) {
  /* 1180, not 940, and not the 1100 it was earlier tonight. The three service areas are
     spelled out rather than ampersanded, because the same area was otherwise called
     "Acquisition & Exit" in the nav and "Acquisition and Exit" in the footer and the hero
     eyebrow. One canonical name won; the row got longer; the breakpoint moved to fit it.
     Verified by measurement at 1180 and 1181, not by estimate. */

  .navbtn {
    display: inline-flex; align-items: center; gap: .6rem;
    position: relative; z-index: 60; cursor: pointer;
    color: var(--cream); font-family: var(--mono); font-size: .6875rem;
    text-transform: uppercase; letter-spacing: .12em;
    /* A 44px tap target, per the usual minimum, without a visible box. */
    padding: .9rem 0; margin: -0.9rem 0;
  }
  .navtoggle:focus-visible + .navbtn { outline: 2px solid var(--olive-lift); outline-offset: 5px; }

  .nav {
    position: fixed; inset: 0; z-index: 55;
    /* flex-start, not center. Centred, the list floated in the middle of a tall
       phone viewport with a void above and below it and read as an overlay rather
       than as the site's navigation. */
    flex-direction: column; align-items: stretch; justify-content: flex-start;
    gap: 0; padding: 6.5rem var(--gutter) 3rem;
    background: var(--forest);
    overflow-y: auto; overscroll-behavior: contain;
    visibility: hidden; opacity: 0; transform: translateY(-0.75rem);
    transition: opacity 280ms cubic-bezier(.2,.7,.3,1),
                transform 280ms cubic-bezier(.2,.7,.3,1),
                visibility 0s linear 280ms;
  }
  .navtoggle:checked ~ .nav {
    visibility: visible; opacity: 1; transform: none;
    transition: opacity 280ms cubic-bezier(.2,.7,.3,1),
                transform 280ms cubic-bezier(.2,.7,.3,1),
                visibility 0s;
  }

  /* The links carry the display face in the panel. It is the one place on the site
     where navigation is the content, so it is set like content. */
  .nav a {
    font-family: var(--serif); font-style: normal;
    font-size: clamp(1.375rem, 5.2vw, 1.875rem); line-height: 1.3;
    padding: .7rem 0; text-shadow: none;
    border-bottom: 1px solid rgba(247,245,239,.14);
  }
  .nav a:not(.btn):hover { text-decoration: none; color: var(--accent-text); }
  .nav__tel { display: block; }

  /* THE GROUPS DISSOLVE HERE.
     `display: contents` drops the group wrappers and their panels out of the box tree, so every
     link lands back in the flat checkbox panel in source order and the phone navigation behaves
     exactly as it did before the dropdowns existed. The same technique the proof rail already
     uses to put figures and labels on one baseline.

     The parent link is hidden and a small mono label takes its place, because "Services" and
     "About" are useful as group headings on a phone and useless as extra tap targets: About
     pointed at the same page as its own first child. */
  .nav__group, .nav__panel { display: contents; }
  .nav__top { display: none; }
  .nav__label {
    display: block; font-family: var(--mono); font-size: .6875rem;
    letter-spacing: .12em; text-transform: uppercase; color: var(--olive-lift);
    margin: 1.6rem 0 .3rem; opacity: .9;
  }
  /* `:first-of-type` used to carry the top border. With links now nested inside groups it
     matched the first link of a panel instead of the first link in the nav, so the rule moved
     to the first label, which is what the eye reaches first. */
  .nav .nav__label:first-of-type { margin-top: 0; }
  /* `.nav a` is 0,1,1 and `.nav__tel` alone is 0,1,0, so the panel's border-bottom
     won on specificity and the phone number kept a rule under it. Qualified. */
  .nav a.nav__tel {
    font-family: var(--mono); font-size: .9375rem; letter-spacing: .06em;
    border-bottom: 0; margin-top: 1.75rem; padding: 0; opacity: .82;
  }

  /* The wordmark stays above the open panel. Without this the panel covered it and
     the header read as a lone X floating on a green field, with nothing to say which
     site you were on. The toggle deliberately does not move when it is pressed. */
  .lockup { position: relative; z-index: 58; }

  /* Open state: the bars become a cross and the word changes. */
  .navtoggle:checked + .navbtn .navbtn__bars i:nth-child(1) { transform: translateY(5.25px) rotate(45deg); }
  .navtoggle:checked + .navbtn .navbtn__bars i:nth-child(2) { opacity: 0; }
  .navtoggle:checked + .navbtn .navbtn__bars i:nth-child(3) { transform: translateY(-5.25px) rotate(-45deg); }
  .navtoggle:checked + .navbtn .navbtn__txt { display: none; }
  .navtoggle:checked + .navbtn .navbtn__txt--close { display: inline; }

  /* The one call to action steps aside while the panel is open, because the panel
     carries Contact of its own and two routes to the same page is one too many. */
  .navtoggle:checked ~ .header__cta { opacity: 0; pointer-events: none; }
  .header__cta { transition: opacity 200ms ease; }

  /* No scrolling the page behind an open panel. */
  body:has(.navtoggle:checked) { overflow: hidden; }

  /* The header orders itself: wordmark, then the action, then the toggle. */
  .site-header__inner { gap: 1rem; }
  .lockup { margin-right: auto; }
}

@media (max-width: 620px) {
  /* At 390 the wordmark, the button and a labelled toggle will not all fit, and the
     button is the one that must survive. The toggle keeps its bars and loses its
     word; `title` and the input's aria-label carry the name for anyone who needs it. */
  .navbtn__txt, .navbtn__txt--close { display: none; }
  .navtoggle:checked + .navbtn .navbtn__txt--close { display: none; }
  .lockup__img { height: 38px; }
  .site-header.is-stuck .lockup__img { height: 36px; }
  .header__cta { padding: .5rem .8rem; font-size: .75rem; }
  .nav { padding-top: 5.5rem; }
}

/* Reduced motion: the panel appears and disappears, it does not travel. */
@media (prefers-reduced-motion: reduce) {
  .nav, .navbtn__bars i, .header__cta { transition: none; }
  .navtoggle:checked ~ .nav { transform: none; }
}

/* ---------------------------------------------------------------------------
   TAP TARGETS. Measured 2026-09-21 at 390 and 768 with
   bella-law/website/tools/visual-check.mjs. Five controls were under the 44px
   minimum, and the menu toggle was the worst of them at 22px wide, which is the
   one control on a phone that has to be hit first time.

   Every fix below adds hit area without moving a pixel of what is drawn: either
   padding cancelled by a negative margin, or a pseudo-element that extends the
   target past the ink.
   --------------------------------------------------------------------------- */

@media (max-width: 860px) {
  /* The toggle. 22x41 measured; the bars stay 22px wide and the box grows. */
  .navbtn { min-width: 44px; min-height: 44px; justify-content: flex-end; }

  /* The header action. 144x37 measured. */
  .header__cta { min-height: 44px; display: inline-flex; align-items: center; }

  /* The wordmark. 136x38 measured. Padding, then a negative margin so the bar
     keeps its height and the logo keeps its position. */
  .lockup { padding-block: .4rem; margin-block: -0.4rem; }

  /* A heading that is entirely a link is a control, not prose. 28px measured. */
  .card h3 a, .matters h3 a { display: inline-block; padding-block: .6rem; margin-block: -0.6rem; }

  /* The phone number in the footer address block. 95x20 measured. */
  .site-footer address a, .rail__links a, .card__more a {
    display: inline-block; padding-block: .6rem; margin-block: -0.6rem;
  }
}

/* Two more controls under 44px, found 2026-09-21 on the pages built that night. Same pattern
   as the block above: hit area grows, nothing drawn moves.
   .defs dt a  the HTML sitemap sets page titles as definition terms, nine links at 22px.
   .crumbs a   the breadcrumb "Home" link, 32x14, on every interior page since the contact
               page shipped. Pre-existing and missed by every review because nobody taps a
               breadcrumb on a desktop. */
@media (max-width: 860px) {
  .defs dt a, .crumbs a { display: inline-block; padding-block: .85rem; margin-block: -0.85rem; }
}

/* The hero eyebrow lists the three service areas separated by middots. At 390 the line broke
   inside a name ("ACQUISITION AND EXIT · DIGITAL / HEALTH AND AI · STARTUPS AND FOUNDERS"),
   which reads as a typographic accident rather than a list. Each name is wrapped in a span and
   held together, so the line can only break at a separator. */
.eyebrow span { white-space: nowrap; }

/* ---------------------------------------------------------------------------
   TABLES ON A PHONE. Fixed 2026-09-22.

   `.data { min-width: 640px }` inside `.table-wrap { overflow-x: auto }` meant
   that at 390 the third column of every comparison table sat outside the
   viewport with no visible affordance that anything was there. On the Startups
   and Founders page the hidden column is headed "Clinician opening a practice",
   which is one of the two audiences that page was written for: half its readers
   never saw their own column, on the device most of them arrive with.

   A horizontal scroll that announces itself would have been the cheap fix. This
   is the honest one: below 760 the minimum width comes off, the type steps down,
   the horizontal padding goes, and the cells wrap. Three narrow columns of
   wrapped text is less handsome than three wide ones. Nothing is hidden.
   --------------------------------------------------------------------------- */
@media (max-width: 759px) {
  .data { min-width: 0; font-size: .8125rem; }
  .data th, .data td { padding: .75rem .5rem .75rem 0; hyphens: manual; word-break: normal;
                       overflow-wrap: break-word; }
  .data th:first-child, .data td:first-child { width: 24%; }
  .data th:last-child, .data td:last-child { padding-right: 0; }
  .data thead th { font-size: .5625rem; letter-spacing: .08em; }
  /* The second column carries a multiple or a short figure on one table and prose on
     two others. At this width it is prose everywhere, so it goes back to the body size. */
  .data td:nth-child(2) { font-size: .8125rem; }
  .table-wrap { overflow-x: visible; }
}

/* ---------------------------------------------------------------------------
   LINKS ON THE DARK GROUNDS. Added 2026-09-22, and it was a latent bug rather
   than a regression.

   The base rule is `a { color: var(--forest) }`. Every dark section on this site
   paints `background: var(--forest)`. So any body link inside one rendered
   forest on forest and was invisible: measured at 1.00:1, which is not a
   contrast failure so much as an absence. It had never fired because until today
   no dark section carried a body link. The moment one did, on the matters
   section of the Acquisition page, a link to the attorney's bio disappeared.

   Buttons are excluded because they carry their own colours.
   --------------------------------------------------------------------------- */
.section--deep a:not(.btn),
.band a:not(.btn),
.connect a:not(.btn),
.proof a:not(.btn) {
  color: var(--cream);
  text-decoration-color: var(--olive-lift);
  text-underline-offset: 0.2em;
}
.section--deep a:not(.btn):hover,
.band a:not(.btn):hover,
.connect a:not(.btn):hover,
.proof a:not(.btn):hover { color: var(--olive-lift); }

/* ---------------------------------------------------------------------------
   THE CONNECT BAND. Added 2026-09-22 on Babak's instruction, after watching the
   live bellalawpllc.com animations frame by frame.

   Two things come across from the old site and nothing else does.

   1. THE MONOGRAM. The old site split the BellaLaw mark into two SVGs, l.svg and
      b.svg, and flew them in from opposite edges so they lock together. It is
      the one genuinely good piece of motion on that site. What does NOT come
      across is its execution: 1000ms linear, travelling a full 100% of the
      viewport, which is the "flies in from off-screen" pattern the 2026-09-21
      craft research names as reading like 2018. Here it travels 38% on a 560ms
      ease-out, which is the page-level duration the same research recommends,
      and the B is delayed 90ms behind the L so they arrive rather than collide.

   2. THE FORM, INLINE. The old site put a real form at the foot of the page
      instead of a link to a contact page. That removes a navigation step from
      the one action the site is built around, and the whole page can now be
      acted on from where the reader finishes reading.

   What is deliberately left behind: the Google Maps embed (this site makes zero
   third-party requests), the "24/7 website chatbot" line (there is no chatbot),
   "automated onboarding" (there is none), and a required phone field, which is
   the highest-friction field on any form.
   --------------------------------------------------------------------------- */

.connect { background: var(--forest); color: var(--cream); padding-block: var(--section); }
.connect__inner { display: grid; gap: 3.5rem; }
@media (min-width: 900px) {
  .connect__inner { grid-template-columns: 1fr 1fr; gap: 5rem; align-items: start; }
}
.connect h2 { color: var(--cream); margin-bottom: .6rem; }
.connect__lede { max-width: 42ch; }

/* The mark. Both halves share one box; the L's artboard is five units taller,
   which is what makes the foot of the L sit below the bowl of the B. */
.monogram {
  position: relative; display: block;
  width: clamp(132px, 17vw, 190px); aspect-ratio: 379 / 451;
  margin: 0 0 2.5rem;
}
.monogram svg { position: absolute; top: 0; left: 0; width: 100%; height: auto; display: block; }
.monogram path { fill: currentColor; }
.monogram__l { color: var(--olive-lift); transform: translateX(-38%); opacity: 0; }
.monogram__b { color: var(--cream);     transform: translateX(38%);  opacity: 0; }
.monogram svg { transition: transform 560ms cubic-bezier(.16,.84,.44,1), opacity 420ms ease-out; }
.monogram.is-in .monogram__l,
.monogram.is-in .monogram__b { transform: none; opacity: 1; }
.monogram.is-in .monogram__b { transition-delay: 90ms; }

.connect__facts { margin: 2.25rem 0 0; }
.connect__facts dt {
  font-family: var(--mono); font-size: .6875rem; text-transform: uppercase;
  letter-spacing: .12em; color: var(--accent-text); margin-top: 1.4rem;
}
.connect__facts dt:first-child { margin-top: 0; }
.connect__facts dd { margin: .4rem 0 0; max-width: 44ch; }
.connect__reach { margin-top: 2.25rem; font-size: 1.0625rem; line-height: 2; }
/* Both offices, in full, at the foot of every page that carries the band. The Florida office
   is titled the Miami office, which is how the firm refers to it and how a Coral Gables address
   is normally presented; the postal address stays Coral Gables, because that is where the mail
   goes. Set in <address> rather than <p> so the register gate does not measure a street address
   as prose. */
.connect__offices { display: grid; gap: 1.5rem; margin-top: 2rem; }
@media (min-width: 560px) { .connect__offices { grid-template-columns: 1fr 1fr; gap: 1.75rem; } }
.connect__offices address { font-style: normal; font-size: .9375rem; line-height: 1.65; opacity: .92; }
.connect__offices address span {
  display: block; font-family: var(--mono); font-size: .6875rem; text-transform: uppercase;
  letter-spacing: .12em; color: var(--accent-text); opacity: 1; margin-bottom: .45rem;
}

/* The card. A lift off the forest rather than a second colour, so the band
   stays one material. */
.connect__form {
  background: rgba(247,245,239,.055);
  border: 1px solid rgba(247,245,239,.13);
  padding: clamp(1.5rem, 3.2vw, 2.5rem);
  opacity: 0; transform: translateY(14px);
  transition: opacity 520ms ease-out, transform 520ms cubic-bezier(.16,.84,.44,1);
}
.connect__form.is-in { opacity: 1; transform: none; }
.connect__form h3 { color: var(--cream); font-size: clamp(1.375rem, 2.2vw, 1.75rem); margin-bottom: .5rem; }
.connect__form > p { opacity: .92; margin-bottom: 2rem; max-width: 46ch; }

/* The form controls, inverted for the dark ground. */
.connect .enquiry { max-width: none; }
.connect .field__label { color: var(--accent-text); }
.connect .field__opt { opacity: 1; color: var(--cream); }
.connect .field__help { color: var(--cream); opacity: .72; }
.connect .enquiry input[type="text"], .connect .enquiry input[type="email"],
.connect .enquiry input[type="tel"], .connect .enquiry textarea {
  color: var(--cream); border-bottom-color: rgba(247,245,239,.32);
}
.connect .enquiry input:focus, .connect .enquiry textarea:focus {
  border-bottom-color: var(--olive-lift);
}
.connect .enquiry input::placeholder, .connect .enquiry textarea::placeholder { color: rgba(247,245,239,.45); }
.connect .field--check input { accent-color: var(--olive-lift); }
.connect .form__note { color: var(--cream); opacity: .68; }
.connect .btn { background: var(--cream); color: var(--forest); border-color: var(--cream); }
.connect .btn:hover { background: #fff; }

/* Reduced motion: the mark is assembled, the card is present, nothing travels. */
@media (prefers-reduced-motion: reduce) {
  .monogram__l, .monogram__b, .connect__form {
    transform: none; opacity: 1; transition: none;
  }
}

/* ---------------------------------------------------------------------------
   THE HEADLINE TYPING ANIMATION WAS REMOVED 2026-09-22, and why is worth keeping.

   It split the H1 into forty letter spans, each animating opacity and transform.
   Forty animating transforms are forty composited layers, all starting in the
   same frame as the hero film begins buffering and decoding. Babak reported the
   film lagging and jumping and said it began when the typing was added.

   Measured on a 4x CPU throttle before removal: 0 dropped frames, median frame
   gap 50ms against the 41.7ms a 24fps film wants. Measured after removal, under
   identical conditions, in the commit that removed it. Whatever the numbers say,
   the film is the thing the hero is for and the typing was decoration.

   The sub-line entrance went with it: it existed only to stop the sub-line
   sitting fully formed under a headline that was still writing.
   --------------------------------------------------------------------------- */

/* ===========================================================================
   RESOURCES
   Two sections on one page, deliberately unlike each other.

   Articles are commentary: dated, many, read once. They get a list, because a
   list is what you scan when you are hunting the one piece you half remember.
   Date first in mono, title in serif, a single line under it.

   Handouts are artefacts: few, undated, returned to. They get cards on the pale
   ground, because each one is a thing you take away rather than a thing you
   read and leave behind.

   The contrast between the two is the design. Rendered alike they would read as
   one undifferentiated pile, and the page would answer neither question.
   =========================================================================== */

/* THE SEARCH FIELD EXISTS ONLY WHERE IT WORKS.
   Every article is real markup in the page before a single script runs. Content
   that depends on script does not exist for a retrieval engine, and this site
   works with JavaScript disabled without exception. The field filters what is
   already on the page; it never fetches and never renders.
   With scripting off the field is never painted, so nobody is handed a control
   that does nothing. The `js` class is set by an inline script in the head, so
   there is no frame in which the field is visible and inert. */
.searchbar { display: none; }
.js .searchbar { display: block; margin: 2.5rem 0 0; }
.searchbar label {
  display: block; font-family: var(--mono); font-size: .75rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent-text); margin-bottom: .6rem;
}
.searchbar input {
  width: 100%; max-width: 32rem; padding: .7rem .9rem;
  font-family: var(--sans); font-size: 1rem; color: var(--ink);
  background: #fff; border: 1px solid var(--stone); border-radius: 0;
}
.searchbar input:focus { outline: 2px solid var(--olive-ink); outline-offset: 1px; }

/* Topic links are real URLs, not script. They are the path for a reader with
   scripting off and the path a crawler follows. */
.topics { margin: 1.25rem 0 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: .5rem .75rem; }
.topics a {
  display: inline-block; font-family: var(--mono); font-size: .75rem; letter-spacing: .06em;
  padding: .45rem .7rem; border: 1px solid var(--stone); text-decoration: none; color: var(--secondary);
}
.topics a:hover, .topics a[aria-current="true"] { border-color: var(--olive-ink); color: var(--olive-ink); }

.articles { list-style: none; margin: 3rem 0 0; padding: 0; }
.articles > li { border-top: 1px solid var(--stone); padding: 1.75rem 0; }
.articles > li:last-child { border-bottom: 1px solid var(--stone); }
.article__date {
  font-family: var(--mono); font-size: .75rem; letter-spacing: .08em;
  color: var(--secondary); margin: 0 0 .5rem;
}
.article__title { font-family: var(--serif); font-weight: 400; font-size: 1.375rem; line-height: 1.3; margin: 0 0 .5rem; }
.article__title a { text-decoration: none; }
.article__title a:hover { text-decoration: underline; text-underline-offset: .2em; }
.article__standfirst { margin: 0; color: var(--secondary); max-width: 54ch; }

/* Shown only when a filter matches nothing. Hidden otherwise, including with
   scripting off, where no filter can ever run. */
.articles__none { display: none; padding: 1.75rem 0; color: var(--secondary); }

/* The handouts notice carries the authorship and the limit. It sits once above
   the cards and again on every handout page, because a reader who arrives at a
   handout directly from a search engine never sees this page at all. */
.notice {
  border-left: 3px solid var(--olive); padding: .9rem 0 .9rem 1.1rem;
  margin: 2rem 0 0; color: var(--secondary); font-size: .9375rem; max-width: 60ch;
}
.notice strong { color: var(--ink); font-weight: 500; }

.handout__meta {
  font-family: var(--mono); font-size: .75rem; letter-spacing: .06em;
  color: var(--secondary); margin: 0 0 .75rem;
}

/* THE RESOURCES CHOOSER.
   The first build of this page separated its two halves with a background tint and one
   hairline, and it read as a single continuous scroll: a reader arrived among the handouts
   without registering that the page had changed subject. Babak called it, 2026-09-24.

   The fix is to state the structure before the reader has to infer it. Two panels sit directly
   under the hero, one per section, each naming what it holds and jumping to it. They are
   navigation, not headings, so the document still carries exactly one h2 per section and the
   heading order stays honest. */
.chooser { display: grid; gap: 1.25rem; margin-top: 2.5rem; }
@media (min-width: 820px) { .chooser { grid-template-columns: 1fr 1fr; gap: 2rem; } }
.chooser__card {
  background: #fff; border: 1px solid var(--stone); border-top: 3px solid var(--olive);
  padding: 1.6rem 1.5rem 1.4rem; display: flex; flex-direction: column;
}
.chooser__kind {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent-text); margin: 0 0 .7rem;
}
/* The description rule is scoped so it cannot swallow the name. Written first as
   `.chooser__card p`, it out-specified `.chooser__name` (0,1,1 beats 0,1,0) and rendered the
   section name at body size, which is the one thing on the card that has to be unmissable.
   Caught by looking at a screenshot; no gate measures type hierarchy. */
.chooser__card .chooser__name {
  font-family: var(--serif); font-size: 1.625rem; line-height: 1.2;
  color: var(--forest); margin: 0 0 .6rem;
}
.chooser__card .chooser__desc { margin: 0 0 1.2rem; color: var(--secondary); font-size: .9375rem; }
.chooser__go { margin-top: auto; margin-bottom: 0; }
.chooser__go a { font-family: var(--mono); font-size: .75rem; letter-spacing: .06em; text-decoration: none; }
.chooser__go a:hover { text-decoration: underline; text-underline-offset: .3em; }

/* A numeral and a rule across the top of each section, so the eye lands on the boundary
   instead of discovering it three paragraphs later. Same mono numeral the steps and phases
   blocks already use, so this invents no new vocabulary. */
.sec-head { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.75rem; }
.sec-head__n {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .12em;
  color: var(--accent-text); white-space: nowrap;
}
.sec-head__line { flex: 1; height: 1px; background: var(--line-rest); }
.section--pale .sec-head__line { background: #C4D2C6; }

/* An anchored section must not land under the fixed header when jumped to. */
#articles, #handouts { scroll-margin-top: 5rem; }

/* The chooser sits inside the hero block, so the hero's own bottom padding was landing under
   it and opening a gap wide enough to read as the end of the page. */
.page-hero .chooser { margin-bottom: 0; }
.page-hero:has(.chooser) { padding-bottom: clamp(3rem, 6vw, 4.5rem); }

/* Handouts are few by design. The three-column practice-card grid left a single handout
   occupying a third of the row with two thirds empty, which read as a page still loading. */
.cards--handouts { grid-template-columns: 1fr; }
@media (min-width: 900px) { .cards--handouts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* The chooser ends by telling you to go to the articles, so the articles should not sit a full
   section rhythm below it. Hero bottom padding plus section top padding measured about 200px at
   1280, which reads as the end of the page rather than the start of the next thing. */
.page-hero:has(.chooser) + .section { padding-top: clamp(2rem, 4vw, 3rem); }

/* A list of rules on a pale ground needs air before the paragraph that follows it. */
.negations + p { margin-top: 2rem; }

/* A six-column reference table cannot collapse to a phone width the way the three-column
   subsector tables do, so it scrolls sideways inside its wrapper instead of pushing the page. */
.table-wrap.table-wrap--scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table-wrap--scroll .data { min-width: 960px; }

/* Four jurisdiction cards sit in one row on a wide screen rather than three and an orphan. */
@media (min-width: 900px) { .cards--four { grid-template-columns: repeat(4, 1fr); gap: 2rem; } }
