/* =====================================================================
   Adverit Legal — Design Tokens (CSS custom properties)
   ---------------------------------------------------------------------
   THE canonical, framework-agnostic source of truth for the brand.

   v2.9.0 — Phase 1 Design Refresh. Palette and type are transcribed from
   the Figma file "Adverit  Copy", page "Master & Satellite actual"
   (node 226:4313). Authorised by ADR-0014 in the ADVERIT vault; the
   per-screen implementation map is docs/design-map.md. 2.1.0 adds the
   Operator Console layer (--adv-console-*), authorised by ADR-0016.
   2.2.0 adds the mobile layer (--adv-m-*) and the first breakpoint
   tokens, transcribed from the 402px mobile tier, authorised by
   ADR-0017. 2.3.0 adds the satellite layer (--adv-sat-*), authorised by
   ADR-0018 (its hero tokens retired in 2.9.0). 2.4.0 gives the master header a row of its own and redraws
   the master hero's headline (--adv-nav-h / --adv-master-nav-h, the
   --adv-hero-intro-pad pair, --adv-hero-intro-title-weight), authorised
   by ADR-0022 (AD-131). 2.5.0 gives the display headings a line budget
   (--adv-display-measure / -budget / -size-tight, the re-measured
   --adv-sat-hero-measure and its -size-tight, --adv-bp-frame),
   authorised by ADR-0021 §4 item 21 (AD-132). 2.6.0 is the 2026-09-16
   round (AD-137): the navy accent button and footer, the second site
   shadow (--adv-shadow-search), and the master homepage's centred hero
   and its search pill (--adv-hero-home-*, --adv-hero-pill-*), which retire the AD-131 row tokens they replace
   (--adv-hero-intro-pad-*, --adv-hero-intro-title-ls,
   --adv-hero-float-gap), authorised by ADR-0024. 2.7.0 is the same
   round's inner pages (AD-138): the inset photo plate's radius
   (--adv-radius-band), the master bar's translucent current item
   (--adv-nav-active-fill / -blur) and the About page's split hero
   (--adv-about-hero-*), authorised by ADR-0025. 2.8.0 adds the form
   field's two drawn states (AD-143): the focus surface and the error
   surface (--adv-color-field-focus / --adv-color-field-error, and the
   --adv-field-* aliases every form reads), authorised by ADR-0028.
   2.9.0 is the round's satellite half (AD-145): one page-title weight
   (700) on both tiers, one header-row height (--adv-nav-h is 99 on both
   tiers and --adv-master-nav-h retires), the firm's city beside the logo
   and in the Home hero (--adv-nav-city-*, --adv-hero-city-*), and the
   footer's light-blue network line on navy, authorised by ADR-0030.
   Its design-QA amendment (ADR-0030 Amendment 1, still 2.9.0 — unreleased)
   turns the nav tint into the HOVER plate and puts the caret on the body
   grey (--adv-color-nav-caret), bounds the city names (--adv-hero-city-max-w
   / -size-tight, --adv-nav-city-max-w), and draws the 402 bar and Homes
   (--adv-m-header-h 88, --adv-m-logo-tile-* 220 × 88, --adv-m-logo-h,
   --adv-m-hero-logo-w, --adv-m-hero-city-size, --adv-m-nav-city-size,
   --adv-m-home-title-weight / -lh). Its second design-QA amendment
   (ADR-0030 Amendment 2, still 2.9.0) slows the Home logo's slide into
   the bar (--adv-transition-logo-slide, 0.48s). ADR-0025 Amendment 19
   (AD-149, still 2.9.0) adds the type scale's smallest step
   (--adv-caption-size 10px, --adv-caption-lh, --adv-caption-ls): the
   news-card date carried it as a literal, and the ≤860 office card on
   the master's map draws two more lines at the same size.
   ADR-0049 (AD-180, still 2.9.0) adds the e-mail layer
   (--adv-email-width 600px, --adv-email-logo-w 160px): the two numbers
   Authentik's generated invitation and reset e-mails need that no page does.
   ADR-0025 Amendment 24 (AD-185, still 2.9.0) adds --adv-m-detail-gap 54px:
   the 402 detail stack (681:27056, 704:30027, 750:35822, 760:8044 — every
   block of a detail page 54 apart), which components.css carried as a literal.

   Every Adverit surface — Hugo firm sites, the adverit.legal master site,
   the demo simulation tool, and any admin/portal UI — MUST consume these
   variables and match them exactly. Do NOT hard-code raw hex/px values
   in components; reference var(--adv-*). Changes here are brand changes
   and require an ADR in the ADVERIT vault.

   Provenance is marked on every group that has none in Figma:
     [figma]      bound to a Figma variable — authoritative
     [read]       read off a component with get_design_context
     [measured]   read off a render; no variable binds it
     [kept]       carried over from v1; the design does not address it
     [deprecated] alias kept so consumers don't break; scheduled for removal

   Values are mirrored verbatim in tokens.scss and tokens.json — keep the
   three in lock-step.
   ===================================================================== */

:root {
  /* ---------- Brand colours [figma] ---------- */
  --adv-color-primary:        #2B68A9; /* "Corporate blue" — links, active edges, accents */
  --adv-color-primary-dark:   #122448; /* "Dark navy" — filled CTA (ADR-0024), active text, deep panels */
  --adv-color-hero-navy:      #122448; /* Hero / footer base (same navy) — footer on both tiers */

  /* ---------- Accents [figma] ----------
     Annotated in the file as "used selectively across the interface".
     These are accents, NOT a second primary. */
  --adv-color-accent-light-blue: #D0DEEC; /* Active/selected surface */
  --adv-color-accent-burgundy:   #652C35; /* Hover text accent, section labels */

  /* ---------- Page palette [design] ----------
     From the "Adverit Design System" Claude Design project, which carries the
     page-level values the Figma *variables* never bound — the ones the screens
     actually use. Everything above is bound in Figma and stays authoritative
     for components; these cover the compositions around them.

     `heroInk` (#112B3D) USED TO LIVE HERE as "the one value in neither source's
     token list". It is gone: 896:9764 binds `corporate/navy`, so the satellite
     hero title is #122448 and the value now resolves through
     `--adv-sat-heading-ink`. Removed rather than aliased — it had one consumer,
     in this repo, and a [measured] token that a variable has since contradicted
     is a trap, not a fallback. */
  /* `surfaceCool` (#F5F5F5) USED TO SIT HERE as "cool section band — NOT
     surface-alt". Removed 2026-09-01: Figma's variable set has exactly TWO page
     backgrounds — `background/main` #FAF9F7 and `background/secondary` #F5F4F2 —
     and #F5F5F5 is neither. Both painted bands on the satellite homepage bind
     `background/secondary` on their own rectangles (896:9785, 896:9818).
     It encoded a distinction the design does not make, and the template comment
     that repeated it as fact is what kept the wrong colour on the band. */
  --adv-color-blue-deep:    #355992; /* master brand / link hover */
  --adv-color-ink-strong:   #212121; /* outlined-button label, strongest ink */
  --adv-color-ink-muted:    #797979; /* secondary text in compositions */
  --adv-color-surface-blue: #E7EEF3; /* pale blue panel */
  --adv-color-rule:         #DEDEDE; /* hairline rules inside sections */
  /* The hero scrim. The master's photo band carries a full-height gradient from
     #232323 at the foot to transparent at the head (623:21938) — darker than
     body ink, and the only reason the white search copy over the photograph is
     readable. Not a surface and not a text colour: it exists to be seen
     through. */
  --adv-color-scrim:        #232323;

  /* ---------- Glass [design, read from the component] ----------
     The master homepage's quick links (node 516:5836, "Frame 102") are the one
     surface in the system that sits ON a photograph: a 10% white wash over a
     10px backdrop blur, going to a 30% light-blue wash when selected. Read off
     the component, not measured off a render, and bound to no Figma variable —
     which is why they are here rather than in the palette above.

     A wash, not a fill: both take the colour of the photograph behind them, so
     they are only legible over the hero's dark foot. Do not reuse on a plain
     page surface, where a 10% white on near-white is invisible. */
  --adv-color-glass:        rgba(245, 245, 245, 0.10);
  --adv-color-glass-active: rgba(208, 222, 236, 0.30);
  --adv-glass-blur:         10px;

  /* ---------- On-media controls [design, read from 623:21940] ----------
     The master's hero CONTROLS — the two selects and the search field — when
     they sit on the photograph: a 70% INK wash under a 5px blur, on the dark
     border, with inverse copy.

     NOT the glass above, and the difference is deliberate. Glass is a 10% WHITE
     wash: it lightens what is behind it, which is right for the quick-link
     tiles (they are plates, and their labels are large). A control has to be
     READ — a placeholder at 14px over an arbitrary photograph needs the
     background darkened, not lightened. Both live on the same hero, one over
     the other, because they answer different questions.

     THE MOBILE TIER ALREADY DREW THIS (ADR-0017, `--adv-m-search-fill`): the
     402 hero field is the same 70% ink. Same value, so the mobile token now
     REFERENCES this one instead of restating it — desktop simply had not
     caught up until 623:21940.

     THE 5px BLUR IS THE ONE NEW VALUE (glass blurs at 10) — see the ADR note
     in Decisions/, rule 5. */
  --adv-on-media-fill: color-mix(in srgb, var(--adv-color-ink) 70%, transparent); /* rgba(60,60,60,.7) */
  /* THE BUTTON IS A LIGHTER WASH THAN THE FIELD — 30%, not 70% (AK,
     2026-08-31). It overlaps the field's tail, so the two washes STACK: at a
     matching 70% the disc composites to 91% ink and a solid #3C3C3C ring has
     almost nothing to separate from, which is what AK saw as "no border". Over
     a mid-grey photograph the arithmetic is: field 87, disc 68, ring 60 — the
     disc reads and the ring does not. At 30% it becomes field 87, disc 79,
     ring 60: the ring gains what the disc gives up, which is the right trade
     for a control whose SHAPE is its affordance.

     681:27546 (the 402 component) is where the design states this; 623:21940
     draws the desktop button at 70% like its field. Taking the mobile value on
     both tiers — a DELIBERATE divergence from the desktop frame, flagged for
     design, and the only reading under which the button is a button. */
  --adv-on-media-btn-fill: color-mix(in srgb, var(--adv-color-ink) 30%, transparent);
  --adv-on-media-blur: 5px;

  /* ---------- Nav item HOVER plate [design, read from 247:7400] ----------
     Every bar item's HOVER, on both tiers (247:7400, the "Header section menu"
     component both headers instance): a 5% BLACK tint under a 30px backdrop
     blur, radius 12. The frame's blur is 30.3, rounded the way ADR-0024
     rounded the menu's 3.05.

     The names say "active" because the tint was the master's CURRENT item
     until the client redrew the states (ADR-0025 §3 → ADR-0030 Amendment 1
     §1). Names are identities, so they stay; current is now an unfilled navy
     600 label (--adv-active-text).

     THE FIRST TRANSLUCENT-BLACK SURFACE IN THE PALETTE, AND IT HAS TO BE ONE.
     About's bar and the satellite Home's are filled #F5F4F2 — which is
     --adv-hover-surface — so an opaque plate would vanish into the bar it sits
     on. A tint darkens whatever is under it by the same step on either bar
     surface. */
  --adv-nav-active-fill: rgba(0, 0, 0, 0.05);
  --adv-nav-active-blur: 30px;

  /* ---------- Neutrals & surfaces [figma] ---------- */
  --adv-color-ink:            #3C3C3C; /* "Text Primary" — headings & body ink */
  --adv-color-body:           #51595F; /* "Text Secondary" — long-form body copy */
  --adv-color-surface:        #FAF9F7; /* "Background Primary" — page background, controls */
  --adv-color-surface-alt:    #F5F4F2; /* "Background Secondary" — cards, hover surfaces */
  --adv-color-border:         #DAD6D0; /* "Borders Light" — default 1px borders */
  --adv-color-border-strong:  #3C3C3C; /* "Borders Dark" */
  /* PURE BLACK — the on-media control's ACTIVE edge, and the only place the
     system uses #000 (AK, 2026-08-31). It is NOT a general ink: text is
     `--adv-color-ink` #3C3C3C, and "Borders Dark" is that same #3C3C3C, which
     is what every edge on the hero control carries at REST. Black is the step
     above it, so focusing the field darkens its outline instead of recolouring
     it — the resting/active pair reads as one control changing state rather
     than as two colours. ADR OWED (rule 5): a new brand value, bound to no
     Figma variable. */
  --adv-color-black:          #000000;
  --adv-color-white:          #FFFFFF;
  /* The dropdown caret. 247:7400 (every state), 1529:15071 and the hero pill
     fill it with "text/secondary", which IS the body grey — an alias, not a
     second hex (ADR-0030 Amendment 1 §1). It was #868686 ("old/Grey/
     navigation") until the 2026-09-17 redraw. */
  --adv-color-nav-caret:      var(--adv-color-body);

  /* ---------- On-dark [figma] ---------- */
  --adv-color-on-navy:        #FAFBFC; /* "Text Inverse" — text on navy/blue */

  /* ---------- Tint ramps [read] ----------
     498:5753 navy · 498:5773 blue · 498:5785 burgundy.

     These are OPACITY steps on the base colour — 100/90/80/70/60/50% — not
     opaque tints mixed toward white. The distinction matters: they take the
     colour of whatever sits behind them, so on the #FAF9F7 page they read as
     the swatch board shows, and on any other surface they do not. Use them
     over a known backdrop, or flatten first. */
  --adv-ramp-navy-100: rgba(18, 36, 72, 1);
  --adv-ramp-navy-90:  rgba(18, 36, 72, 0.9);
  --adv-ramp-navy-80:  rgba(18, 36, 72, 0.8);
  --adv-ramp-navy-70:  rgba(18, 36, 72, 0.7);
  --adv-ramp-navy-60:  rgba(18, 36, 72, 0.6);
  --adv-ramp-navy-50:  rgba(18, 36, 72, 0.5);
  --adv-ramp-blue-100: rgba(43, 104, 169, 1);
  --adv-ramp-blue-90:  rgba(43, 104, 169, 0.9);
  --adv-ramp-blue-80:  rgba(43, 104, 169, 0.8);
  --adv-ramp-blue-70:  rgba(43, 104, 169, 0.7);
  --adv-ramp-blue-60:  rgba(43, 104, 169, 0.6);
  --adv-ramp-blue-50:  rgba(43, 104, 169, 0.5);
  --adv-ramp-burgundy-100: rgba(101, 44, 53, 1);
  --adv-ramp-burgundy-90:  rgba(101, 44, 53, 0.9);
  --adv-ramp-burgundy-80:  rgba(101, 44, 53, 0.8);
  --adv-ramp-burgundy-70:  rgba(101, 44, 53, 0.7);
  --adv-ramp-burgundy-60:  rgba(101, 44, 53, 0.6);
  --adv-ramp-burgundy-50:  rgba(101, 44, 53, 0.5);

  /* ---------- Interaction language [read] ----------
     Consistent across button, tag, filter, search, nav item and all four
     cards, so it is encoded once here rather than per component. */
  --adv-hover-surface:     var(--adv-color-surface-alt);      /* #F5F4F2 */
  --adv-hover-accent:      var(--adv-color-accent-burgundy);  /* text accent on hover */
  --adv-active-surface:    var(--adv-color-accent-light-blue);/* #D0DEEC */
  --adv-active-text:       var(--adv-color-primary-dark);     /* navy — NOT blue, see below */
  --adv-active-edge:       var(--adv-color-primary);          /* #2B68A9 */
  /* THE FORM FIELD'S TWO DRAWN STATES (AD-143, ADR-0028 §8) — read off
     560:15756 (focus) and 560:15874 (validation). Neither fill is bound to a
     Figma variable; both edges are. The focus state is NOT the active state
     above: a focused field is a near-white #F2F4F5 under the blue edge, where
     a selected chip is #D0DEEC. The error state is a warm #EBE5E4 under the
     burgundy edge, with the message in burgundy. Every `.adv-field` reads
     these — the master's forms and the satellite's contact form alike. */
  --adv-color-field-focus:   #F2F4F5;
  --adv-color-field-error:   #EBE5E4;
  --adv-field-focus-surface: var(--adv-color-field-focus);
  --adv-field-focus-edge:    var(--adv-active-edge);          /* #2B68A9 */
  --adv-field-error-surface: var(--adv-color-field-error);
  --adv-field-error-edge:    var(--adv-color-accent-burgundy); /* #652C35 */
  --adv-field-error-text:    var(--adv-color-accent-burgundy);
  /* Card hover is not a recolour: same surface under a 2% blue wash, plus
     scale(1.05) and the title to navy. The wash over #F5F4F2 composites to
     #F1F1F1, which is what earlier measurements of the render reported. */
  --adv-card-hover-wash:   rgba(43, 104, 169, 0.02);
  --adv-card-hover-scale:  1.05;

  /* ---------- Disabled [measured] ----------
     Binds no Figma variable in any of the six button variants. Label on fill
     is 3.08:1 — below AA, accepted under WCAG 1.4.3's inactive-control
     exemption. Flagged to design; replace if a bound value ever arrives. */
  --adv-disabled-bg:     #D6D6D6;
  --adv-disabled-border: #979EA5;
  --adv-disabled-text:   #777778;

  /* ---------- Semantic aliases (prefer these in components) ---------- */
  --adv-text:                 var(--adv-color-ink);
  --adv-text-body:            var(--adv-color-body);
  --adv-text-muted:           var(--adv-color-body);
  --adv-bg:                   var(--adv-color-surface);
  --adv-bg-card:              var(--adv-color-surface-alt);
  --adv-bg-tint:              var(--adv-color-accent-light-blue);
  --adv-border-color:         var(--adv-color-border);
  --adv-link-color:           var(--adv-color-primary);
  --adv-link-hover:           var(--adv-color-primary-dark);
  /* Focus is NOT designed — authored by us, because it is an accessibility
     requirement that cannot wait on design (ADR-0014 §4). */
  --adv-focus-ring:           var(--adv-color-primary);
  --adv-focus-ring-width:     2px;
  --adv-focus-ring-offset:    2px;

  /* ---------- Deprecated aliases [deprecated] ----------
     The new palette has no counterpart for these, but they have live
     consumers (tint ×104, link ×47, tint-edge ×45, faint ×43, on-navy-muted
     ×12). Remapped rather than deleted so this refresh does not double as a
     console-wide breakage. Scheduled for removal in a follow-up ticket —
     do NOT reference them in new code. */
  --adv-color-link:           var(--adv-color-primary);        /* was #1A6AA3 */
  --adv-color-muted:          var(--adv-color-body);           /* was #6D7A85 */
  --adv-color-faint:          var(--adv-color-body);           /* was #9AA6B0 */
  --adv-color-tint:           var(--adv-color-accent-light-blue); /* was #EEF4F8 */
  --adv-color-tint-edge:      var(--adv-color-border);         /* was #D4E2EC */
  --adv-color-border-soft:    var(--adv-color-surface-alt);    /* was #EEF1F4 */
  --adv-color-on-navy-muted:  var(--adv-color-on-navy);        /* was #9CC3DD */
  --adv-color-navy-divider:   rgba(250, 251, 252, 0.12);       /* was #1C405F */

  /* ---------- Wordmark [kept] ----------
     These describe the logo asset, not the UI, so the refresh leaves them. */
  --adv-color-logo-blue:      #5E89C6;
  --adv-color-charcoal:       #333739;

  /* ---------- Status palette (admin Operator Console) [kept] ----------
     Live / Suspended / Building / Error / Demo. No counterpart in Figma —
     this is a console taxonomy, not brand surface — so ADR-0007 stands and
     the values are carried over.

     ONE CORRECTION (ADR-0014 §3): warning measured 4.47:1 on its own
     background, not the 4.8:1 recorded in v1 — under AA. The fg is darkened
     from #B45309 to #A34A08 to clear 4.5:1. Erratum filed against ADR-0007.

     Note the pill backgrounds sit at 1.02–1.11:1 against the new page
     backgrounds: the border is load-bearing and must not be dropped. */
  --adv-status-success-fg:     #1F7A5C;
  --adv-status-success-bg:     #E7F3EC;
  --adv-status-success-border: #BFE0CC;
  --adv-status-warning-fg:     #A34A08;  /* was #B45309 — see above */
  --adv-status-warning-bg:     #FBF0E3;
  --adv-status-warning-border: #EBD3AE;
  --adv-status-danger-fg:      #B4322B;
  --adv-status-danger-bg:      #FBEAE8;
  --adv-status-danger-border:  #E6C3BF;
  --adv-status-demo-fg:        #6B4E9E;
  --adv-status-demo-bg:        #F1ECF8;
  --adv-status-demo-border:    #D9CCEE;
  --adv-status-info-fg:        #1A6AA3;  /* no longer tracks link, which moved to #2B68A9 */
  --adv-status-info-bg:        #E8F1F8;
  --adv-status-info-border:    #C2DBEC;

  /* ---------- Typography: families [figma] ----------
     The Figma file is Inter and nothing else. Self-hosted, latin +
     latin-ext, font-display: swap — no Google Fonts CDN, because the EU
     data-residency rule makes a third-country font fetch on every page
     load an avoidable transfer. */
  --adv-font-heading: 'Inter', system-ui, -apple-system, sans-serif;
  --adv-font-body:    'Inter', system-ui, -apple-system, sans-serif;
  --adv-font-mono:    'IBM Plex Mono', ui-monospace, monospace; /* [kept] console/eyebrow only */

  /* ---------- Typography: weights ---------- */
  --adv-weight-regular:  400;
  --adv-weight-medium:   500;
  --adv-weight-semibold: 600;
  --adv-weight-bold:     700;

  /* ---------- Type scale [figma] ----------
     Figma exposes seven styles; the token set has eight roles, so the
     mapping is authored, not mechanical (ADR-0014 §2).

     LINE HEIGHT: three Figma styles report `lineHeight: 100`, which means
     AUTO — not 100% and not 100px. For Inter, AUTO is 1.21 (hhea 1984+494
     over 2048 upem), confirmed against rendered nodes: a 38px heading
     measures 46px, a 14px node 17px. Never transcribe it as 1 or 100.

     Role       Figma style                Size  LH               */
  --adv-h1-size: 38px;   --adv-h1-lh: 1.21;   --adv-h1-ls: 0;  /* Heading/semibold_38px (AUTO) */
  --adv-h2-size: 28px;   --adv-h2-lh: 1.5;    --adv-h2-ls: 0;  /* Heading/regular_28px */
  --adv-h3-size: 22px;   --adv-h3-lh: 1.21;   --adv-h3-ls: 0;  /* Heading/medium_22px (AUTO) */
  --adv-h4-size: 16px;   --adv-h4-lh: 1.5625; --adv-h4-ls: 0;  /* Navigation/medium_16px — see note */
  --adv-lead-size: 24px; --adv-lead-lh: 1.5;  --adv-lead-ls: 0;/* Body/regular_24px */
  --adv-body-size: 16px; --adv-body-lh: 1.5625; --adv-body-ls: 0; /* Body/regular_16px (25px) */
  --adv-small-size: 14px; --adv-small-lh: 1.21; --adv-small-ls: 0; /* Navigation/regular_14px (AUTO) */
  --adv-eyebrow-size: 12px; --adv-eyebrow-lh: 1.4; --adv-eyebrow-ls: 0.12em; /* [kept] no Figma counterpart */
  --adv-caption-size: 10px; --adv-caption-lh: 1.21; --adv-caption-ls: 0; /* "Old/small" (AUTO) */

  /* caption is the design's smallest step, and it took until AD-149 to become a
     token. The news-card date has been 10px since the card shipped, written as
     a literal in components.css with a comment calling it "the only 10px in the
     design"; 1605:21983/21984 — the ≤860 office card's country and its
     practice-areas line — made that untrue. Two call sites is a role.
     `small` is 14 and its Figma style is Navigation/regular_14px; its JSON role
     read "Caption" until AD-149 and now reads "Small", so the word means one
     size. Authorised by ADR-0025 Amendment 19. */

  /* h4 has no fourth heading in Figma — the design has three heading sizes
     and card titles use h2 (28px). It is mapped to Navigation/medium_16px,
     the smallest authored label style, so the role stays usable. */

  /* Navigation roles, explicit [figma] */
  --adv-nav-size:       16px; --adv-nav-lh:       1.5625; /* Navigation/medium_16px, weight 500 */
  --adv-nav-small-size: 14px; --adv-nav-small-lh: 1.21;   /* Navigation/regular_14px (AUTO) */

  /* ---------- Display scale [design] ----------
     The Figma *variables* stop at 38px, so a transcription of them alone has
     nothing to set a hero or a section headline with — which is why the first
     pass produced a type scale that could not build a homepage. These are the
     sizes the screens use, from the Claude Design project's `typography.css`
     plus the satellite template itself.

     LINE HEIGHT: the file reports 100 on these, and ADR-0014 §2 is explicit that
     100 means AUTO — 1.21 for Inter — not 100%. The first transcription read it
     as a flat 1 and set every display headline in a line box its own size. Only
     `display` is corrected here, from a measured 70px on the master homepage's
     band headline; `hero`, `pageTitle` and `cardTitle` are left at 1 until each
     is measured the same way rather than assumed. */
  /* `--adv-hero-*` MOVED to the satellite layer at the foot of this file
     (`--adv-sat-hero-*`, ADR-0018) and retired there in 2.9.0 with its only
     consumer, the firm sites' `.adv-hero-title` (ADR-0030 §2). Leaving it
     here is what let five empty-state plates borrow it — see
     `--adv-monogram-size` below. */
  /* The initials plate that stands in for a missing photograph — firm card,
     expert photo, person card, insight media, CTA band. All five are AUTHORED
     (the design draws no empty state for any of them) and all five used to read
     `--adv-hero-size` simply because it was the largest display value in the
     file. That coupling meant correcting the hero above would silently resize
     five unrelated components, so the borrowed value is pinned here instead and
     the plates keep exactly the size they render today. */
  --adv-monogram-size: 72px; /* [authored] empty-photo initials plate */
  /* AUTO (1.21), not 1 — see the note below the group. 58 x 1.21 = 70.18, which
     is the 70px line box the frames show on a band headline. */
  --adv-display-size: 58px; --adv-display-lh: 1.21; --adv-display-weight: 700; /* section headline */
  /* ---------- The display heading's line budget (AD-132) ----------
     A MEASURE, A RUNE COUNT AND ONE STEP DOWN, and none of them belong on
     `--adv-display-size`: that token is also read by `.adv-expert-name`,
     `.adv-detail__name`, `.adv-article__title` and
     `.adv-page-head--master .adv-page-title`, none of which want a measure.
     These three reach exactly two headings, through `.adv-display--budget`
     and `.adv-display--tight` — see the note on those rules in
     `css/components.css`, which is also where the three-line cap lives.

     600 IS WHAT THE SATELLITE ALREADY DREW. `sections/intro.html` carried an
     inline `max-width:16ch`, which computes to 603.38 at 58/700 — so this is
     that number, made a token and given to the master's About heading, which
     had no cap at all. It binds because the band's column is 660.

     55 IS MEASURED, NOT DIVIDED. Dividing 600 by an average character width
     gives 65 and ignores raggedness, which is where the missing ten live; a
     realistic string at 600/58/700 takes a fourth line from 56 runes. Hugo
     compares the headline's `strings.RuneCount` against this number and emits
     `--tight` or does not, which is how the size steps by CONTENT and not by
     viewport — `clamp()` keys off the screen and would do the opposite. Hugo
     cannot read a custom property at build time and neither can `@media`, so
     this is the canonical record and the literals in `sections/hero.html`,
     `sections/intro.html`, the master's `sections/about.html` and
     `sites/_template/static/admin/config.yml` MUST match it. Same contract as
     `--adv-bp-*` above. */
  --adv-display-measure:     600px; /* `.adv-display--budget`'s measure in the 660 column */
  --adv-display-budget:      55;    /* runes that fit three lines at 58/700 [measured 2026-09-08] */
  --adv-display-size-tight:  52px;  /* the one step down, chosen per string [figma] */
  /* 58/1.21, NOT 72/1 (AK, 2026-09-01). AD-75 set 72 from the two handoff
     templates and recorded it as correcting "the 58/900 a first pass read from a
     style name". The style name was right. THE FILE HAS NO 72px TYPE STYLE AT
     ALL — its heading scale is 58 (black/bold), 38 (semibold), 28 (regular),
     22 (medium) — and three page h1s bind `Heading/black_58px` directly:
     336:10814 (satellite About), 343:11445 (satellite listing) and the master's
     own 522:8766. So 72 existed only in the handoff HTML, which is why
     `.adv-page-head--master .adv-page-title` was already patched back to 58: the
     master had found this and fixed it at its own scope, leaving the satellite on
     the wrong base. That override is now redundant, as is `--sm`.
     lh is AUTO, the same trap as `hero` and `display`: About's h1 box is 70,
     which is 58 x 1.21, not 72 x 1.
     700 SINCE 2.9.0 (ADR-0030 §4, AD-145). The redrawn satellite heads
     (343:11443 and its three twins, 553:12683, 553:13398) bind
     `Heading/bold_58px` where 336:10814 / 343:11445 bound `black_58px`, and
     the master had already moved every head it redrew to 700 by rebinding
     this at its own scope (ADR-0025 §2). The token moves instead and those
     rebinds are gone; the two search titles, which nothing rebound, follow. */
  --adv-page-title-size: 58px; --adv-page-title-lh: 1.21; --adv-page-title-weight: 700; /* page h1 — 343:11443, 553:12683 */
  /* MEASURED AT LAST, and it is h2 (AK, 2026-08-31). 38/1 was the placeholder
     the note below this group flagged — "cardTitle is left at 1 until measured".
     The component 288:3219 names its title style `Heading/regular_28px` in every
     variant, which is `--adv-h2-size` exactly, and the token file already said
     so in the h4 note: "card titles use h2 (28px)". 1.5 comes with the style. */
  --adv-card-title-size: 28px; --adv-card-title-lh: 1.5; --adv-card-title-weight: 400; /* large card title = h2 */
  --adv-subtitle-size: 24px; --adv-subtitle-lh: 1.5; /* hero subtitle, intro copy */

  /* THE MASTER HOMEPAGE'S HEADLINE IS THE ONE DISPLAY SIZE THAT IS NOT SET
     TIGHT. It is 58px like the others, but with a loose line box — not the
     AUTO every other display size carries.

     REDRAWN TWICE. 2026-09-08 (1198:9572): the line box closed 68 → 56 and the
     weight dropped 900 → 700. The weight differs from `--adv-page-title-weight`,
     which is every page h1 on BOTH tiers, hence a token of its own.
     2026-09-16 (1482:29818, ADR-0024 §6): the headline is centred above the
     search and binds the NAMED style `Heading/bold_58px` — 700, letter-spacing 0,
     a 95.245% line box (55.2). That binding answers AD-131's open question, so
     the 1px tracking token is gone and the rule says `letter-spacing: 0`; the
     56 stays, 0.8px from the frame.

     Its own tokens rather than a change to `--adv-display-*`: those set every
     band headline on the page, and the file gives THIS node its own metrics.
     Consumed by `.adv-page-hero--home .adv-page-title`. */
  --adv-hero-intro-title-weight: 700;
  --adv-hero-intro-title-lh: 56px;

  /* Section label — uppercase, maroon, 24px. This is what the screens put above
     every band ("About us", "practice areas", "our values"). Note it is NOT the
     v1 `eyebrow`, which is 12px mono and has no counterpart in the design at
     all; that one stays only because the console still uses it. */
  --adv-label-size: 24px; --adv-label-lh: 1; --adv-label-weight: 500;

  /* ---------- Spacing [read] ----------
     Measured off auto-layout padding and gaps. 26 and 34 do not fit the old
     4/8-point scale — the scale gains steps rather than the comps being
     rounded to fit it. */
  --adv-space-4:   4px;   /* card title→body gap */
  --adv-space-8:   8px;   /* [kept] */
  --adv-space-12:  12px;  /* filter row gap, panel gap */
  --adv-space-16:  16px;  /* dropdown item gap, control padding-block */
  --adv-space-24:  24px;  /* [kept] */
  --adv-space-26:  26px;  /* control + card padding-inline (button, filter, card) */
  --adv-space-32:  32px;  /* [kept] */
  --adv-space-34:  34px;  /* card padding-block */
  --adv-space-40:  40px;  /* nav item padding-inline */
  --adv-space-42:  42px;  /* expanded filter column gap */
  --adv-space-48:  48px;  /* [kept] */
  --adv-space-60:  60px;  /* page margin: 60 each side of the 1320 container on 1440 */
  --adv-space-64:  64px;  /* [kept] */

  /* ---------- Radii [read] ----------
     The design has exactly two: 12px for every panel and card, pill for
     every control. The button stores a literal 66px, which CSS clamps to
     half its 50px box — so it is a pill, and is transcribed as one.
     The remaining names are deprecated aliases (button ×90, md ×68). */
  --adv-radius-0:       0;
  --adv-radius-card:    12px;   /* all four cards + the open-filter panel */
  --adv-radius-pill:    999px;  /* button, tag, filter, search field */
  --adv-radius-xs:      4px;    /* open-filter search field + tickbox (522:9005, 522:9537) */
  /* The master's PHOTO PLATES (AD-138): the listing band (1485:37739), the
     detail band (1485:37746) and About's hero photograph (1482:33811) are inset
     1320 plates with a 24 radius. A third radius on the desktop tier — ADR-0025
     §1 amends ADR-0014 §5 ("exactly two") and ADR-0017 §4 ("two per tier"). */
  --adv-radius-band:    24px;
  --adv-radius-button:  var(--adv-radius-pill);  /* [deprecated] was 6px */
  --adv-radius-md:      var(--adv-radius-card);  /* [deprecated] was 8px */
  --adv-radius-lg:      var(--adv-radius-card);  /* [deprecated] was 14px */
  --adv-radius-xl:      var(--adv-radius-card);  /* [deprecated] was 16px */

  /* ---------- Borders ---------- */
  --adv-border-width: 1px;
  --adv-border:       var(--adv-border-width) solid var(--adv-color-border);
  --adv-border-tint:  var(--adv-border-width) solid var(--adv-color-border);

  /* ---------- Elevation [read] ----------
     THE DESIGN IS FLAT. No component in the file casts a shadow — not the
     card, not its hover, not the full-bleed dropdown, not the floating
     filter panel. Every surface is fill + 1px border, and card hover uses
     scale, not elevation. So the site shadows resolve to `none`.

     raised/dropdown are retained for the Operator Console only: a dialog
     or slide-over with no elevation is a usability problem, not a style
     choice. This is a sanctioned divergence (ADR-0014 §6) — the first in a
     system whose premise is one visual language everywhere.

     ONE EXCEPTION ARRIVED (AK, 2026-08-31): the master's rebuilt "Find legal
     support" menu (890:8431) carries `drop-shadow(0 0 3.05px rgba(0,0,0,0.08))`
     — the FIRST site component in the file to cast one, and it contradicts the
     finding above. It is a hairline halo, not elevation: no offset, 3px of
     blur, 8% black, on a panel that already has its 1px border. Kept as its own
     token rather than relaxing `--adv-shadow-card`, because the finding still
     holds for every other surface. Recorded by ADR-0024.

     A SECOND ONE ARRIVED (2026-09-16, AD-137): the master hero's search pill
     (1482:29818) carries `drop-shadow(0 0 3.05px rgba(0,0,0,0.04))` — the same
     halo at half the strength. Its own token for the same reason, and rounded
     to 3px the way the menu's 3.05 was. Two named exceptions, not a relaxed
     rule: every other surface is still flat. ADR-0024 §4. */
  --adv-shadow-card:       none;
  --adv-shadow-card-hover: none;
  --adv-shadow-menu:       0 0 3px rgba(0, 0, 0, 0.08);         /* master nav menu, 890:8431 */
  --adv-shadow-search:     0 0 3px rgba(0, 0, 0, 0.04);         /* master hero search pill, 1482:29818 */
  --adv-shadow-raised:     0 10px 30px rgba(18, 36, 72, 0.12);  /* console only */
  --adv-shadow-dropdown:   0 12px 34px rgba(18, 36, 72, 0.14);  /* console only */

  /* ---------- Layout [read] ---------- */
  --adv-container:      1320px; /* search field is 1320 wide at x=60 on a 1440 frame */
  --adv-gutter:         26px;   /* card inner gutter */
  --adv-grid-columns:   12;
  --adv-section-pad-x:  60px;   /* page margin on 1440 */
  /* [design] The screens space their bands by 96 and stack heading→body→CTA by
     26. v1's 56px section padding was a guess and is superseded. */
  --adv-section-gap:    96px;
  --adv-stack-gap:      26px;
  --adv-section-pad-y:  96px;   /* = --adv-section-gap; literal so the parity test can compare it */
  --adv-card-gap:       60px;   /* between cards in a homepage row */
  /* [design] THE MASTER HOMEPAGE HERO — ONE CENTRED COLUMN (1482:29818,
     2026-09-16, ADR-0024 §6). A 1440 x 1024 composition that starts at y=0,
     under the transparent bar: the wordmark box at 112, the headline centred
     on 457.5, the subtitle at 510, the search pill at 643, "Popular:" at 725.

     THE GAPS ARE WHAT IS LEFT BETWEEN THE BLOCKS' OWN HEIGHTS, so each block
     keeps its own box and the column cannot drift by summing: wordmark 215.4
     (the tile at 2.174x, `.adv-page-hero__wordmark`) → 102 → h1 56 → 25 →
     subtitle 36 → 97 → pill 70 → 12 → Popular. 102 rather than the 103 a 215
     box would give: the glyph box renders 215.4, and 102 puts the h1's centre
     on the frame's 457.5.

     `min-height`, not `100vh`: the frame is a composition, not a viewport — at
     900 tall the Popular line alone would already sit at the fold.

     NO OPACITY TOKEN. The frame draws its render at 73% over #F5F4F2, and the
     designer's export ALREADY IS that composite — measured against Figma's own
     render of 1482:29818 (mean error 0.6 as delivered, 3.1 with a further 73%
     applied). So the file is shown as it is. Off the 4/8 scale throughout;
     every value is the frame's. */
  --adv-hero-home-min-h:         1024px;
  --adv-hero-home-pad-top:       112px;
  --adv-hero-home-gap-title:     102px;
  --adv-hero-home-gap-subtitle:  25px;
  --adv-hero-home-gap-search:    97px;
  --adv-hero-home-title-measure: 892px;
  --adv-hero-home-gap-popular:   12px;
  /* [design] The hero's search pill (1482:29844): 899 x 70, its two select
     cells 100 and 140 wide, and a 60px navy submit disc 5 in from the right
     end. The cell gap and the pill's own inset are the scale's 26. */
  --adv-hero-pill-w:            899px;
  --adv-hero-pill-h:            70px;
  --adv-hero-pill-office-w:     100px;
  --adv-hero-pill-support-w:    140px;
  --adv-hero-pill-submit-inset: 5px;
  /* [design] The master About hero (1482:33810, AD-138): one 1024 band, copy on
     the left in a 500 column (1482:33910, vertically centred — 366 to 659), a
     720 x 815 photograph from the bar's foot to the right edge (1482:33811).
     Its own min-height rather than --adv-hero-home-min-h: the values match
     today, but a redraw of one page must not move the other. */
  --adv-about-hero-min-h:   1024px;
  --adv-about-hero-copy-w:  500px;
  --adv-about-hero-photo-h: 815px;
  /* [read] The header's row — ONE height for both tiers since 2.9.0. The design
     publishes one header component in two variants (516:6080); both were 60
     until the 2026-09-08 round redrew the master's at 99 (1198:9572,
     1205:11636), and the 2026-09-16 round redrew the satellite's at 99 too
     (I553:12719, 1484:36481 — ADR-0030 §1). So the second token the master's
     value used to need (--adv-master-nav-h, rebound onto this one inside
     `.adv-nav--master`) is gone: `.adv-nav__bar` reads this, and so do the
     rules OUTSIDE the nav whose frame positions are page-y and are written as
     "frame y − bar" (ADR-0025 §8) — the heroes that pull themselves up under
     the bar and the listing and detail heads, on both tiers. Below 861 the bar
     is --adv-m-header-h, set as a `height` directly. */
  --adv-nav-h:          99px;
  /* [design] The firm's city beside the logo (I553:12719: Inter Medium 24/25,
     #3C3C3C) and in the Home hero's lockup under the wordmark (1484:36477:
     Inter Regular 42, line box 1.153). The footer's city (247:8404) is the
     bar's pair on navy. ADR-0030 §1–§3. */
  --adv-nav-city-size:  24px;
  --adv-nav-city-lh:    25px;
  --adv-hero-city-size: 42px;
  --adv-hero-city-lh:   1.153;
  /* [design] How far a city may run (MD, 2026-09-17; ADR-0030 Amendment 1 §5).
     The hero city's box is at most 300: a compound name wraps inside it, a
     single long word drops to the tight size (and, past that, is fitted by
     the theme's script). The bar's city is at most 243, and a longer name
     shrinks its type to fit. */
  --adv-hero-city-max-w:      300px;
  --adv-hero-city-size-tight: 30px;
  --adv-nav-city-max-w:       243px;

  /* ---------- Motion [kept] ----------
     The Figma file carries no prototype transitions, so there is nothing to
     measure and any value here would be invention. Carried over from v1.
     Provenance differs from its neighbours on purpose — see ADR-0014 §6.
     --adv-transition-logo-slide is not a measurement either: it is a PRODUCT
     DECISION (MD, 2026-09-17 — the client asked for a slower slide), the Home
     logo's travel into the bar, twice the 240 it had (ADR-0030 Amendment 2). */
  --adv-transition-fast:       0.15s;
  --adv-transition-logo-slide: 0.48s;
  --adv-ease:                  ease;

  /* ---------- Z-index ---------- */
  --adv-z-dropdown: 20;
  --adv-z-header:   50;

  /* =====================================================================
     Operator Console layer [authored, ADR-0016] — v1.0.0 of the layer,
     derives from the base set above. Design source: Claude Design project
     "Обновление консоли на токены D1".

     WHY THIS LAYER EXISTS. The console shares the Adverit visual system but
     is an operational tool, not a marketing surface. Three things the site
     scale cannot give it:

       1. Density. The site type scale steps 14 → 16px. A registry row needs
          11/12/13/14, and a mono column header needs 10.5.
       2. Control shape. The site's controls are pills. At a 32px control
          height in a dense toolbar a pill reads as a tag, not a field, and
          it eats the 3px active edge on a nav item. The console uses 6px.
       3. Zoning. The site is flat: fill + 1px border. A console needs
          page / nav / panel to be three distinguishable planes so a table
          reads as a table — surface-alt against the page is 1.04:1, which
          is not a plane.

     This layer introduces NO new colour: every value resolves to a base
     token or a color-mix of one, so the palette stays single-sourced and a
     brand change still propagates. It is a sanctioned divergence in the
     same sense as the retained raised/dropdown shadows (ADR-0014 §6).

     RULES
     - Console components consume --adv-console-* and base tokens ONLY.
       No raw hex, rgba, or px outside the scale.
     - The deprecated aliases (tint, faint, muted, border-soft,
       radius-button/md/lg/xl, tint-edge, link) MUST NOT appear in console
       code. Their v2 remapping is what this layer exists to undo.
     - Mirror into tokens.scss / tokens.json in the same commit — the
       parity test in packages/ui/src/tokens.test.ts covers this layer.

     CONTRAST — measured, not assumed (sRGB, WCAG 2.1); the invariants are
     enforced by tokens.test.ts:
     - Status pill text on its own background: 4.61 (Live) to 6.49
       (Disabled). All pass AA. Live is the floor.
     - Status pill background against a white panel: 1.10 to 1.16. THE
       BORDER IS LOAD-BEARING. A pill without its 1px border is not a pill.
     - On a selected row (#D0DEEC) a pill's own background falls to ~1.2:1
       and Live's text to 3.84 — below AA. Hence pill-on-selected-bg: the
       pill inverts to the panel fill with a full-strength border.
     - --adv-color-ink-muted (#797979) FAILS AA as console text: 4.35 on
       white, 4.14 on the page, 3.96 on the nav. It is never used for text
       here — see the ink group.
     ===================================================================== */

  /* ---------- Console surfaces ----------
     Three planes, all from the base neutrals. The console inverts the
     site's card convention: panels are WHITE and the chrome is the warm
     grey, because in a data view the content plane must be the brightest
     thing on screen. */
  --adv-console-page:            var(--adv-color-surface);      /* #FAF9F7 view background */
  --adv-console-panel:           var(--adv-color-white);        /* tables, cards, overlays, menus */
  --adv-console-nav:             var(--adv-color-surface-alt);  /* #F5F4F2 sidenav + topbar */
  --adv-console-inset:           var(--adv-color-surface);      /* wells inside a panel: stepper band, code blocks */

  /* ---------- Console rules ----------
     Two weights only. `rule` is structural (panel edge, table head/foot),
     `rule-soft` is the row divider — it replaces border-soft, which in v2
     resolves to the card fill and therefore draws nothing. */
  --adv-console-rule:            var(--adv-color-border);       /* #DAD6D0 */
  --adv-console-rule-soft:       color-mix(in srgb, var(--adv-color-border) 55%, var(--adv-color-white)); /* #EBE8E5 */

  /* ---------- Console interaction surfaces ----------
     hover and selected must never be the same value: an operator scanning
     a table needs "where is my cursor" and "what did I pick" to be
     different questions. The site's own hover token is surface-alt and its
     own active token is accent-light-blue — the brand's language, not a
     new one. */
  --adv-console-row-hover:       var(--adv-hover-surface);      /* #F5F4F2 */
  --adv-console-row-selected:    var(--adv-active-surface);     /* #D0DEEC */
  --adv-console-selected-edge:   var(--adv-active-edge);        /* #2B68A9 — 4.2:1 on the fill, non-text */
  --adv-console-accent-wash:     color-mix(in srgb, var(--adv-color-primary) 8%, var(--adv-color-white)); /* #EEF3F8 — card/quick-action hover */

  /* ---------- Console ink ----------
     TWO text levels, not three. --adv-color-ink-muted (#797979) fails AA
     at every console size on every console surface (see header) — the
     third level is carried by TYPE instead: mono family, uppercase,
     10–11px, 0.08–0.14em tracking. That reads as "metadata" without asking
     the eye to resolve low-contrast grey, and it survives a user zooming
     or a high-contrast OS setting.

     ink-faint exists for NON-TEXT only — a disabled glyph, a decorative
     stroke, a select arrow. Never put a word in it. */
  --adv-console-ink:             var(--adv-color-ink);          /* #3C3C3C  11.03:1 on panel */
  --adv-console-ink-body:        var(--adv-color-body);         /* #51595F   7.13:1 on panel */
  --adv-console-ink-meta:        var(--adv-color-body);         /* metadata: same value, mono/uppercase carries the level */
  --adv-console-ink-faint:       var(--adv-color-ink-muted);    /* #797979 NON-TEXT ONLY — fails AA for copy */
  --adv-console-ink-on-accent:   var(--adv-color-on-navy);      /* #FAFBFC  5.54:1 on primary */

  /* ---------- Console accent ----------
     accent for non-text and for text on the panel (5.74:1). On a selected
     row primary drops to 4.2:1, so text there takes accent-strong. */
  --adv-console-accent:          var(--adv-color-primary);      /* #2B68A9 */
  --adv-console-accent-strong:   var(--adv-color-primary-dark); /* #122448 — text on selected/wash surfaces */

  /* ---------- Console status ----------
     The taxonomy itself is unchanged (ADR-0007) — this only adds the
     neutral the set was missing: StatusPill's `disabled` variant filled
     with border-soft on a border-soft-adjacent panel, i.e. an invisible
     pill. */
  --adv-console-neutral-fg:      var(--adv-color-body);         /* 6.49:1 on the fill */
  --adv-console-neutral-bg:      var(--adv-color-surface-alt);
  --adv-console-neutral-border:  var(--adv-color-border);
  /* A pill sitting on a selected row inverts: fill becomes the panel,
     border goes to full strength. A modifier, not a second palette. */
  --adv-console-pill-on-selected-bg: var(--adv-color-white);

  /* ---------- Console feedback ----------
     One focus ring for the whole console. Replaces five hand-copied
     rgba(0, 77, 133, 0.1) declarations built on the pre-v2 primary, plus a
     sixth at 0.12 on the login screen. The scrim replaces two literals on
     the retired #04243F navy (Overlay, mobile nav). */
  --adv-console-focus:           0 0 0 3px color-mix(in srgb, var(--adv-color-primary) 20%, transparent);
  --adv-console-scrim:           color-mix(in srgb, var(--adv-color-primary-dark) 42%, transparent);

  /* ---------- Console radii ----------
     Controls are 6px. Panels keep the brand's 12px, so a dialog still
     reads as an Adverit surface. Pills stay pills — radius-pill is a live
     base token and did not change; status pills, tags, counters and
     avatars all keep it. */
  --adv-console-radius-control:  6px;                           /* button, field, select, kebab, nav item, toast, callout, menu panel */
  --adv-console-radius-inset:    4px;                           /* menu item, segmented tab, language chip */
  --adv-console-radius-panel:    var(--adv-radius-card);        /* 12px — panel, dialog, card */

  /* ---------- Console type scale ----------
     Six steps. Every one replaces at least two literals in the pre-AD-77
     code. 2xs/3xs are mono-only: uppercase, tracked, metadata. */
  --adv-console-text-3xs:        10px;    /* nav group label, build stamp */
  --adv-console-text-2xs:        10.5px;  /* table column header, language chip */
  --adv-console-text-xs:         11px;    /* KV label, timestamps, hints */
  --adv-console-text-sm:         12px;    /* status pill, tag, counter, segmented tab, button sm */
  --adv-console-text-md:         13px;    /* table cell, menu item, field text, button */
  --adv-console-text-lg:         14px;    /* record name, nav item, dialog body */
  --adv-console-title:           var(--adv-h3-size);  /* 22px page h1 — was 25px in registries, 27px on the dashboard */
  --adv-console-metric:          32px;    /* StatCard number — was 34px */

  /* ---------- Console spacing ----------
     The site scale has no step between 8 and 12, and the console's dense
     clusters need 6 and 10. Named here rather than added to --adv-space-*
     so the site scale stays a transcription of the design. */
  --adv-console-gap-1:           6px;
  --adv-console-gap-2:           10px;
  --adv-console-gap-3:           var(--adv-space-12);
  --adv-console-gap-4:           var(--adv-space-16);
  --adv-console-gap-5:           var(--adv-space-24);

  /* ---------- Console metrics ----------
     Control heights were never tokenised, so they drifted to 30, 32, 34
     and 36px on one toolbar. Two values, not one: a control with a text
     label is 32px, an icon-only control is 30px so it does not outweigh
     the field next to it. Row height stays with the shell — it is
     padding-derived and pinning it would fight the stacked mobile row. */
  --adv-console-control-h:       32px;   /* field, select, button, segmented tab, icon tile */
  --adv-console-icon-h:          30px;   /* icon-only control: kebab, dialog close, row action */
  --adv-console-topbar-h:        60px;   /* brandbar + topbar — was a literal --topbar in .shell */

  /* ---------- Console elevation ----------
     Reuses the two console-only shadows already sanctioned in ADR-0014 §6.
     Nothing new: a flat design plus a floating dialog needs exactly these. */
  --adv-console-shadow-panel:    var(--adv-shadow-raised);
  --adv-console-shadow-pop:      var(--adv-shadow-dropdown);

  /* =====================================================================
     Mobile layer [read + authored, ADR-0017] — the 402px tier.

     Measured off the mobile frames in "Adverit.fig", page "Master &
     Satellite actual" (added to the file 2026-08-25; inventory in
     docs/design-map.md §3a/§4b), via the Claude Design project "Adverit
     Mobile Foundations". The file still binds ZERO variables and ZERO
     text styles, so every value is read off a node — node ids inline —
     or marked AUTHORED where the file is silent (states, touch).

     NO new colour, same constitution as the console layer: every colour
     here resolves to a base token or a color-mix of one. That includes
     the menu-row ink, which the handoff flags as "not in the desktop
     palette" — rgb(81,89,95) is exactly #51595F, i.e. color-body
     ("Text Secondary"). The handoff is corrected, not followed, there.

     Geometry the layer introduces: ONE new radius (8px mobile cards —
     ADR-0014 §5's "exactly two radii" is amended to two per tier; glass
     tiles, full-bleed media and panels keep the brand 12px). The kit's
     drawn 66/70/78px pill literals clamp to half-box and are transcribed
     as radius-pill, the same reading §5 gave the desktop button's 66.

     Focus adds NOTHING: the authored mobile ring (2px primary at 2px
     offset) is exactly the base --adv-focus-ring set from ADR-0014 §4.
     ===================================================================== */

  /* ---------- Breakpoints [authored] ----------
     The file draws 402 and 1440 and nothing between, so the steps are
     ours (ADR-0017 §2). CSS @media cannot read var() — these tokens are
     the canonical record and the JS/JSON consumable; the literals in the
     stylesheets MUST match them.
       condense: margins 60→26, display sizes clamp, dropdown stacks
       nav:      nav collapses to the toggle; BODY STEPS TO 14/25 (the
                 handoff's own boundary for the body step)
       mobile:   single column, 20px margin, mobile button mapping,
                 8px cards — where the 402 frames apply
       frame:    the design width itself — where the 600/60/660 split the
                 display line budget is measured against actually exists

     THE FIRST THREE ARE `max-width` LITERALS AND THE FOURTH IS NOT, because
     the first three mark degradations at and below a step while `frame` marks
     where the frame BEGINS. This file has no `min-width` layer (ADR-0021 §3
     and §9), so the one rule that uses it is an UNDO and its literal is 1439,
     one under this token. */
  --adv-bp-condense:    1100px;
  --adv-bp-nav:         860px;
  --adv-bp-mobile:      560px;
  --adv-bp-frame:       1440px;

  /* ---------- Frame & grid [read] ----------
     The tier is drawn at 402, NOT 390. Content is 362 between two 20px
     margins — every band, card and control on 597:19805 starts at x=20
     and is 362 wide. Supersedes the space-26 the responsive CSS relaxed
     to below 1100 (that step keeps 26; the ≤mobile step takes 20). */
  --adv-m-frame:        402px;
  --adv-m-margin:       20px;
  --adv-m-content:      362px;

  /* ---------- Header (1537:19420, 1537:19045 — every page, both tiers) ----------
     The bar is the logo tile's height, 88: a 220 × 88 tile centred, the
     wordmark inside 162.9 × 59.3 (top ≈ 14.3). It was 72 with a 150 × 60
     tile and a 40-high wordmark (597:19805) until the 2026-09-17 frames; MD
     took 88 for every page, not only Home (ADR-0030 Amendment 1 §7). The
     menu toggle is a 20px glyph at x=362, y=26 — hard against the margin,
     not a 60px tile; its 44px hit area is authored AROUND it (see touch).
     The satellite's city sits under the wordmark's left edge at 16 regular
     (1537:19432). On the Home tops the large lockup's tile is 295 wide
     (1537:18130, 1537:19268; the wordmark inside is 218.5). */
  --adv-m-header-h:     88px;
  --adv-m-logo-tile-w:  220px;
  --adv-m-logo-tile-h:  88px;
  --adv-m-logo-h:       59.3px;
  --adv-m-hero-logo-w:  295px;
  --adv-m-nav-city-size: 16px;
  --adv-m-toggle:       20px;

  /* ---------- Type [read] ----------
     The display end contracts to ONE number — 38 carries both the hero
     (weight 800) and every band headline (weight 700) — and the BODY
     STEP DROPS TO 14/25px (desktop 16/25). 16 survives only as the
     uppercase section label (desktop 24). Card titles 22, ink not navy. */
  --adv-m-hero-size:    38px; --adv-m-hero-weight: 800; --adv-m-hero-lh: 1.1;   /* 597:19805 */
  --adv-m-title-size:   38px; --adv-m-title-weight: 700; --adv-m-title-lh: 1.1; /* band headline */
  --adv-m-card-title:   22px; --adv-m-card-title-lh: 1.1;                       /* 754:38390 */
  --adv-m-lede-size:    18px; --adv-m-lede-lh: 1.35;                            /* desktop 24 · 1.5 */
  --adv-m-label-size:   16px; --adv-m-label-weight: 500;                        /* uppercase maroon */
  --adv-m-body-size:    14px; --adv-m-body-lh: 25px;                            /* the step change */
  --adv-m-tag-size:     14px;                                                   /* tag size=big */
  --adv-m-tag-compact:  10px;                                                   /* tag size=compact — smallest step in the system */
  /* The master Home's 402 headline (1537:18130) is 600 on a 0.99 line box,
     centred — Home only; every other 402 head keeps --adv-m-hero-weight. The
     satellite Home's city under its lockup is 26 on the desktop city's line
     box (1537:19312). ADR-0030 Amendment 1 §7. */
  --adv-m-home-title-weight: 600; --adv-m-home-title-lh: 0.99;
  --adv-m-hero-city-size: 26px;

  /* ---------- Button (597:19957) ----------
     Height 50, pill (drawn 66), padding 14/26, label 14/25 medium. Two
     widths: long fills the 362 measure, short is 171 so two sit in a row
     with 20 between. THE FILL LOGIC INVERTS ON MOBILE — `main` is the
     OUTLINED button (1px border-strong, navy label, no fill) and only
     `accent` carries a fill. Do not reuse the desktop class. No
     accent+short variant exists — three variants, not four. */
  --adv-m-btn-h:        50px;
  --adv-m-btn-long:     362px;
  --adv-m-btn-short:    171px;
  --adv-m-btn-pad:      14px 26px;
  --adv-m-btn-radius:   var(--adv-radius-pill);   /* drawn 66 — clamps, a pill (ADR-0014 §5 reading) */

  /* ---------- Hero search (Group 186, 664:24579) ----------
     A 362 × 56 pill both mobile homepages float on the hero photograph:
     a 70% ink wash with its own 56 × 56 round button. A WASH, not a
     surface — on a light page it disappears (same warning as glass). */
  --adv-m-search-h:     56px;
  --adv-m-search-fill:  var(--adv-on-media-fill); /* rgba(60,60,60,.7) — the desktop on-media wash, unchanged at 402 */
  --adv-m-search-btn-fill: var(--adv-on-media-btn-fill); /* rgba(60,60,60,.3) — 681:27546; see the note on the base token */
  --adv-m-search-btn:   56px;
  --adv-m-search-radius: var(--adv-radius-pill);  /* drawn 78 / button 70 — both clamp */

  /* ---------- Quick-link tile (597:19805) ----------
     Same glass as desktop — the 10% white wash over the 10px blur — at
     57 tall, keeping the brand 12px radius (NOT the 8px mobile card). */
  --adv-m-tile-h:       57px;
  --adv-m-tile-radius:  var(--adv-radius-card);

  /* ---------- Radii [read] ----------
     The one new geometry value in the layer: the mobile card set rounds
     at 8. 12 stays on glass tiles, full-bleed media and panels, so both
     live on a phone — ADR-0014 §5 amended, see ADR-0017 §4. */
  --adv-m-radius-card:  8px;

  /* ---------- AUTHORED: touch ----------
     The file states no hit area and its visible boxes are below any
     floor (menu row 25 tall, toggle 20, tickbox 16). The target is a
     44px hit area AROUND the visual box — padding or a pseudo-element,
     never a resize. The menu stack is 25 + 26 = 51 pitch, so 44 fits
     with no neighbour overlap. */
  --adv-m-touch-min:    44px;

  /* ---------- AUTHORED: button states ----------
     The file has no hover, pressed, focus or disabled anywhere. Derived
     from the desktop behaviour the system already records, so mobile
     inherits the brand's logic rather than a new one. main is already
     the outlined form on mobile, so its pressed state is desktop main
     AT REST — navy fill, light label. accent presses to the desktop
     accent HOVER — burgundy — since the accent itself became navy on
     2026-09-16 (Button 247:8285, hover 498:5691) and its old press, one
     step down to blue-deep, would now read as a lighter button under the
     finger (ADR-0024 §2). Disabled is the desktop inactive recipe verbatim. */
  --adv-m-btn-main-pressed-bg:    var(--adv-color-primary-dark);
  --adv-m-btn-main-pressed-ink:   var(--adv-color-on-navy);
  --adv-m-btn-accent-pressed-bg:  var(--adv-hover-accent);
  --adv-m-btn-disabled-bg:        var(--adv-disabled-bg);
  --adv-m-btn-disabled-border:    var(--adv-disabled-border);
  --adv-m-btn-disabled-ink:       var(--adv-disabled-text);

  /* ---------- Tickbox (filter rows) ----------
     The file draws the checked mark as a 10 × 10 rect with NO fill — it
     renders invisible (authoring slip #3, flagged to design). Authored
     to primary, matching the tag's active edge. */
  --adv-m-tick-box:     16px;
  --adv-m-tick-radius:  2px;
  --adv-m-tick-border:  var(--adv-color-border);
  --adv-m-tick-mark:    var(--adv-color-primary);

  /* ---------- Category tag, active ----------
     The same active surface the desktop set uses — the brand's own
     interaction language, not a mobile invention. size=compact,
     state=active is undrawn in the file (authoring slip #1): authored
     as the big-active recipe at compact padding. */
  --adv-m-tag-active-bg:      var(--adv-active-surface);   /* #D0DEEC */
  --adv-m-tag-active-border:  var(--adv-active-edge);      /* #2B68A9 */
  --adv-m-tag-active-ink:     var(--adv-active-text);      /* #122448 */

  /* ---------- Menu rows (623:23275) ----------
     25-tall text rows on a 26 stack — a text list, not 56px tap rows;
     the 44px target comes from touch-min. Row ink is color-body: the
     handoff calls rgb(81,89,95) foreign, but it IS #51595F, Text
     Secondary — corrected, see the layer header. state=active is
     authored to 14/500 (the file's 13px variant is authoring slip #2). */
  --adv-m-row-ink:      var(--adv-color-body);
  --adv-m-row-size:     14px;
  --adv-m-row-active-weight: 500;

  /* ---------- Rhythm [read] ----------
     Read off the homepage band stack. The desktop 96/26 pair does not
     appear on mobile. 34 and 24 exist on the base scale and are
     referenced; 20 does not (it is the mobile margin recurring as a
     stack gap) and stays a layer literal. */
  --adv-m-band-gap:     var(--adv-space-34);  /* between bands */
  --adv-m-head-gap:     var(--adv-space-24);  /* inside a band's head */
  --adv-m-stack-gap:    20px;                 /* between stacked controls */
  --adv-m-tile-gap:     var(--adv-space-16);  /* between tiles */
  --adv-m-chip-gap:     var(--adv-space-8);   /* between chips */
  /* The DETAIL pages run on 54, not the homepage's 34 (681:27056, 704:30027,
     750:35822, 760:8044): bar → title, title → body, block → block. Not on the
     base scale, so a layer literal like the stack gap (AD-185). */
  --adv-m-detail-gap:   54px;                 /* between the blocks of a detail page */

  /* =====================================================================
     SATELLITE TIER  --adv-sat-*                            [ADR-0018, Proposed]

     WHY A LAYER AND NOT MORE BASE TOKENS. The two tiers share one token
     namespace, and that has now produced the same bug twice. Correcting the
     satellite hero's size would have resized five unrelated empty-state plates,
     because they had borrowed `--adv-hero-size` for being the largest number in
     the file (fixed by `--adv-monogram-size`). And the satellite's band
     headings are navy in the file while `.adv-display` defaults to body ink —
     the master's reading, inherited by a tier that never agreed to it.

     A flat namespace cannot express "this belongs to one tier". This layer can,
     and it is the same device already used twice: `--adv-console-*` (ADR-0016)
     and `--adv-m-*` (ADR-0017).

     SCOPE. Only values the satellite frames prove differ from the shared
     default, or that no other consumer should ever read. NOT a copy of the
     palette — everything the tiers agree on stays in the base tokens above and
     a brand change still propagates.

     THIS LAYER INTRODUCES NO NEW COLOUR: `heading-ink` resolves to a base
     token, exactly the rule the console layer follows.

     RULES
     - Satellite components consume --adv-sat-* and base tokens ONLY.
     - Nothing outside the satellite tier may read --adv-sat-*. If a value is
       wanted elsewhere it belongs in the base scale, not borrowed from here —
       that borrowing is what this layer exists to stop.
     - Mirror into tokens.scss / tokens.json in the same commit; the parity
       test in packages/ui/src/tokens.test.ts covers this layer.
     ===================================================================== */

  /* ---------- Heading ink [figma] ----------
     Every heading on the tier binds `corporate/navy`, checked on four nodes
     across three screens: the hero h1 (896:9764), both homepage band headings
     (896:9774 "Discuss your questions…", 896:9849 "Let's discuss how we can
     help.") and the listing h1 (343:11445). The listing already got there
     through `.adv-page-head .adv-page-title`; the other three did not.

     This replaces `--adv-color-hero-ink` (#112B3D), which was marked [measured]
     as "the one value in neither source's token list". It is in the list now,
     and a bound variable beats a value read off a render — the precedence rule
     AD-75 recorded for `.adv-area-card__count`. */
  --adv-sat-heading-ink:     var(--adv-color-primary-dark);  /* #122448 */

  /* ---------- Homepage hero — RETIRED in 2.9.0 ----------
     `--adv-sat-hero-*` (size, lh, weight, measure, measure-tier, size-tight,
     intro-pad, photo-gap, cta-gap) served the photograph hero of 896:9755 and
     its one consumer, `.adv-hero-title`. The 2026-09-16 Home (1484:36469)
     opens on the split hero and the wordmark lockup instead (ADR-0030 §2), so
     the layer went with the component rather than being left to rot. */

  /* ---------- About / "our approach" (336:11104) ----------
     Label box bottom to the first row's box top. THE FRAME SAYS 54 AND THIS IS
     56, and the 2 is not a fudge — it is the label's line box.

     336:10867 ("our approach") is 190 x 29 at 24px, i.e. AUTO leading (24 x 1.21
     = 29.04), so 2.5px of half-leading sits inside the box under the glyphs. Our
     `.adv-section-label` still carries `--adv-label-lh: 1`, so its box is 24 and
     ends level with the glyphs. Box to box the frame is 54 (757 -> 811); glyph to
     box it is 56.5, and 56 is what puts our shorter box where the frame puts its
     text.

     So this number is CONDITIONAL on `--adv-label-lh` — the sixth AUTO-read-as-1
     in this file, and the one still outstanding. Correct that token and this
     becomes 54. It is not corrected here because `.adv-section-label` is every
     band label on BOTH tiers, and the master's were measured against lh 1 the day
     before; that is its own change, not a side effect of an About spacing fix. */
  --adv-sat-approach-gap:    56px;   /* label to the first approach row */

  /* ---------- The tier's text measure inside the 660 column ----------
     550, and it is not one block's number — it is the same measure in two
     unrelated places, both sitting in the right-hand 660 column of the same
     600/60/660 grid:

       - About's approach copy: all four nodes (336:10875, 336:10879, 336:10886,
         336:11080) are x=660 w=550 against a column that runs to 660. The 110 of
         slack is what wraps each step to two lines and gives the row its 50px
         height.
       - Every LISTING head's lead: 343:11446 (practice areas), 343:12287
         (services) and 385:3687 (insights) are all x=720 w=550. 343:11855
         (experts) is 557 — one box out of four, 7px off three that agree, which
         reads as a handle nudged rather than a second intent.

     A MEASURE, NOT A COLUMN — the same distinction `--adv-sat-hero-measure`
     records. Left to the column the text runs the full 660 and each block wraps
     wherever its own sentence happens to run out.

     NOT About's own head, which is 660 (336:10815 — the full column). That head
     is a different composition and keeps the column as its measure; only the
     listings cap. */
  --adv-sat-measure: 550px;

  /* =====================================================================
     E-MAIL  --adv-email-*                                   [ADR-0049]
     The two numbers an HTML e-mail needs that no page does (AD-180).
     scripts/authentik-mail.mjs writes Authentik's invitation and reset
     e-mails from tokens.json as inline styles — mail clients drop custom
     properties — so these exist here for lock-step, not for a stylesheet.
     ===================================================================== */
  --adv-email-width:  600px;   /* the one column every mail client renders unscaled */
  --adv-email-logo-w: 160px;   /* the wordmark's display width; its PNG is 2x */
}

/* Brand text selection */
::selection { background: var(--adv-color-accent-light-blue); }
/* =====================================================================
   Adverit Legal — Base layer
   ---------------------------------------------------------------------
   Element resets, body defaults, typography utilities and layout helpers
   built entirely on tokens.css. Import order in any consumer:

       @import "../tokens/tokens.css";
       @import "fonts.css";
       @import "base.css";
       @import "components.css";

   Fonts moved out to fonts.css and are now SELF-HOSTED (ADR-0014). This
   file used to @import three families from fonts.googleapis.com, with a
   note suggesting self-hosting "for performance". Performance was the
   lesser problem: it put a request carrying every visitor's IP to a
   third-country host on every page load of every firm site, against the
   EU data-residency Immutable Rule. Do not reintroduce it.
   ===================================================================== */

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

html { scroll-behavior: smooth; }

/* THE FOOTER SITS ON THE VIEWPORT'S FOOT (AK, 2026-08-31). A short page — the
   search entry screen is the one that prompted this, and 896:9585 draws exactly
   it: a 1024 frame with the footer at 741 — otherwise ends its footer wherever
   the content happens to stop, leaving the page surface below it and the footer
   reading as a band that failed to load rather than as the end of the document.

   AUTHORED HERE AND NOT PER SCREEN. It is a property of the DOCUMENT, both
   themes render the same `header / main / footer` skeleton, and on any page
   taller than the viewport the rule does nothing at all — `min-height` is a
   floor, and `flex: 1 0 auto` lets main grow past it. A per-page version would
   have to be remembered by every short page anyone adds later.

   `100dvh` with a `100vh` fallback: on a phone `vh` is the LARGEST viewport,
   chrome retracted, so it overshoots by the height of the address bar and puts
   the footer just below the fold — the exact thing this rule exists to prevent.

   `min-height`, never `height`: the latter would make the body a fixed box and
   long pages would overflow it. And `flex: 1 0 auto` rather than `1 1 auto`,
   because a shrinkable main would let a tall page's content compress instead of
   the page scrolling. */
body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--adv-bg);
  color: var(--adv-text);
  font-family: var(--adv-font-body);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
body > main { flex: 1 0 auto; }

a { color: var(--adv-link-color); }

/* Accessible focus ring — visible, brand-coloured, never removed outright */
:focus-visible {
  outline: 2px solid var(--adv-focus-ring);
  outline-offset: 2px;
}

/* ---------- Typography utilities ----------
   Class-based so non-semantic markup can opt in; the same rules also
   apply to bare h1–h4 inside .adv-prose. */

.adv-h1 {
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h1-size);
  line-height: var(--adv-h1-lh);
  letter-spacing: var(--adv-h1-ls);
  color: var(--adv-text);
  margin: 0;
}
.adv-h2 {
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h2-size);
  line-height: var(--adv-h2-lh);
  letter-spacing: var(--adv-h2-ls);
  color: var(--adv-text);
  margin: 0;
}
.adv-h3 {
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h3-size);
  line-height: var(--adv-h3-lh);
  letter-spacing: var(--adv-h3-ls);
  color: var(--adv-text);
  margin: 0;
}
.adv-h4 {
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h4-size);
  line-height: var(--adv-h4-lh);
  letter-spacing: var(--adv-h4-ls);
  color: var(--adv-text);
  margin: 0;
}
.adv-lead {
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-regular);
  font-size: var(--adv-lead-size);
  line-height: var(--adv-lead-lh);
  color: var(--adv-text-body);
  margin: 0;
}
.adv-body {
  font-family: var(--adv-font-body);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-text-body);
  margin: 0;
}
.adv-small {
  font-family: var(--adv-font-body);
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-text-muted);
  margin: 0;
}
.adv-eyebrow {
  font-family: var(--adv-font-mono);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-eyebrow-size);
  line-height: var(--adv-eyebrow-lh);
  letter-spacing: var(--adv-eyebrow-ls);
  text-transform: uppercase;
  color: var(--adv-color-link);
  margin: 0;
}

/* Bare heading mapping for prose blocks */
.adv-prose h1 { font: var(--adv-weight-semibold) var(--adv-h1-size)/var(--adv-h1-lh) var(--adv-font-heading); letter-spacing: var(--adv-h1-ls); }
.adv-prose h2 { font: var(--adv-weight-semibold) var(--adv-h2-size)/var(--adv-h2-lh) var(--adv-font-heading); letter-spacing: var(--adv-h2-ls); }
.adv-prose h3 { font: var(--adv-weight-semibold) var(--adv-h3-size)/var(--adv-h3-lh) var(--adv-font-heading); letter-spacing: var(--adv-h3-ls); }
.adv-prose h4 { font: var(--adv-weight-semibold) var(--adv-h4-size)/var(--adv-h4-lh) var(--adv-font-heading); }
.adv-prose :is(p, li) { font-size: var(--adv-body-size); line-height: var(--adv-body-lh); color: var(--adv-text-body); }

/* ---------------------------------------------------------------------
   PROSE LISTS, AND THE BLOCK RHYTHM THAT WAS NEVER AUTHORED
   (MD, 2026-09-09 — AD-128, ADR-0023)

   The mapping above covered headings and paragraphs and NOTHING ELSE, so a
   list inside a prose block arrived at browser defaults: `disc` at a 40px
   indent, a 1em block margin, and a colour inherited from `body`
   (--adv-text) rather than the --adv-text-body the paragraph beside it takes
   one line up. Two greys in one body of copy, in the same column. This is
   not hypothetical and it did not arrive with AD-128 — 116 firm article
   bodies under sites/ already end in a bulleted list, and they have rendered
   this way since the demo firms were seeded.

   THE PARAGRAPH MARGIN IS NOT MERELY UNSET — IT IS TRAPPED. Every container
   a prose block sits in is a flex item (.adv-detail__body, .adv-stack,
   .adv-expert-bio__block, .adv-split-media__body), and a flex item is an
   independent formatting context: the first paragraph's 1em cannot collapse
   out of the block, so it is ADDED to the container's own gap. The master's
   About and Join bands are drawn on a 34 rhythm (279:2389), declare
   --adv-space-34, and render 50. Zeroing the block-start and paying the
   rhythm at the block-end is what makes a container's declared gap the
   distance you actually see.

   THE HEADINGS ARE IN THE RHYTHM because they are in the mapping. Left out,
   `h1`–`h4` kept browser margins — em-relative and so arbitrary at every step
   (23.24 under an h2, 22 under an h3, beside a deliberate 24) — and a prose
   block that OPENS on a heading kept a trapped top margin, which is the whole
   defect the block-start zero exists to remove. Naming them here costs nothing
   and closes the one hole the enumeration left open. `blockquote`, `table`,
   `pre`, `hr`, `dl` and `figure` are still out: they carry no mapping above, so
   the boundary is the same one the mapping draws.

   24 AND 8 ARE THE TWO STEPS tokens.css MARKS `[kept]`. Every other step is
   `[read]` and carries the job it was measured from — 26 is control and card
   padding-inline, 34 is card padding-block, 40 is nav item padding-inline.
   Prose is none of those, and borrowing a measured step for an unmeasured
   job is how a scale stops meaning anything (rule 5). 24 is also the nearest
   step to the 25px line box (16 x 1.5625), so a paragraph boundary reads as
   one blank line, and it stays a clear 10 under the 34 that separates the
   whole block from the composition around it. 8 is a third of 24: an item
   boundary a third the weight of a paragraph boundary is what keeps an
   eight-item list reading as ONE block subdivided rather than as eight short
   paragraphs. AD-128 bracketed this at 0 to 16 and 16 was declined on that
   ratio — at 16 an item costs two thirds of a paragraph. 24 for the indent
   too: the smallest step that keeps a `disc` inside the box, against 40,
   which is only the browser's number and 6% of the 660 measure.

   THE MARGINS ARE CHILD-SCOPED AND THE INDENT IS NOT, deliberately.
   Indentation is per level, so a nested list must indent again and the
   selector has to reach it. Block rhythm belongs to the top-level flow only,
   so `>` stops a nested list paying a paragraph-sized gap inside its parent
   item.

   `li > :is(p, ul, ol)` IS WHAT MAKES A LOOSE LIST EQUAL A TIGHT ONE, and the
   `>` above is not enough on its own. Goldmark wraps each item of a LOOSE list
   (blank lines between the bullets) in a `<p>`; that `<p>` is not a child of
   the sink, so the rhythm rule misses it — but the BROWSER's 1em does not. Left
   alone it collapses with `li + li` to max(1em, 8) and reappears below the list
   by collapsing out through the `li` and the `ul`, neither of which has block
   padding or a border to stop it, landing past the `:last-child` rule that
   believes it removed exactly that margin. Measured before this line existed: a
   tight list rendered an 8px item gap and no tail, the same list written loose
   rendered 14 and a 14px tail. Zeroing it makes the two shapes identical, which
   matters because the 33 bodies are authored in YAML block scalars where a
   blank line between bullets is the readable way to write them. Whoever writes
   the next thirty should not have to know this to get the same page.

   `li + li`, NOT A MARGIN ON EVERY `li`. A block-end margin on the last item
   collapses out of the list — a `ul` here has no block padding or border to
   stop it — and survives the `:last-child` rule below as 8px the rule
   believes it removed, on every one of those 116 articles whose body ends in
   a list. A start margin on all but the first item has nothing to leak.

   `> :last-child` IS UNSCOPED, and it is the general form of a rule
   components.css used to carry as `.adv-article .adv-prose > :last-child` —
   written for the one page that had prose, which is now every page that has
   prose. That copy is DELETED rather than left beside this one: two rules
   declaring the same property and value is an edit to either with no visible
   effect. `.adv-article > :last-child` is a different rule, governs the
   article's own non-prose children, and stays. Without this, the last block's
   margin is trapped in the flex item and added to the gap: 34 + 24 to the
   practice-area page's "Discuss your case".
   --------------------------------------------------------------------- */
.adv-prose > :is(p, ul, ol, h1, h2, h3, h4) { margin-block: 0 var(--adv-space-24); }
.adv-prose :is(ul, ol)      { padding-inline-start: var(--adv-space-24); }
.adv-prose li + li          { margin-block-start: var(--adv-space-8); }
.adv-prose li > :is(p, ul, ol) { margin-block: 0; }
.adv-prose > :last-child    { margin-block-end: 0; }

/* ---------- Layout helpers ---------- */
.adv-container {
  max-width: var(--adv-container);
  margin-inline: auto;
  padding-inline: var(--adv-section-pad-x);
}
.adv-section {
  padding-block: var(--adv-section-pad-y);
}
.adv-grid-12 {
  display: grid;
  grid-template-columns: repeat(var(--adv-grid-columns), 1fr);
  gap: var(--adv-gutter);
}

/* Surfaces */
.adv-surface { background: var(--adv-bg); }
.adv-on-navy { background: var(--adv-color-hero-navy); color: var(--adv-color-on-navy); }

/* ---------------------------------------------------------------------
   THE `hidden` ATTRIBUTE, MADE TO WORK

   `[hidden]` is a User-Agent rule — `display: none` in the UA origin — and
   ANY author `display` declaration beats it, whatever the specificity. Almost
   every component in this system sets `display`, so `el.hidden = true` from
   JS did nothing to a card, a chip row or a filter bar: the element stayed on
   screen while the script believed it was gone.

   That shipped three times before it was understood, each time as a different
   symptom — filters that changed the count but not the grid, a "load more"
   that was always visible, a blank strip above the footer — and each time it
   was patched with one more `.some-component[hidden]` rule. This is the rule
   those were reaching for.

   `!important` is deliberate. The point is to beat every author `display` in
   the sheet, including ones written later by someone who does not know this
   exists — which is precisely the person it protects. An element that wants to
   ignore it should not be using the attribute.
   --------------------------------------------------------------------- */
[hidden] { display: none !important; }
/* =====================================================================
   Adverit Legal — Component layer
   ---------------------------------------------------------------------
   Built only on tokens.css (+ base.css). Class prefix: .adv-*.

   v2 — Phase 1 Design Refresh, authorised by ADR-0014. Every component
   below that carries a `node` comment was read out of Figma with
   get_design_context ("Adverit  Copy" / "Master & Satellite actual"),
   not measured off a render — the earlier fitted values were wrong about
   radius, hover and shadow, and reading the component is what corrected
   them. If you change one of these, read the node again first.

   THE SYSTEM IS FLAT. Nothing in the design casts a shadow: every surface
   is a fill plus a 1px border, and card hover is a transform, not an
   elevation. `--adv-shadow-card` resolves to `none` by design.

   THE INTERACTION LANGUAGE IS SHARED, so it is written once as tokens and
   reused rather than restated per component:
     hover   surface --adv-hover-surface   + text --adv-hover-accent
     active  surface --adv-active-surface  + text --adv-active-text
                                           + edge --adv-active-edge

   Class names are a contract with the themes and packages/ui. Existing
   names are preserved and restyled; components the refresh introduces are
   added alongside. Anything marked [not in Figma] is carried over from v1
   and repointed to the new tokens — it will be revisited when its screen
   is built.
   ===================================================================== */

/* ---------------------------------------------------------------------
   Buttons                                                node 247:8285
   50px tall, pill, Inter Medium 16/25.
   Figma pads the bordered variants 15/27 and the unbordered ones 14/26 —
   the same box, with the border accounted for. Here every variant carries
   a 1px border (transparent where the design has none), so one padding
   value serves all of them and the heights cannot drift apart.
   --------------------------------------------------------------------- */
.adv-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--adv-space-8);
  height: 50px;
  padding-inline: var(--adv-space-26);
  border: var(--adv-border-width) solid transparent;
  border-radius: var(--adv-radius-pill);
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
  /* A button is a label, not a paragraph — the same reason the nav items say
     so. Without it "Contact legal expert" breaks over two lines and the pill
     grows to 80px tall. */
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--adv-transition-fast) var(--adv-ease),
              color var(--adv-transition-fast) var(--adv-ease),
              border-color var(--adv-transition-fast) var(--adv-ease);
}

/* accent — the filled call to action. NAVY SINCE 2026-09-16: the accent
   variant itself was recoloured in the component set (247:8284 is
   corporate/navy), so this is the same variant, not a new one — and its hover
   (498:5691) is corporate/burgundy. It was blue with a navy hover; a navy
   button cannot hover to navy. `--adv-color-primary` does NOT move with it:
   it is still every link, active edge and "Explore ↗" (ADR-0024 §2). */
.adv-btn--primary {
  color: var(--adv-color-on-navy);
  background: var(--adv-color-primary-dark);
}
.adv-btn--primary:hover { background: var(--adv-hover-accent); }

/* main — outlined. Hover is the shared language: soft surface + burgundy. */
.adv-btn--secondary {
  color: var(--adv-color-primary-dark);
  background: transparent;
  border-color: var(--adv-color-border-strong);
}
.adv-btn--secondary:hover {
  background: var(--adv-hover-surface);
  border-color: var(--adv-hover-accent);
  color: var(--adv-hover-accent);
}

/* Disabled binds no variable in any of the six Figma variants, so these are
   measured values (ADR-0014 §5). Label-on-fill is 3.08:1 — below AA, and
   allowed only because WCAG 1.4.3 exempts inactive controls. */
.adv-btn:disabled,
.adv-btn[aria-disabled="true"],
.adv-btn--disabled {
  background: var(--adv-disabled-bg);
  border-color: var(--adv-disabled-border);
  color: var(--adv-disabled-text);
  cursor: not-allowed;
}

/* On a navy or blue surface the filled button inverts. [not in Figma] */
.adv-btn--on-primary {
  color: var(--adv-color-primary);
  background: var(--adv-color-on-navy);
}
.adv-btn--ghost-on-dark {
  color: var(--adv-color-on-navy);
  background: transparent;
  border-color: rgba(250, 251, 252, 0.55);
}
.adv-btn--ghost-on-dark:hover { background: rgba(250, 251, 252, 0.10); }

/* Text button — node 513:4489. Two states, no box. */
.adv-link-more {
  display: inline-flex;
  align-items: center;
  gap: var(--adv-space-8);
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
  color: var(--adv-color-primary);
  text-decoration: none;
}
.adv-link-more::after { content: "\203A"; font-size: 1.2em; line-height: 1; }
.adv-link-more:hover { color: var(--adv-hover-accent); }
/* The master homepage's "Explore …" links are a NORTH-EAST ARROW after body
   copy, not the chevron after a nav-weight label that the firm screens use
   (`ArrowLink` in the reference template: `--type-body` plus "↗"). Different
   glyph, different weight — a modifier rather than a second component. */
.adv-link-more--out { font-weight: var(--adv-weight-regular); }
.adv-link-more--out::after { content: "\2197"; font-size: 1em; }

/* ---------------------------------------------------------------------
   Icon                                    nodes 516:7647, 247:7403
   The Figma kit does contain icons — they are named by meaning ("search"),
   which is why an earlier search for layers called icon/glyph/arrow found
   none. Each ships as several assets differing only in fill; the committed
   SVGs use currentColor instead, so state comes from the colour rules that
   are already written and an icon cannot disagree with its label.
   --------------------------------------------------------------------- */
/* NO BLANKET `fill` HERE. Two families of icon live in this set: filled glyphs
   (search, caret, mail) whose paths carry `fill="currentColor"` of their own,
   and stroked outlines (phone, pin) drawn with `stroke="currentColor"` over a
   root `fill="none"`.

   A CSS `fill: currentColor` on the wrapper beats that root presentation
   attribute — CSS always does — and cascades into the outline's paths, so the
   phone and the map pin rendered as solid dark silhouettes instead of line art.
   The committed assets already state their own paint; this rule only has to
   size them and hand down the colour. */
.adv-icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  flex-shrink: 0;
  color: inherit;
}
/* The exported caret points UP — its path is an apex-at-top triangle, and the
   Figma component rotates it 180° to point down. The asset is kept verbatim, so
   that rotation has to happen here or every caret in the UI is upside down. */
.adv-icon--caret {
  width: 8px;
  height: 8px;
  color: var(--adv-color-nav-caret);
  transform: rotate(180deg);
  transition: transform var(--adv-transition-fast) var(--adv-ease);
}
/* Open: back to the asset's own orientation, i.e. 180° from closed. */
[aria-expanded="true"] > .adv-icon--caret { transform: rotate(0deg); }
@media (prefers-reduced-motion: reduce) {
  .adv-icon--caret { transition: none; }
}
.adv-icon--search { width: 24px; height: 24px; }
.adv-icon--close { width: 8px; height: 8px; }
/* The search tile's ✕ (searchOpen, 1529:12859): 14 across at stroke 1.5 — the
   viewBox is cropped to the stroke, so the box is 15.5. */
.adv-icon--sheet-close { width: 15.5px; height: 15.5px; }

/* ---------------------------------------------------------------------
   Category tag                            nodes 257:1159, 623:21974/5
   Note the active state is not just a recolour: it steps up from
   Inter Regular 14 to Medium 16, which is why the active chip is visibly
   larger (183x45 against 105x37). That is the design's intent, not drift.

   THE PADDING IS 9/15, NOT THE 10/16 THE FRAME APPEARS TO SAY, and the
   difference is where the 1px border lives. Figma draws this stroke INSIDE
   the box: the tag measures 105x37 with its text at x=16 y=10 and 73x17 —
   16+73+16 = 105 and 10+17+10 = 37, with no room left for a rim. A CSS
   `border` sits OUTSIDE the padding box, so transcribing 10/16 literally
   made every tag in the system 2px wider and 2px taller than drawn. Take
   the border out of the drawn inset and both states land exactly:
     inactive  15+73+15+2 = 105   9+17+9+2 = 37
     active    15+151+15+2 = 183  9+25+9+2 = 45
   This is a CORRECTED READING of the same nodes, not a new value — and it
   is worth knowing generally, because every bordered box in this file that
   sizes itself from its content has the same 2px to give back. The controls
   do not: their 60px heights are stated, so the border is absorbed there. */
.adv-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 9px 15px;   /* the drawn 10/16 less the 1px border — see above */
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-pill);
  background: var(--adv-color-surface-alt);
  color: var(--adv-color-ink);
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-regular);
  font-size: var(--adv-small-size);
  /* 17px, not 1. The style the file names on this text says lineHeight 100,
     but the text node it is bound to measures 73x17 — Figma's own box wins
     over its transcription, as it has on every other reading. At `1` the
     inactive tag came out 36 against the drawn 37, and the active state
     (which carries its own 25px line-height) was the only one that fit. */
  line-height: 17px;
  text-decoration: none;
  transition: background var(--adv-transition-fast) var(--adv-ease),
              color var(--adv-transition-fast) var(--adv-ease),
              border-color var(--adv-transition-fast) var(--adv-ease);
}
/* A BADGE CAN ALSO BE A BUTTON — the search page's kind tabs (and, until AD-196, the
   insights listing's scope tags, 430:9032) are a live single-select and a <button> is
   what they are. It needs the cursor
   and the margin reset an <a> gets for free, and it must be EXCLUDED from the
   hover recolour while pressed: the hover rule and the pressed rule below carry
   the same weight, so without the `:not()` the active tag lost its fill under
   the pointer. */
button.adv-badge { margin: 0; cursor: pointer; }
a.adv-badge:hover,
button.adv-badge:not([aria-pressed="true"]):hover,
.adv-badge--hover {
  border-color: var(--adv-hover-accent);
  color: var(--adv-hover-accent);
}
/* `aria-pressed` is for a <button> that toggles; `aria-current` is for the one
   item of a set that is showing. The homepage's practice-area and service chips
   are ANCHORS (they work as links with no JS, see sections/practice-areas.html),
   and an anchor cannot be "pressed" — so both spellings select the same state
   rather than the markup being bent to fit one rule. */
.adv-badge--active,
.adv-badge[aria-current="true"],
.adv-badge[aria-pressed="true"] {
  background: var(--adv-active-surface);
  border-color: var(--adv-active-edge);
  color: var(--adv-active-text);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
}

/* ---------------------------------------------------------------------
   Filter control + panel                    nodes 516:7846, 522:8974
   --------------------------------------------------------------------- */
.adv-filter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 60px;
  padding-inline: var(--adv-space-40);
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-pill);
  background: var(--adv-color-surface);
  color: var(--adv-color-ink);
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
  cursor: pointer;
  transition: background var(--adv-transition-fast) var(--adv-ease),
              color var(--adv-transition-fast) var(--adv-ease),
              border-color var(--adv-transition-fast) var(--adv-ease);
}
.adv-filter:hover {
  background: var(--adv-hover-surface);
  border-color: var(--adv-hover-accent);
  color: var(--adv-hover-accent);
}
.adv-filter[aria-expanded="true"],
.adv-filter--active {
  background: var(--adv-active-surface);
  border-color: var(--adv-active-edge);
  color: var(--adv-active-text);
}
/* The caret follows the label's colour in every state — see .adv-icon. */
.adv-filter .adv-icon--caret { color: currentColor; }

.adv-filter-panel {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-12);
  padding: var(--adv-space-16) var(--adv-space-26);
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-card);
  background: var(--adv-color-surface);
  /* No shadow: the design floats this panel on a border alone. */
}
.adv-filter-panel--columns { flex-direction: row; gap: var(--adv-space-42); }
/* THE SEARCHABLE VARIANT                 `open filter` search=yes (522:9638)
   The component has eight variants across three axes — search, multiple choice
   and expanded (two columns). This is the one the practice-areas listing uses:
   a 40px field above the rows, one column, single choice.

   Padding steps up to 26 on all four sides when the field is there; without it
   the frame uses 16/26. The panel is also given a floor of 306, the frame's
   width — a menu of two short country names would otherwise draw a search box
   barely wider than the word "Search". */
.adv-filter-panel--search {
  min-width: 306px;
  padding: var(--adv-space-26);
}
.adv-filter-panel__search {
  width: 100%;
  height: 40px;
  /* THE 40 IS A FLOOR, NOT A SUGGESTION. The panel is a flex column with
     `max-height: 320px; overflow-y: auto`, and a flex item's `height` is only a
     preference — at the default `flex-shrink: 1` an overflowing panel squeezes
     whatever will squeeze. The rows hold at 25 because their text does; this
     field has no content to stop it, so it collapsed to its 21px min-content
     box. It was visible only where the list is long enough to scroll — the
     four-row Jurisdiction panel next to it stayed 40 — which is exactly why it
     read as one filter being wrong rather than as a rule being wrong. */
  flex-shrink: 0;
  padding-inline: var(--adv-space-12);
  border: var(--adv-border-width) solid var(--adv-color-border);
  /* 4px, not the pill the page-level search field uses: inside a panel that is
     already a 12px card, a pill reads as a second, rounder component. */
  border-radius: var(--adv-radius-xs);
  background: var(--adv-color-surface);
  font-family: var(--adv-font-body);
  font-size: var(--adv-small-size);
  line-height: 1;
  color: var(--adv-color-ink);
}
.adv-filter-panel__search::placeholder { color: var(--adv-color-body); }
/* The same two-ring fault AK spotted on the enquiry form, and the same fix: one
   edge, the active fill, no detached outline. This field is inside a 306px
   panel, where a ring at an offset had even less room to be anything but
   noise. */
.adv-filter-panel__search:focus {
  outline: none;
  border-color: var(--adv-active-edge);
  background: var(--adv-active-surface);
}
/* TICKBOX — `Row 1` tickbox=yes (522:9537, re-read on 529:12257). 19px, radius
   4, surface fill with the light ring.

   SELECTED IS A FILLED NAVY SQUARE, NOT A CHECK (AK, 2026-08-31). We drew a
   light-blue fill with a blue check glyph inside it; 529:12257 draws a NAVY
   19px ring with a 13px navy square inset 3 from the outer edge, and no mark of
   any kind. Navy `#122448`, not the blue `#2B68A9` we used for the ring. The
   402 tier had this right all along — its own rule fills the box and explicitly
   hides the check — so the two tiers were drawing two different controls, and
   the mobile rule needed a comment explaining how it out-specified the desktop
   one. Both are this rule now and the check glyph is gone from the markup.

   The square is two inset shadows rather than a pseudo-element: the same
   `.adv-tick` treatment has to work on `.adv-consent input`, and a replaced
   element has no reliable ::after. Painted over the navy background the rings
   read 1 edge, 2 surface, 13 navy, 2 surface, 1 edge = 19.

   ORDER IS EVERYTHING, AND OURS WAS BACKWARDS (AK, 2026-08-31). Box-shadows
   paint FIRST-ON-TOP, so listing the 3px surface ring first put it OVER the 1px
   navy edge and the edge never appeared — a selected box showed a bare surface
   ring where the frame draws a navy one. The comment here used to claim the
   opposite ("first shadow paints on top, so the 1px navy edge sits over…"),
   which is the right rule applied to the wrong operand: the navy edge was the
   SECOND shadow, i.e. underneath. Rendered both orders side by side at 8x to
   confirm before touching it. The navy edge must be listed FIRST. */
.adv-tick {
  flex-shrink: 0;
  position: relative;
  width: 19px;
  height: 19px;
  border-radius: var(--adv-radius-xs);
  background: var(--adv-color-surface);
  box-shadow: inset 0 0 0 var(--adv-border-width) var(--adv-color-border);
}
.adv-filter-panel__row[aria-selected="true"] .adv-tick {
  background: var(--adv-color-primary-dark);
  box-shadow: inset 0 0 0 var(--adv-border-width) var(--adv-color-primary-dark),
              inset 0 0 0 3px var(--adv-color-surface);
}
/* The count a kind tag carries — "(12)" — is written by the script; empty
   before it runs, so it must not leave a stray gap in the pill. */
[data-kind-count]:empty { display: none; }
/* AND A WORD SPACE WHEN IT IS NOT EMPTY (AK, 2026-09-02). The markup writes
   `All <span data-kind-count>` with a real space between them, and the tag ate
   it: `.adv-badge` is a FLEX container, so the text and the span become two
   anonymous flex items and the whitespace between flex items is discarded. Both
   frames draw the space — 553:13401 "All (13)", 419:3418 "All (188)" — and both
   tiers rendered "All(13)". 4px is that space at Inter 14. */
[data-kind-count]:not(:empty) { margin-inline-start: 4px; }

/* Nothing left after typing. Not `.adv-empty` — that is a page-level block with
   40px of padding; this is one line inside a 306px panel. */
.adv-filter-panel__none {
  margin: 0;
  font-size: var(--adv-small-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-body);
}
.adv-filter-panel__col { display: flex; flex-direction: column; gap: var(--adv-space-12); }
/* Row — node 522:9537. 16/25 in body ink, burgundy on hover, navy Medium when
   selected. The design's tickbox variant is for the master site's multi-choice
   facets; on the satellite a row is a plain label.

   THE UA BUTTON CHROME HAS TO BE RESET HERE. A row is a <button> — it performs
   an action rather than navigating — and an unstyled <button> arrives with a
   grey buttonface fill, a 2px outset border, its own padding, centred text and
   the system font. None of that is overridden by setting a colour and a size,
   so the panel renders as a stack of native grey buttons: the right values on
   the wrong widget. The hero's panel escaped this only because its rows are
   <a> elements. */
.adv-filter-panel__row {
  display: flex;
  align-items: center;
  gap: var(--adv-space-12);
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  text-align: start;
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-regular);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
  white-space: nowrap;
  cursor: pointer;
}
.adv-filter-panel__row:hover { color: var(--adv-hover-accent); }
/* Medium and navy — the selected row steps up a weight, like the category tag
   does. Set on both attributes because the panel's rows use aria-selected while
   a link-based panel elsewhere may use aria-current. */
.adv-filter-panel__row[aria-selected="true"],
.adv-filter-panel__row[aria-current="true"] {
  color: var(--adv-active-text);
  font-weight: var(--adv-weight-medium);
}
.adv-filter-panel__row:focus-visible {
  outline: var(--adv-focus-ring-width) solid var(--adv-focus-ring);
  outline-offset: var(--adv-focus-ring-offset);
}

/* Applied filters — nodes 522:10713 and 431:9328. Chips are borderless here,
   unlike .adv-badge, and the row carries a right-aligned sort control.
   8 BETWEEN THEM, not 12: both frames draw the chips and "Clear all" on one
   8px rhythm (431:9328 — chip ends 392, "Clear all" starts 400). */
.adv-applied-filters {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--adv-space-8);
}
.adv-applied-filters__chip {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px var(--adv-space-16);
  border: none;
  border-radius: var(--adv-radius-pill);
  background: var(--adv-color-surface-alt);
  color: var(--adv-color-ink);
  font-family: var(--adv-font-body);
  font-size: var(--adv-small-size);
  /* 17px, the .adv-badge correction applied to the same text: the frames draw
     the chip 37 tall on 10px padding and no border, so the line box is 17 and
     not the 14 that `1` gives. */
  line-height: 17px;
  cursor: pointer;
}
/* THE `--active` MODIFIER IS GONE (AK, 2026-08-31). It painted every applied
   chip in the blue active tokens — light-blue fill, blue border, navy text — on
   the reading that "on a listing the chip is active by definition" and that
   522:10713 drew the CategoryTag's `active` variant. It does not. 522:10713 and
   431:9328 agree to the pixel and both draw the RESTING look: #F5F4F2, NO
   BORDER, #3C3C3C at Inter Regular 14. Which is right on its own terms — the
   blue active state means "this is the one showing" among peers, and a chip in
   the applied row has no unapplied peers to be distinguished from. The X is
   what makes it a chip; the fill was saying nothing. Only the base class
   remains, so the listings and the search screen now render one chip. */
.adv-applied-filters__chip .adv-icon { width: 8px; height: 8px; color: var(--adv-color-body); }
.adv-applied-filters__chip:hover { color: var(--adv-hover-accent); }
.adv-applied-filters__chip:hover .adv-icon { color: var(--adv-hover-accent); }
.adv-applied-filters__clear {
  border: 0;
  background: none;
  padding: 0;
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
  color: var(--adv-color-primary);
  cursor: pointer;
}
.adv-applied-filters__clear:hover { color: var(--adv-hover-accent); }
.adv-applied-filters__sort { margin-inline-start: auto; }
/* THE CHIPS LINE (AD-143, 431:9291 — the master's insights listing): the applied
   chips, and "Sorted by" at the container's right edge once there are any. The
   engine clears and hides the chip container on every apply, so the sort cannot sit
   inside it; it moves into the slot beside it (site.js, `data-sort-follows-chips`).
   The line is 28 under the row above it where the cluster's other rows are 34 apart
   — the search row since the scope tags left (AD-196, ADR-0059 §5) — and it takes no
   room at all while nothing is applied. */
.adv-chips-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--adv-space-26);
  margin-block-start: calc(28px - var(--adv-space-34));
}
.adv-chips-line:not(:has(> .adv-applied-filters:not([hidden]))) { display: none; }
.adv-chips-line__sort:empty { display: none; }
.adv-chips-line__sort .adv-sort { margin-inline-start: 0; }

/* ---------------------------------------------------------------------
   Search                                    nodes 516:8512, 516:7687
   1320x60 — the container width — with a 60px circular button flush right.
   --------------------------------------------------------------------- */
.adv-search { display: flex; align-items: center; gap: 0; width: 100%; max-width: var(--adv-container); }
.adv-search__field {
  flex: 1;
  height: 60px;
  padding-inline: var(--adv-space-26) 70px;
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-pill);
  background: var(--adv-color-surface);
  color: var(--adv-color-ink);
  font-family: var(--adv-font-body);
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  margin-inline-end: -60px; /* the button sits on top of the field's tail */
}
.adv-search__field::placeholder { color: var(--adv-color-body); }

/* ---------------------------------------------------------------------
   AUTOFILL                                                    [authored]
   The browser repaints an autofilled field in its own colours — Chrome's
   pale blue plate and near-black text — and the design has no such state.
   It was at its worst on the master homepage hero while that field was a
   70% ink WASH under a 5px blur on a photograph (until AD-137): the
   autofill plate landed on it as an opaque box.

   THE TEXT is only reachable through `-webkit-text-fill-color`. `color`
   does not win: the UA paints autofilled glyphs through a separate
   channel. It is a literal, so it is restated per context below.

   THE BACKGROUND NEEDS TWO DIFFERENT MECHANISMS, and that is a
   measurement, not a preference. The first version of this block used one
   — a transition delayed past any session, on the reasoning that the UA
   applies its plate as a transition and a delayed transition never
   arrives. Forced into `:autofill` and measured, the hero field kept its
   wash and the LIGHT fields still came out `rgb(232,240,254)`: Chrome
   also carries `-internal-autofill-selected` with an `!important`
   background, and a UA `!important` outranks anything an author writes.
   So:

     - opaque fields take the classic `inset 0 0 0 1000px` shadow, which
       paints OVER the UA plate instead of trying to outrank it;
     - a translucent field must NOT, because an opaque 1000px plate is
       exactly what would flatten its wash. The on-media hero field was the
       one such case and relied on the delayed transition alone; it is gone
       (AD-137), and the pill field below takes the pill's own surface.

   `:-webkit-autofill` and `:autofill` are SEPARATE rules on purpose: a
   selector list is dropped whole if one selector fails to parse, so
   pairing the standard pseudo with the prefixed one loses both on a
   browser that knows only the older name.

   FIREFOX IS NOT FIXED BY THIS and cannot be, by an author: its autofill
   highlight is a UA `!important` declaration with no author-reachable
   handle, and `-webkit-text-fill-color` means nothing there. Chromium and
   WebKit are covered; Firefox will still show its own tint. Recorded
   rather than left to be rediscovered. */
.adv-search__field:-webkit-autofill,
.adv-search__field:-webkit-autofill:hover,
.adv-search__field:-webkit-autofill:focus,
.adv-filter-panel__search:-webkit-autofill {
  /* The FILLED colour, not the resting one: an autofilled field is by
     definition non-empty, so `:not(:placeholder-shown)` is what it would
     otherwise be wearing. */
  box-shadow: inset 0 0 0 1000px var(--adv-hover-surface);
  -webkit-text-fill-color: var(--adv-color-ink);
  caret-color: var(--adv-color-ink);
  transition: background-color 0s 9999999s, color 0s 9999999s;
}
.adv-search__field:autofill,
.adv-filter-panel__search:autofill {
  box-shadow: inset 0 0 0 1000px var(--adv-hover-surface);
  -webkit-text-fill-color: var(--adv-color-ink);
  caret-color: var(--adv-color-ink);
  transition: background-color 0s 9999999s, color 0s 9999999s;
}
.adv-field input:-webkit-autofill,
.adv-field input:-webkit-autofill:hover,
.adv-field textarea:-webkit-autofill,
.adv-field select:-webkit-autofill {
  box-shadow: inset 0 0 0 1000px var(--adv-color-surface);
  -webkit-text-fill-color: var(--adv-color-ink);
  caret-color: var(--adv-color-ink);
  transition: background-color 0s 9999999s, color 0s 9999999s;
}
.adv-field input:autofill,
.adv-field textarea:autofill,
.adv-field select:autofill {
  box-shadow: inset 0 0 0 1000px var(--adv-color-surface);
  -webkit-text-fill-color: var(--adv-color-ink);
  caret-color: var(--adv-color-ink);
  transition: background-color 0s 9999999s, color 0s 9999999s;
}
/* THE PLATE FOLLOWS THE FIELD'S STATE (AD-143). The inset shadow above paints
   over the field's own background, so without these a filled-in name or email
   kept the resting plate while focused or invalid — the one state change the
   visitor would not see. Focus first, then error, so an invalid field that is
   focused still reads as invalid (the rule below does the same for the fill). */
.adv-field input:-webkit-autofill:focus,
.adv-field textarea:-webkit-autofill:focus {
  box-shadow: inset 0 0 0 1000px var(--adv-field-focus-surface);
}
.adv-field input:autofill:focus,
.adv-field textarea:autofill:focus {
  box-shadow: inset 0 0 0 1000px var(--adv-field-focus-surface);
}
.adv-field [aria-invalid="true"]:-webkit-autofill,
.adv-field [aria-invalid="true"]:-webkit-autofill:focus {
  box-shadow: inset 0 0 0 1000px var(--adv-field-error-surface);
}
.adv-field [aria-invalid="true"]:autofill {
  box-shadow: inset 0 0 0 1000px var(--adv-field-error-surface);
}
/* The master hero's pill field (AD-137) sits transparent INSIDE the pill, so its
   plate is the pill's own surface, not the filled-field grey — anything else
   paints a grey box in the middle of a light control. (Until AD-137 this was
   the on-media field, which took no plate at all over its photograph.) */
.adv-hero-search--pill .adv-search__field:-webkit-autofill,
.adv-hero-search--pill .adv-search__field:-webkit-autofill:hover,
.adv-hero-search--pill .adv-search__field:-webkit-autofill:focus {
  box-shadow: inset 0 0 0 1000px var(--adv-color-surface);
}
.adv-hero-search--pill .adv-search__field:autofill {
  box-shadow: inset 0 0 0 1000px var(--adv-color-surface);
}
.adv-search__field:focus,
.adv-search__field:not(:placeholder-shown) {
  background: var(--adv-hover-surface);
  border-color: var(--adv-hover-accent);
  outline: none;
}
.adv-search__button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  flex-shrink: 0;
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-pill);
  background: var(--adv-color-surface-alt);
  color: var(--adv-color-body);
  cursor: pointer;
  transition: border-color var(--adv-transition-fast) var(--adv-ease),
              color var(--adv-transition-fast) var(--adv-ease);
}
.adv-search__button:hover,
.adv-search__button:focus-visible {
  border-color: var(--adv-hover-accent);
  color: var(--adv-hover-accent);
}
/* THE BUTTON JOINS THE FIELD'S ACTIVE STATE — `search state=active` (516:8513).
   The control is drawn as ONE outline: the frame's active variant puts burgundy
   on the field's border AND on the button's, and swaps the glyph to the
   burgundy asset (#652C35 against the default #51595F). Ours changed the field
   alone, so typing lit three sides of a rounded box and left the right-hand cap
   on the light border — an outline that stops where the control does not.

   `~`, because the button follows the field in the form and the state lives on
   the field. `:not(:placeholder-shown)` carries it after focus moves away: the
   frame calls the variant `active`, not `focused`, and a field with a query in
   it is still the active one. The fill does not change — #F5F4F2 is what the
   button already wears in both variants. */
.adv-search__field:focus ~ .adv-search__button,
.adv-search__field:not(:placeholder-shown) ~ .adv-search__button {
  border-color: var(--adv-hover-accent);
  color: var(--adv-hover-accent);
}

/* ---------------------------------------------------------------------
   Language chip                                          node 498:4725
   A 60x60 SQUARE, not a pill — the one control in the kit that is not
   rounded. hover and active are the same treatment in the design.
   --------------------------------------------------------------------- */
.adv-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  border: none;
  border-radius: var(--adv-radius-0);
  background: transparent;
  color: var(--adv-color-ink);
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
  text-decoration: none;
  text-transform: uppercase;
  cursor: pointer;
}
/* A BAR TILE HOVERS LIKE A BAR ITEM — the tint plate below (ADR-0030 Amendment 1
   §1; no frame draws a tile hover, and one hover language for the bar is ours).
   `a` and `button` only: the one-language chip is a static `span` and stays
   bare, as the frames' EN tile is. The language menu's rows are the exception
   underneath: a square list on the page surface keeps its square opaque rows. */
:is(a, button).adv-chip:hover {
  background: var(--adv-nav-active-fill);
  -webkit-backdrop-filter: blur(var(--adv-nav-active-blur));
  backdrop-filter: blur(var(--adv-nav-active-blur));
  border-radius: var(--adv-radius-card);
}

/* ---------------------------------------------------------------------
   Navigation                                nodes 516:6080, 247:7400
   Nav items are 60px tall with a 40px inline padding. HOVER is a surface
   change (the tint plate); CURRENT is a label change (navy 600, no fill) —
   247:7400, on both tiers since ADR-0030 Amendment 1 §1.
   --------------------------------------------------------------------- */
.adv-nav { background: var(--adv-color-surface); }
/* ABOUT'S BAR IS ITS HERO'S SURFACE (1482:33909, AD-138 — ADR-0025 §3): #F5F4F2,
   no hairline drawn, so the sticky bar keeps its scroll-only hairline. Set by a
   page flag (front matter `navSurface: "alt"`, header.html). It stays FILLED —
   the transparent state is the homepage's alone (ADR-0024 §6).

   NO HOVER REBIND HERE ANY MORE. The shared hover plate was #F5F4F2, this bar's
   own colour, so it was rebound to the page surface; the plate is a tint now
   (247:7400), which shows on either bar (ADR-0030 Amendment 1 §1). */
.adv-nav--alt { background: var(--adv-color-surface-alt); }

/* THE HEADER IS ONE ROW — 99 + 1 on both tiers since ADR-0030 §1 (it was 60
   until the 2026-09-08 round redrew the master's, and the 2026-09-16 round the
   satellite's). There is no utility bar in this design — no phone/email strip
   and no CTA button. The right-hand side is two 60px tiles, search and the
   language chip, 10 in from the edge (1310 / 1370) on both tiers since
   ADR-0030 Amendment 1 §2 (the master's were flush at 1320 / 1380). */
/* THREE COLUMNS: 1fr | auto | 1fr — THE FALLBACK, which only the styleguide's
   plain `.adv-nav` and the ≤1439 sheet tier still use; both headers bind their
   own row (`.adv-nav--row` below). The equal outer tracks centre the menu on the
   frame no matter how wide the logo or the tiles are — on a 1440 frame the design
   starts the menu at x=347, and flex `margin: auto` put it at ~379 because that
   centres it in what is LEFT OVER rather than on the bar.

   Grid rather than absolute positioning, because an absolutely positioned menu
   becomes the containing block for everything inside it — and the dropdown has to
   sit inside its own item (so it can open under it on mobile) while still spanning
   the whole header. Only a statically positioned menu allows both. */
/* UNSCOPED as of AD-76. The design publishes the header as two variants of ONE
   component (Type=satellite | master, node 516:6080). The 2026-09-08 round
   redrew the master's bar at 99 and the 2026-09-16 round redrew the
   satellite's the same way (I553:12719, ADR-0030 §1), so the row's geometry is
   `.adv-nav--row`'s — both headers emit it — and what the tiers still disagree
   on (where the menu sits, the tile's x, the current item) is rebound on the
   tier modifiers, as custom properties rather than as scoped `height` rules;
   see the note at `.adv-nav--row` for why that distinction matters.

   The legacy utility strip that used to live here went with the v1 master
   header it was propping up. */
.adv-nav__bar {
  /* NOT POSITIONED — deliberately. The dropdown panel is absolute with
     `inset-inline: 0`, and a positioned bar becomes its containing block: the
     panel then spans the BAR (capped at 1440 and centred), so on a wider
     monitor it stopped short of the screen edges. The panel belongs to the NAV
     surface, which is full-bleed; the bar only contains the items. */
  display: grid;
  /* `--adv-nav-cols`: each header binds its row (`.adv-nav--row` and the tier
     modifiers below) — the master centres its menu between the tile and the
     tiles (AD-140), the satellite sets it right (ADR-0030 §1). The fallback is
     the note above's. */
  grid-template-columns: var(--adv-nav-cols, 1fr auto 1fr);
  align-items: center;
  height: var(--adv-nav-h, 99px);
  /* CAPPED AND CENTRED, exactly like `.adv-footer__top`. The frames are 1440
     wide and the bar was full-bleed, so past 1440 the logo and the two tiles
     kept walking outward with the viewport while every band below stayed in the
     1320 container — on a wide monitor the header no longer belonged to the
     page. The surface stays full-bleed; only its contents are contained. */
  max-width: var(--adv-container-outer);
  margin-inline: auto;
}

/* The bar itself has no padding, and NEITHER DOES THE LOGO carry the page
   margin. The Header component puts its logo tile at x=0 in both variants —
   185 wide, `padding: 10px 20px`, the 137-wide wordmark centred in it. An
   earlier pass gave the tile the 60px page margin instead, on the reasoning
   that every other band starts at 60; the component says otherwise, and the
   header is the one row in the design that runs edge to edge (the search and
   language tiles are flush right for the same reason). */
/* `--adv-nav-tile-x`: the header row's tile starts at x=28 on both tiers (I553:12719,
   516:6081), so the glyph sits on the page's 60 (ADR-0030 Amendment 1 §2). */
.adv-nav__logo-link {
  padding-inline: var(--adv-nav-tile-pad, 20px);
  margin-inline-start: var(--adv-nav-tile-x, 0px);
  /* The satellite's city is text inside this link, and it drew the link's
     underline in the link's blue until AD-145's design QA — the frame's city is
     plain ink. (The master's link holds only the image.) */
  text-decoration: none;
}
.adv-nav__logo { display: block; height: var(--adv-nav-mark-h, 50px); width: auto; }

.adv-nav__links { display: flex; align-items: center; justify-self: var(--adv-nav-menu-justify, auto); }
/* `--adv-nav-tiles-inset`: the row's two tiles end 10 in from the edge (1370 + 60), both tiers. */
.adv-nav__actions {
  display: flex;
  align-items: center;
  justify-self: end;
  margin-inline-end: var(--adv-nav-tiles-inset, 0px);
}

/* Mobile-only rows (ADR-0017 §7): the 402 menu sheet (623:23130) lists the
   dropdown's content as flat items — Practice areas · Legal experts ·
   Partner firms on the master, Expertise on a firm site. They exist in the
   markup of both headers and appear only when the sheet does (the 860
   block), where the dropdown itself is hidden.
   `.adv-nav__links >` is load-bearing: the shared item rule below is
   (0,1,1) and a bare class (0,1,0) would lose to its inline-flex. */
.adv-nav__links > .adv-nav__mobile-link { display: none; }

/* An item whose page is not built yet: present, legible, not clickable.
   See partials/nav-link.html for why it renders at all. */
.adv-nav__links [aria-disabled="true"] { color: var(--adv-color-ink-muted); cursor: default; }
.adv-nav__links [aria-disabled="true"]:hover { background: none; }

/* Sticky is NOT designed — the file carries no prototype, so there is
   nothing to read. Authored: the bar is the only persistent way back out
   of a multi-page site, which is the whole point of the restructure.

   THE WRAPPER HAS TO CARRY IT. Both themes render `<header class="site-header">`
   around the nav, and a `position: sticky` element can only offset inside its
   containing block — which here was a wrapper exactly as tall as the nav, so it
   had nowhere to stick and the header scrolled away like any other block. The
   rule used to live in the master theme's own CSS and was deleted with the rest
   of the v1 layer; nothing replaced it, and neither theme had it. It belongs
   here, with the class that promises the behaviour.

   `.site-header` is not an `adv-` name. Renaming it means touching both themes'
   markup, which is a separate change; it is styled here so the promise is kept
   in one place meanwhile. */
.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--adv-z-header);
}
.adv-nav--sticky {
  position: sticky;
  top: 0;
  z-index: var(--adv-z-header);
  border-bottom: var(--adv-border-width) solid transparent;
  transition: border-color var(--adv-transition-fast) var(--adv-ease);
}
.adv-nav--sticky[data-scrolled="true"] { border-bottom-color: var(--adv-color-border); }
/* `> span` is the UNBUILT item (nav-link.html renders one when its page does not
   exist yet). It was missing here, so those items got the colour rule below but
   none of the geometry: no padding, no height, no nowrap — and two of them in a
   row ran together as one word. The shape of the bar is the point of rendering
   them at all, so they take the same box as a real item. */
.adv-nav__links > a,
.adv-nav__links > span,
.adv-nav__item,
.adv-dropdown__toggle {   /* v1 name — the toggle IS a nav item in this design */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 60px;
  /* 40, or the compact 24 a translated master menu needs to fit its row
     (`.adv-nav--compact`, AD-140). The 4px tile inset that used to come off this
     (ADR-0025 Amendment 9) retired with the filled current item: the hover plate
     is the whole item box in 247:7400, and nothing beside it is filled any more. */
  padding-inline: var(--adv-nav-item-pad, var(--adv-space-40));
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
  color: var(--adv-color-ink);
  text-decoration: none;
  /* A nav item is a label, not a paragraph. Without this the flex row shrinks
     the longest item first and "Legal experts" breaks onto a second line,
     which pushes the bar past its 60px and knocks the whole header out. */
  white-space: nowrap;
  transition: background var(--adv-transition-fast) var(--adv-ease);
}
.adv-nav__links > a:hover,
.adv-nav__item:hover,
.adv-dropdown__toggle:hover {
  /* HOVER IS THE TINT PLATE, ON EVERY BAR (247:7400, ADR-0030 Amendment 1 §1): a
     5% black tint under a 30px blur, radius 12 — the master's old CURRENT tile
     (ADR-0025 §3), whose tokens keep their names. A tint shows on either bar
     surface, so the `--alt` and satellite-Home rebinds of the old opaque
     #F5F4F2 plate are gone.

     The blur sits on the ITEMS only — never on `.adv-dropdown` or anything that
     contains the popover or the search sheet, where a backdrop-filter would
     become the containing block of their absolute and fixed boxes. */
  background: var(--adv-nav-active-fill);
  -webkit-backdrop-filter: blur(var(--adv-nav-active-blur));
  backdrop-filter: blur(var(--adv-nav-active-blur));
  border-radius: var(--adv-radius-card);
}
/* OPEN IS NOT HOVER. `247:7400` draws `dropdownMenu=true, state=Default` bare,
   caret up: the flipped caret and the menu itself mark the open state, so
   `[aria-expanded="true"]` left the list above. The master opens its menu on
   mouse hover, so a pointer user still sees the plate while over the toggle;
   only keyboard and touch opening lose it. */

/* CURRENT IS A LABEL, NOT A SURFACE (247:7400 state=active, both tiers — ADR-0030
   Amendment 1 §1): no fill, Inter 600, `--adv-active-text` (#122448). It was the
   master's tint plate (ADR-0025 §3) and nothing on the satellite (ADR-0030 §1).
   A hovered current item takes the plate like any other.

   `:where()` keeps the (0,2,1) the ≤1439 and ≤860 sheet rules were written
   against: their rows are inverse on navy and restate the colour. The toggle is
   current on its sections through `data-current` (a button is not a link to
   the current page; header.html).

   THE BOX DOES NOT GROW. 247:7400 keeps the Default width for the active label
   (127 for "About"), so the 600 label spills evenly into the padding: see
   `.adv-nav__label` below. */
:where(.adv-nav) .adv-nav__links > a[aria-current="page"],
:where(.adv-nav) .adv-nav__item[aria-current="page"],
:where(.adv-nav) .adv-dropdown__toggle[data-current] {
  font-weight: var(--adv-weight-semibold);
  color: var(--adv-active-text);
}
/* THE LABEL'S BOX IS ITS 500 WIDTH IN EVERY STATE. The header wraps each label as
   `<span class="adv-nav__label" data-label="…"><span class="adv-nav__label-text">…`
   (nav-link.html `reserve`, both headers' toggles): a hidden 500-weight copy of
   the label sizes a one-cell grid, and the visible text sits in the same cell
   with no width of its own, centred — so a 600 label is drawn 1–2px wider on
   each side than its box, exactly as the frame's 127 "About" is.

   INSIDE THE SPAN, NOT ON THE ITEM (trap: the item is `inline-flex` with a 10px
   gap, so a pseudo-element there would be a flex item and add 10). The copy is
   `visibility: hidden`, which keeps it out of the accessibility tree; the
   `/ ""` form says the same to browsers that read generated content. */
.adv-nav__label { display: inline-grid; }
.adv-nav__label::before {
  content: attr(data-label);
  content: attr(data-label) / "";
  grid-area: 1 / 1;
  visibility: hidden;
  font-weight: var(--adv-weight-medium);
}
.adv-nav__label-text {
  grid-area: 1 / 1;
  justify-self: center;
  display: flex;
  justify-content: center;   /* unsafe centring: a wider label overflows both edges evenly */
  width: 0;
}

/* The toggle is usually a <button>; strip the UA chrome the anchors don't have. */
.adv-dropdown__toggle {
  background: transparent;
  border: none;
  cursor: pointer;
}

/* Language switcher. The design draws a single static `EN` tile and no
   switcher, but the network is at least four locales — so the open/close
   behaviour is authored. Closed it is exactly the designed tile; open it
   drops the alternatives directly beneath, on the same 60px rhythm. */
.adv-nav__lang { position: relative; display: inline-flex; }
.adv-nav__lang-menu {
  position: absolute;
  inset-block-start: 100%;
  inset-inline-end: 0;
  z-index: var(--adv-z-dropdown);
  display: flex;
  flex-direction: column;
  min-width: 60px;
  background: var(--adv-color-surface);
  border: var(--adv-border-width) solid var(--adv-color-border);
}
/* Its rows are a square list on the page surface: they keep the square opaque
   hover they always had, not the bar's rounded tint. */
.adv-nav__lang-menu .adv-chip:hover {
  background: var(--adv-hover-surface);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-radius: var(--adv-radius-0);
}
/* (its [hidden] rule lives with the other panels, just below) */

/* Mobile toggle — authored, since no frame below 1440 exists (ADR-0014 §7). */
.adv-nav__toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  border: none;
  background: transparent;
  color: var(--adv-color-ink);
  cursor: pointer;
}
.adv-nav__toggle:hover {
  background: var(--adv-nav-active-fill);
  -webkit-backdrop-filter: blur(var(--adv-nav-active-blur));
  backdrop-filter: blur(var(--adv-nav-active-blur));
  border-radius: var(--adv-radius-card);
}

/* Burger → X. Three bars: the element is the middle one, the pseudo-elements
   are the outer two. Built from real boxes rather than the box-shadow trick,
   because a shadow cannot be rotated — and rotating is the whole point. */
.adv-nav__toggle-icon,
.adv-nav__toggle-icon::before,
.adv-nav__toggle-icon::after {
  display: block;
  width: 20px;
  height: 2px;
  background: currentColor;
  transition: transform var(--adv-transition-fast) var(--adv-ease),
              background var(--adv-transition-fast) var(--adv-ease);
}
.adv-nav__toggle-icon { position: relative; }
.adv-nav__toggle-icon::before,
.adv-nav__toggle-icon::after { content: ""; position: absolute; inset-inline-start: 0; }
.adv-nav__toggle-icon::before { inset-block-start: -6px; }
.adv-nav__toggle-icon::after { inset-block-start: 6px; }

/* Open: the middle bar goes, the outer two meet in the centre and cross. */
.adv-nav__toggle[aria-expanded="true"] .adv-nav__toggle-icon { background: transparent; }
.adv-nav__toggle[aria-expanded="true"] .adv-nav__toggle-icon::before { transform: translateY(6px) rotate(45deg); }
.adv-nav__toggle[aria-expanded="true"] .adv-nav__toggle-icon::after { transform: translateY(-6px) rotate(-45deg); }

@media (prefers-reduced-motion: reduce) {
  .adv-nav__toggle-icon,
  .adv-nav__toggle-icon::before,
  .adv-nav__toggle-icon::after { transition: none; }
}

/* Dropdown — node 247:7706. Full-bleed, 317px tall, flat: no border, no
   radius, no shadow. Columns start at x=60 (the page margin), the group
   label sits at y=34 and the items from y=81 on a 41px pitch. */
/* THE `hidden` ATTRIBUTE IS A UA `display: none`, AND ANY AUTHOR `display`
   RULE BEATS IT. Every panel below sets `display: flex`, which silently
   defeats `hidden` — the element stays on screen, and JS that toggles the
   attribute appears to do nothing. Restating it is not optional. */
/* (These panels needed their own `[hidden]` restatement until base.css grew a
   global one. Kept as a comment so the note above them still has its subject.) */

/* The per-component `[hidden]` restatements that used to live here are gone:
   base.css now carries one `[hidden] { display: none !important; }` for the
   whole system. Three components had been patched individually — the listing
   filters, the load-more button and the search results band — while the CARDS
   those filters hide had not, so a facet changed the count and left the grid
   alone. One rule, not a growing list of the places it was remembered. */

/* THE FULL-BLEED PANEL IS GONE FROM BOTH TIERS (AK: master 2026-08-31,
   satellite 2026-09-01). What is left here is the positioning the popover
   builds on; `--popover` further down supplies the surface, the width and the
   one edge it anchors to.

   Removed with it: `.adv-dropdown { position: static }` (the base existed to
   make the BAR the panel's containing block, so a panel inside one item could
   still span the header — the popover anchors to its own item instead, see the
   `--satellite` / `--master` anchoring below), and `__cols` / `__group` /
   `__label`, the two-column grid and its labels. Nothing renders them: the
   satellite's `nav-dropdown.html` was the only template that did.

   `inset-inline: 0` and the padding stayed with the full-bleed shape too — both
   were overridden by `--popover` anyway, and leaving them would keep describing
   a panel this file no longer draws. */
.adv-dropdown__menu {
  position: absolute;
  /* Without this the panel falls back to its static position — inside the
     60px bar, on top of the menu — which looks like the menu has vanished
     rather than like the panel is misplaced. */
  inset-block-start: 100%;
  z-index: var(--adv-z-dropdown);
  background: var(--adv-color-surface);
}
.adv-dropdown__menu a {
  display: block;
  padding-block: var(--adv-space-8);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
  color: var(--adv-color-ink);
  text-decoration: none;
}
.adv-dropdown__menu a:hover { color: var(--adv-hover-accent); }

/* ---------------------------------------------------------------------
   Master dropdown                                        node 890:8431
   A 236x228 POPOVER UNDER ITS OWN ITEM, not a full-bleed panel: surface
   fill, 1px border, 12 radius, 26/40 padding, and one column of four
   links at 16/25 medium on a 26 rhythm.

   THIS REPLACES THE 516:5371 PANEL — a 110/385 category-and-item grid
   317 tall running the full viewport, with the item column fed from the
   network's data. That whole apparatus is gone (AK, 2026-08-31); the
   menu navigates to sections and no longer previews their contents.
   `__inner`, `__items` and the `--master` `__group` rules went with it.

   BOTH TIERS NOW (AK, 2026-09-01), which is why the modifier is
   `--popover` and no longer `--master`. It never named a tier; it named
   a shape, and a tier name stops being true the moment a second tier
   takes the shape. The firm sites' full-bleed two-halves panel is gone
   the same way and for the same reason — the columns were fed from the
   site's own content, so a thin firm rendered a 317px band of empty
   page. Its `__cols` / `__group` / `__label` rules went with it; see
   theme/adverit/layouts/partials/nav-dropdown.html.

   NOT A READING OF THE SATELLITE FRAME. 896:10032 still draws the
   1440x317 panel. AK's call, recorded here so it is not "corrected"
   back — the master's frame sat in exactly this state until 890:8431.
   --------------------------------------------------------------------- */
/* THE PANEL ANCHORS TO THE BAR, NOT TO THE TOGGLE'S TEXT. The frame puts it at
   y=74 — 14 under a 60px bar — and at x=257, level with its own item: two
   different reference edges, so the wrapper has to span the bar's full height
   for `calc(100% + 14px)` to mean 74 while `inset-inline-start: 0` still means
   the item's left edge.

   The toggle ALREADY fills the bar (measured: 60 tall, its own padding-block),
   so the stretch changes nothing today — it pins the wrapper to the BAR rather
   than to whatever the toggle's padding happens to be, which is what keeps the
   14 a bar-relative measure. The alternative was the distance from a centred
   25px line box to the bar's foot: a magic number that breaks the day the bar's
   height or the nav's type changes. */
/* BOTH TIERS, LISTED RATHER THAN FOLDED INTO `.adv-dropdown`. The base rule
   further up sets `position: static` on purpose — that is what made the old
   full-bleed panel take the BAR as its containing block — and it still reads as
   the deliberate opposite of this. Folding this in would leave the two facing
   declarations 80 lines apart with nothing saying which won; naming the navs
   keeps the anchoring where its reasoning is. */
/* ===== THE HEADER ROW — BOTH TIERS (1198:9572, 1205:11636, I553:12719) =====
   The bar is 99 tall (`--adv-nav-h`) around a 66.9 wordmark in a 248-wide
   tile. The master's frames measure it in both wordmark states and the
   satellite's redrawn frames measure the same (ADR-0030 §1), so this is the
   row of every page on both tiers, emitted by both headers as `.adv-nav--row`.
   Only the styleguide's plain `.adv-nav` keeps the old 50 mark and 20 pad.

   REBOUND AS CUSTOM PROPERTIES, NOT AS SCOPED `height` RULES, and that is the
   single most important line in this block. `.adv-nav--row .adv-nav__bar`
   would be (0,2,0), and the mobile bar below it is a BARE CLASS at (0,1,0)
   inside `@media (max-width: 860px)` — media queries add no specificity, so
   the more specific desktop rule would win there and hand every phone a 99px
   bar with a 248 tile. The desktop screenshot would be perfect. Rebinding a
   property the shared rule reads leaves that override winning on source order,
   the way `:root` is remapped for the 402 type step further down.

   The tile's inset is (248 - 183.65) / 2 = 32.175 — the scale's 32. */
.adv-nav--row {
  --adv-nav-mark-h: 66.9px;
  --adv-nav-tile-pad: var(--adv-space-32);
  --adv-nav-cols: minmax(248px, auto) minmax(0, 1fr) auto;
  /* THE GLYPH SITS ON THE PAGE'S 60, ON BOTH TIERS (516:6081, I553:12719 —
     ADR-0030 Amendment 1 §2): the tile starts at x=28 (28 + 32 = 60) and the
     two tiles end 10 in from the edge (1310 / 1370). Documented literals. The
     master's tile was at x=0 (glyph 32) until the client's 2026-09-17 note. */
  --adv-nav-tile-x: 28px;
  --adv-nav-tiles-inset: 10px;
}
/* THE MASTER'S MENU IS CENTRED BETWEEN THE TILE AND THE TILES, NOT ON THE BAR (AD-140).
   The round's inner-page header instances — 516:6209 (300:5214) and 1482:33909
   (About) — draw the 928 menu at x=320: 248 + (1320 − 248 − 928) / 2, the
   centre of the old geometry. With the tile at 28 and the tiles 10 in, the
   same rule centres it at ≈329 (276 + (1034 − 928) / 2); 516:6081 still draws
   320, which is a designer question, not a literal to copy. Only the
   homepage, with its wordmark off-canvas, centres it on the bar (1198:9572,
   256; see `.adv-nav--home` below). `auto` for the tiles' track and a middle
   `minmax(0, 1fr)` that the menu centres in also give the menu the whole
   1034 between them (1072 before the tile moved to 28 and the tiles 10 in) —
   the `1fr auto 1fr` row capped a centred menu at 944,
   which no translated menu fits.
   The first track has a 248 FLOOR, a documented literal: the frames'
   `adverit_Logo_legal 2` tile is 248 wide. The logo is an SVG with no
   intrinsic width until it loads, and an `auto` track would open at the 64 of
   its padding and push the menu ~92px sideways as it arrived. */
.adv-nav--master {
  --adv-nav-menu-justify: center;
  /* The homepage's hero state (see `.adv-nav--home` below): the tile leaves by
     the frame's 229 plus its own x, and the menu gives back half of what the
     tile and the tiles take — −(28 + 248 − 120 − 10) / 2 = −73 at the tokens,
     −64 − (28 − 10) / 2 (it was the scale's −64 while both were 0). */
  --adv-nav-home-tile-shift: translateX(calc(-229px - var(--adv-nav-tile-x) - max(0px, (100vw - var(--adv-container-outer)) / 2)));
  --adv-nav-home-menu-shift: translateX(calc((var(--adv-nav-tiles-inset) - var(--adv-nav-tile-x)) / 2 - var(--adv-space-64)));
}

/* THE SATELLITE'S ROW (I553:12719, ADR-0030 §1). The tile starts at x=28 and
   the firm's CITY follows the mark inside the same link (below); the menu is
   set RIGHT, against the search tile at 1310, and the two tiles end 10 in from
   the edge. Items stay vertically centred — the frame's top 14 is the master's
   12/13 again, and ADR-0022 Open kept centring.

   THE FIRST TRACK IS THE FLEXIBLE ONE HERE, not the menu's. The menu sits in
   an `auto` track, so it always gets its whole width, and the tile + city get
   what is left (never under 248): a long city ("Mönchengladbach") ellipsizes
   at the menu's edge instead of pushing the menu into the tiles. The link is
   `start`-aligned, or it would stretch into a 700-wide home link. */
.adv-nav--satellite.adv-nav--row {
  --adv-nav-cols: minmax(248px, 1fr) auto auto;
  --adv-nav-menu-justify: end;
  /* The homepage's hero state. The tile AND the city leave (the link's own
     width, plus its 28, plus the capped bar's offset on a wider screen); the
     right-set menu travels to the bar's centre, which depends on its width —
     one per language — so it is written in the menu's own percentage:
     (1440 − W) / 2 − (1310 − W) = W / 2 − 590 (1484:36481). */
  --adv-nav-home-tile-shift: translateX(calc(-100% - var(--adv-nav-tile-x) - max(0px, (100vw - var(--adv-container-outer)) / 2)));
  --adv-nav-home-menu-shift: translateX(calc(50% - 590px));
  /* …over a FILLED bar (1484:36481 draws #F5F4F2): the satellite's top state is
     not transparent, so ADR-0024 §6 / ADR-0025 §3 still hold. */
  --adv-nav-home-fill: var(--adv-color-surface-alt);
}
:where(.adv-nav--satellite.adv-nav--row) .adv-nav__logo-link {
  display: flex;
  align-items: center;
  justify-self: start;
  min-width: 0;
  max-width: 100%;
  gap: 18px;                       /* I553:12719 — 262 − (60 + 183.65), a documented literal */
}
/* THE FIRM'S CITY (I553:12719): Inter Medium 24/25, ink, 18 after the mark —
   262 − (60 + 183.65) = 18.35. Printed as DATA, never translated (trap 7:
   "Antwerp" is one string for every language).

   AT MOST 243 WIDE, AND A LONGER NAME SHRINKS TO FIT (MD — ADR-0030 Amendment 1
   §5). site.js scales the type by the box over the name's natural width, down to
   a floor of 12; the ellipsis below is what is left under the floor, and what a
   page without JavaScript shows. The line box stays 25, so the bar does not
   move. */
.adv-nav__city {
  max-width: var(--adv-nav-city-max-w);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--adv-nav-city-size);
  line-height: var(--adv-nav-city-lh);
  font-weight: var(--adv-weight-medium);
  color: var(--adv-color-ink);
}

/* THE HOMEPAGE OPENS WITH NO WORDMARK IN THE BAR. It is drawn large in the
   hero instead (`.adv-page-hero__wordmark`), and the bar slides its own in from
   the left once that one has gone under the header. `--home` is server-rendered
   on `.IsHome` alone, so THIS state is in the first paint: site.js is deferred,
   and flipping the state from script would paint the wordmark in the bar and
   then take it away. The script only ever changes `data-wordmark`'s value.

   229 IS THE FRAME'S NUMBER AND IT IS ONLY HALF THE TRAVEL. On a 1440 frame
   the tile starts at x=28 (it was 0 until ADR-0030 Amendment 1 §2, and the
   frame's hidden tile is still drawn at −229), so the shift adds the tile's own
   x: −257 leaves the tile's right edge at 19 and the glyph's at −13, all that is
   still on screen is padding, and it draws nothing.
   But `.adv-nav__bar` is CAPPED AT 1440 AND CENTRED (see its own note), so on
   anything wider the tile's natural left edge is already (100vw - 1440) / 2 in
   from the screen — and a flat -229 slides the wordmark left without ever
   taking it off the page. At 1600 that leaves the tail of it, the `t` and the
   `al`, sitting in the corner above the hero.

   So the travel is the frame's 229 PLUS the bar's own left offset, which is
   what `max()` computes here — 0 at 1440 and below, half the overflow above it.
   `100vw` counts the scrollbar where the bar's box does not, which errs
   further off-screen rather than short. (`-100%` is not the answer: the tile is
   a stretched grid item, so its 100% is the 1fr track, and that goes wrong in
   the other direction as the viewport grows.)

   A TRANSFORM, NOT `display: none` OR `left`. The bar is `1fr auto 1fr` and the
   equal outer tracks are the only reason the menu is centred at all (see the
   note at `.adv-nav__bar`): taking the tile out of the grid would re-centre the
   menu on the wrong axis and the 64 below would stop being a slide.

   And the menu's 64 (73 since the tile moved — see `.adv-nav--master`) is the
   tile's cell, GIVEN AWAY in the hero state: the
   master grid centres the menu between the 248 tile and the two 60px tiles —
   248 + (1440 − 248 − 120 − 928) / 2 = 320, every inner page's position
   (AD-140) — and 1198:9572 draws the homepage's hero state centred on the
   whole bar instead, (1440 − 928) / 2 = 256. The difference is the scale's own
   64, (248 − 120) / 2. Until AD-140 the grid centred on the bar and the BAR
   state carried +64; the grid now draws the bar state, so the hero state
   carries −64. The menu's travel is unchanged. */
/* The two shifts are the tier's (`--adv-nav-home-*-shift`, bound on `.adv-nav--master` and
   on the satellite row, ADR-0030 §2), so every `transform: none` below — the bar state, the
   ≤1439 sheet, ≤860, the <noscript> — resets both tiers at the weight it already has. */
.adv-nav--home .adv-nav__logo-link { transform: var(--adv-nav-home-tile-shift, none); }
.adv-nav--home .adv-nav__links { transform: var(--adv-nav-home-menu-shift, none); }
.adv-nav--home[data-wordmark="bar"] .adv-nav__logo-link,
.adv-nav--home[data-wordmark="bar"] .adv-nav__links,
/* …and so does an open search sheet (1529:12876): its backdrop covers the hero's
   lockup, so the bar shows its own, exactly as scrolling does. The sheet script
   writes its own attribute and never `data-wordmark` — the next scroll event
   would otherwise put the lockup back under the open sheet. */
.adv-nav--home[data-search-sheet="open"] .adv-nav__logo-link,
.adv-nav--home[data-search-sheet="open"] .adv-nav__links { transform: none; }

/* THE COMPACT STEP (AD-140): the item inset the ≤1100 tier already uses, for a
   master menu whose translated labels do not fit the 1072 the 1440 row leaves
   at 40 — measured 2026-09-16: NL 1127, DE 1144, FR 1183 at 40; 967, 984, 1023
   at 24; EN 920 keeps the frame's 40. The theme decides which language takes
   it (`navCompact`, master/hugo.toml). */
.adv-nav--compact { --adv-nav-item-pad: var(--adv-space-24); }

/* THE BAR IS TRANSPARENT WHILE THE HERO'S WORDMARK IS SHOWING (2026-09-16,
   1482:29858). The frame draws the header with no fill and no hairline: the
   hero's surface runs under it from y=0 (`.adv-page-hero--home` pulls itself up
   by the bar's height). The fill rides THE SAME STATE as the wordmark — one
   observer, one attribute — so the fill, the hairline and the bar's own
   wordmark always arrive together, and `[data-wordmark="bar"]` is simply
   today's bar.

   (0,2,0) against `.adv-nav--sticky[data-scrolled="true"]`'s (0,2,0): this wins
   on ORDER and must stay below that rule, or the hairline draws across the
   render as soon as the page moves a pixel.

   EVERY FAILURE PATH LANDS ON THE FILLED BAR, never on a transparent bar over
   body copy: no JS → head.html's <noscript> refills it; no IntersectionObserver
   or no hero wordmark → site.js writes "bar". (≤860 draws the same two states
   since ADR-0030 Amendment 1 §7, with a fade for the slide — see that block.) */
.adv-nav--home[data-wordmark="hero"] {
  background: var(--adv-nav-home-fill, transparent);
  border-bottom-color: transparent;
}

/* ONE SLIDE, TWO ELEMENTS. AUTHORED — the Figma file carries no prototype
   transitions at all (ADR-0014 §6), so there is nothing here to read and
   nothing this contradicts. 480ms (`--adv-transition-logo-slide`) since
   ADR-0030 Amendment 2: the client asked for a slower slide, and MD doubled
   the 240 it shared with the band crossfade (`.adv-switch-panel`). It no
   longer has to hurry, because the hero's wordmark has faded out before the
   slide starts (below): there is never a moment with two logos.

   ONE DURATION FOR EVERY WAY IN (MD). The search sheet's open and close move
   the tile on the same 480, though the sheet itself travels on its own 240:
   "the sheet closed at the top" and "the reader scrolled back to the top"
   enter the SAME state, and a transition takes the duration of the state it
   enters, so CSS alone cannot give the two different numbers. */
.adv-nav--home .adv-nav__logo-link,
.adv-nav--home .adv-nav__links { transition: transform var(--adv-transition-logo-slide) var(--adv-ease); }
/* THE FILL ARRIVES AT ONCE AND LEAVES ON THE SLIDE'S DURATION. A transition runs
   on the state being ENTERED, so only the "hero" state names one: flipping to
   "bar" is instant, so the page never scrolls under a half-filled bar beside
   the menu. Restates `.adv-nav--sticky`'s border transition: one `transition`
   property, so naming one drops the other. */
.adv-nav--home[data-wordmark="hero"] {
  transition: background-color var(--adv-transition-logo-slide) var(--adv-ease),
              border-color var(--adv-transition-fast) var(--adv-ease);
}
@media (prefers-reduced-motion: reduce) {
  /* The two STATES stay — which wordmark the page is showing is the design,
     not decoration; only the travel between them goes. */
  .adv-nav--home[data-wordmark],
  .adv-nav--home .adv-nav__logo-link,
  .adv-nav--home .adv-nav__links { transition: none; }
}

/* THE HERO'S WORDMARK FADES AS IT GOES UNDER THE BAR (ADR-0030 Amendment 2 §2,
   the client; no frame draws motion). `data-hero-fade` marks what fades — the
   master's glyph, the satellite's lockup (glyph and city: one box, which ends
   at the city's last line) — and the same element carries the observer's
   `data-hero-wordmark` (site.js), so the fade and the flip agree by
   construction:
   - it STARTS when the drawn glyph's top reaches the bar's foot.
     `--adv-hero-fade-lead` is how far below the element's top the glyph
     starts: 0 on the master's `img`, the tile's inset on the satellite lockup;
   - it ENDS, at 0, when the element's bottom edge passes the bar's foot
     (`exit 100%`) — the edge on which the observer's `isIntersecting` turns
     false and writes "bar".
   The inset is the bar the observer measures (`.adv-nav__bar`: 99 above 860,
   88 at ≤860, rebound there). The 1px hairline is transparent in this state.

   SCROLL-LINKED, NOT TIMED, and not gated on reduced motion: nothing moves, and
   the reader's own scroll drives it. A browser without scroll-driven animation
   (Firefox, 2026-09) gets a timed fade instead: the observer writes
   `data-hero-leaving` while the glyph is partly under the bar, and removes it
   when the glyph is clear again. */
[data-hero-fade] {
  --adv-hero-fade-inset: var(--adv-nav-h);
  --adv-hero-fade-lead: 0px;
}
/* The 35 is `.adv-page-hero__wordmark`'s inset above the glyph (below). */
.adv-hero-lockup[data-hero-fade] { --adv-hero-fade-lead: 35px; }
@keyframes adv-hero-fade {
  to { opacity: 0; }
}
@supports (animation-timeline: view()) {
  [data-hero-fade] {
    animation-name: adv-hero-fade;
    animation-duration: auto;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-timeline: view(block var(--adv-hero-fade-inset) 0px);
    animation-range: exit var(--adv-hero-fade-lead) exit 100%;
  }
}
@supports not (animation-timeline: view()) {
  [data-hero-fade] { transition: opacity 240ms var(--adv-ease); }
  [data-hero-fade][data-hero-leaving] { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  [data-hero-fade] { transition: none; }
}

.adv-nav--master .adv-nav__links,
.adv-nav--master .adv-dropdown,
.adv-nav--satellite .adv-nav__links,
.adv-nav--satellite .adv-dropdown { align-self: stretch; }
.adv-nav--master .adv-dropdown,
.adv-nav--satellite .adv-dropdown {
  position: relative;
  display: flex;
  align-items: center;
}
.adv-dropdown__menu--popover {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-26);
  /* One edge — the item's own left. This used to reset `inset-inline: auto`
     first, because the base rule set the full-bleed `inset-inline: 0`; the base
     no longer does, so there is nothing left to undo. */
  inset-inline-start: 0;
  /* FLUSH TO THE BAR (AK, 2026-08-31). The frame draws the panel at y=74, 14
     under the bar, and on screen that reads as a seam rather than as spacing —
     the panel looks detached from the item that opened it. Hard against the
     bar's foot instead, which is also where the old full-bleed panel sat, so
     the header keeps one behaviour rather than two. */
  inset-block-start: 100%;
  width: 236px;
  padding: var(--adv-space-26) var(--adv-space-40);
  /* #FAF9F7, not white. The reference's master-chrome.jsx paints master
     surfaces white and the frames never do; 890:8431 binds `background/main`
     like every frame before it (OPEN-ITEMS §2.11). */
  background: var(--adv-color-surface);
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-card);
  /* The one shadow on the whole site — see the elevation note in tokens.css.
     ADR owed: it is a new brand value, not a transcription of an existing one. */
  box-shadow: var(--adv-shadow-menu);
}
/* THE ROUNDED CORNERS ARE A HOLE IN THE CONTROL (AK, 2026-08-31 — the panel
   dropped out while the pointer travelled from the item down to it).

   The header closes the panel on `pointerleave` of `.adv-nav`. The panel is a
   DOM descendant of the nav, so hovering it never counts as leaving — but a
   pointer that lands on NEITHER box for even one frame does. That first showed
   up as the frame's 14px gap between the bar and the panel, which is now closed;
   what survives closing it is the 12px CORNER RADIUS. Inside the panel's own
   top-left and top-right 12x12 squares, the pixels outside the arc do not
   hit-test as the panel, so a pointer descending within ~12px of either edge
   still fell through to the page — measured, by hit-testing every pixel of the
   path rather than by moving a mouse.

   So the panel is given a square-cornered hit area over its top 12px: part of
   the panel, transparent, and present only while the panel is open (`[hidden]`
   takes the pseudo-element with it). Geometry, not a timer — a pointer that
   never lands on nothing cannot fire the leave, however slowly or erratically it
   moves, and there is no grace period to tune or to feel as lag on the way out.

   The insets are -1px because an absolutely positioned child is placed against
   the PADDING box: -1 reaches the border box, so the strip covers the border
   row the corner arc also cuts. It stops exactly at the panel's top edge and
   never overlaps the bar, so the toggle's own last pixel row stays clickable. */
.adv-dropdown__menu--popover::before {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline: -1px;
  height: 13px;
}
.adv-dropdown__cats {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-26);
  align-items: flex-start;
  /* The frame's own column width; the labels are shorter and left-aligned in
     it, which is what keeps them on one ragged edge rather than centred. */
  width: 157px;
}
/* SCOPED TO THE MENU ON PURPOSE, and it is not decoration: a category is an
   <a>, which brings it under `.adv-dropdown__menu a` (0,1,1) — that rule's 8px
   padding-block would otherwise outrank a bare `.adv-dropdown__cat` (0,1,0) and
   add padding the 26 rhythm does not allow. The extra class buys (0,2,0). */
.adv-dropdown__menu .adv-dropdown__cat {
  padding: 0;
  border: none;
  background: none;
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
  /* INK, not navy. 890:8431 binds `text/main` on all four; the navy was the
     516:5371 panel's way of ranking the category column above its items, and
     with no items to rank against it was just a second colour. */
  color: var(--adv-color-ink);
  text-align: start;
  white-space: nowrap;
  cursor: pointer;
}
.adv-dropdown__menu .adv-dropdown__cat:hover { color: var(--adv-hover-accent); }
/* The row of the section this page is in (AD-138; header.html computes it). No
   frame draws this row's state, so it takes the system's active text, navy —
   listed for the designer (ADR-0025 Open). */
.adv-dropdown__menu .adv-dropdown__cat[aria-current="page"] { color: var(--adv-active-text); }
/* A category whose page is not built: legible, not clickable — the same state
   nav-link.html gives an unbuilt nav item. */
.adv-dropdown__menu .adv-dropdown__cat[aria-disabled="true"] {
  color: var(--adv-color-ink-muted);
  cursor: default;
}

/* ---------------------------------------------------------------------
   Cards                    nodes 516:7541, 516:7550, 516:7564, 516:7576
   One family, four contents. 475x168 with a 168px square media on the
   left, except the practice-area card which is 475x231 and has no media,
   and the firm card which has no media either.

   HOVER IS NOT A RECOLOUR. All four scale to 1.05, take a 2% blue wash,
   and move the title to navy. The wash over the card surface composites
   to #F1F1F1, which is exactly the "unbound colour" earlier passes
   reported measuring — it was the render of this, not a value of its own.
   --------------------------------------------------------------------- */
/* Any card that IS a link. The large cards each declare this themselves; the
   compact 475 family never did, because until the search-results screen nothing
   had wrapped one in an <a> — so its titles arrived in the browser's default
   underlined link style. */
a.adv-card { text-decoration: none; color: inherit; }

.adv-card {
  position: relative;
  background: var(--adv-color-surface-alt);
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-card);
  box-shadow: var(--adv-shadow-card); /* none — the design is flat */
  overflow: hidden;
}
.adv-card--hover {
  transition: transform var(--adv-transition-fast) var(--adv-ease),
              background var(--adv-transition-fast) var(--adv-ease);
}
/* A BUTTON WITH A PHONE LABEL (the satellite Home's primary, 1537:19268): both
   labels ship and one shows — `display: none` also takes the other out of the
   button's accessible name. The ≤560 block swaps them. */
.adv-btn__label--narrow { display: none; }

/* HOVER IS FOR POINTERS THAT HOVER (AD-145 design QA — ADR-0030 Amendment 1
   §7). A tap on a touch screen leaves `:hover` stuck on the card until the next
   tap elsewhere, which is the navy title the client saw on a practice-area card
   after going back to the list — and the scale reflowed the grid under the
   finger. The whole affordance (scale, wash, navy title) is gated, not only the
   scale that `(hover: none)` used to undo. */
@media (hover: hover) {
  .adv-card--hover:hover {
    transform: scale(var(--adv-card-hover-scale));
    background:
      linear-gradient(var(--adv-card-hover-wash), var(--adv-card-hover-wash)),
      var(--adv-color-surface-alt);
    z-index: 1; /* the scaled card must sit above its neighbours in a grid */
  }
  /* `.adv-area-card__title` joins the list now that its RESTING colour is ink —
     288:3219's hover variant is the one that turns it navy, and until the resting
     state was corrected there was no difference to draw. */
  .adv-card--hover:hover :is(.adv-topic-card__title, .adv-news-card__title, .adv-media-card__title, .adv-area-card__title),
  a.adv-area-card:hover .adv-area-card__title {
    color: var(--adv-color-primary-dark);
  }
}
@media (prefers-reduced-motion: reduce) {
  .adv-card--hover:hover { transform: none; }
}

/* Media rail — 168px square, flush left, matching the card's radius. */
.adv-card__media,
.adv-media-card__media {
  width: 168px;
  /* A property for the same reason as the body's block padding below. */
  height: var(--adv-media-card-rail-h, 168px);
  flex-shrink: 0;
  object-fit: cover;
  border-start-start-radius: var(--adv-radius-card);
  border-end-start-radius: var(--adv-radius-card);
}
/* A result with no photograph gets the system's monogram plate — the
   search engine writes the initial in; a hole beside panelled rows reads
   as a broken card. */
.adv-media-card__media--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--adv-color-primary-dark);
  color: var(--adv-color-on-navy);
  font: var(--adv-weight-semibold) 28px/1 var(--adv-font-heading);
}

/* Practice area / service — node 516:7541. 475x231, no media, symmetric
   34/26 padding, and a title in a fixed 88px box so a one-line and a
   two-line title leave the body copy on the same baseline. */
.adv-topic-card { display: flex; flex-direction: column; }
.adv-topic-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-4);
  flex: 1;
  padding: var(--adv-space-34) var(--adv-space-26);
}
.adv-topic-card__title {
  margin: 0;
  min-height: 88px;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-regular);
  font-size: var(--adv-h2-size);
  line-height: var(--adv-h2-lh);
  color: var(--adv-color-ink);
}
.adv-topic-card__snippet {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-body);
}
/* A TOPIC RESULT'S CHIPS (AD-166, ADR-0038 §AD-166 §4/§8) — the topic entity's search card is this
   card (419:4268 is the same `Rectangle 117` + `Frame 188`), with a row of its areas and services.
   Each chip is a plain `.adv-badge` span: the frame's `category tag` is the badge exactly (fill,
   1px border, pill, 10/16, 14 regular), 8 apart and wrapping inside the card. The frame hangs the
   row 4 under the 88 title box — the body's own gap — and has no description; with the
   description MD chose, the row sits 16 under it (no frame; a designer question). */
.adv-topic-card__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--adv-space-8);
}
.adv-topic-card__snippet + .adv-topic-card__chips { margin-block-start: var(--adv-space-12); }

/* Expert / firm — node 516:7550. Media rail plus a 26px gutter (text
   starts at x=194 on a 168px rail), 34px from the top, 4px between lines. */
.adv-media-card { display: flex; align-items: stretch; }
.adv-media-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-12);
  /* The block padding reads a property so one screen can take the frame's 168 without
     outweighing the ≤560 shorthand (the satellite search, `.adv-search-results--sat`). */
  padding: var(--adv-media-card-pad-y, var(--adv-space-34)) var(--adv-space-26);
  /* `min-width: 0` OR THE TEXT NEVER WRAPS AND NEVER ELLIPSES (AK,
     2026-09-02). A flex item's automatic minimum size is its min-content
     width, so a long line held this column open past the card and the card's
     own `overflow: hidden` quietly cut it — text disappearing rather than
     wrapping. It is also what makes the ellipses below actually appear. */
  min-width: 0;
}
/* 22/500 — `Heading/medium_22px`, which 419:4519 binds on the INSIGHT result.
   INK, NOT NAVY, and AUTO rather than `1` (AK, 2026-08-31): the frame colours
   every line of this card `text/main` and reports `leading: normal`, so a
   two-line title measures 54 (2 x 26.6). At `1` and navy ours ran three lines
   of 22 in a second colour the card does not use anywhere else. */
.adv-media-card__title {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-h3-size);
  line-height: var(--adv-h3-lh);
  color: var(--adv-color-ink);
  /* TWO LINES, and this one is load-bearing rather than cosmetic. The card is
     168 tall because its media rail is (419:4515 draws both at 168); a third
     line of title pushed the CARD to 213 while the image stayed 168, leaving a
     45px strip of empty card under the photograph. The frame's own title box is
     54 — two lines of 27 — and every long title in it is cut, so the clamp is
     read off the design rather than imposed on it. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
/* AN ENTITY'S NAME IS A DIFFERENT STYLE FROM AN ARTICLE'S TITLE (419:3446 /
   419:4112): `Heading/regular_28px` — 28 at 1.5, regular — which is
   `--adv-h2-*`, the same style the topic card's title takes.

   `--entity`, NOT `--firm`. The two are independent questions: `--firm` removes
   the media rail, which only the FIRM card does; this type is shared by the firm
   AND the expert card, which keeps its rail (419:4108). They were one modifier
   until the expert branch was written, and that would have broken the day
   expert data first arrived — the expert would have lost its photograph to a
   class it only wanted the type from. */
.adv-media-card--entity .adv-media-card__title {
  font-weight: var(--adv-weight-regular);
  font-size: var(--adv-h2-size);
  line-height: var(--adv-h2-lh);
  /* ONE LINE, NOT THE INSIGHT TITLE'S TWO (AK, 2026-09-02). The clamp above is
     read off the insight result, whose title box is 54 — two lines of 27. An
     entity's name is a different style in a different block: 419:3445 draws a
     100px stack of a 42 name over two 25 lines, and the card's whole arithmetic
     below (34 + 42 + 4 + 25 + 4 + 25 + 34 = 168) has exactly one line for it.
     At two the name alone measured 84 and the card came out 212 while its
     photograph stayed 168 — a 42px strip of empty card under the picture, and
     the row beside it dragged to the same height by `grid-auto-rows: 1fr`.
     "Jean-Christophe Vanderhaeghen" is not a hypothetical in this network. */
  -webkit-line-clamp: 1;
}
/* And its lines sit 4 apart, not 12 — the frame's own gap inside a 100px block
   holding a 42 name over two 25 lines (419:3445). */
.adv-media-card--entity .adv-media-card__body { gap: var(--adv-space-4); }
/* THE INSIGHT VARIANT IS PADDED 26, NOT 34, and it is what makes the card come
   out 168 — the height of its own media rail. 419:4518 puts that content block
   at top 26 where an entity's (419:3444 / 419:4111) sits at 34; with 34 on both,
   the body ran 18 past the photograph and left a strip of empty card beneath it.
   An entity card keeps 34 and lands on the same 168 by its own arithmetic
   (34 + 42 + 4 + 25 + 4 + 25 + 34), which is why this is scoped rather than
   swapped — and scoped to `--entity` so the EXPERT card, which shares that
   arithmetic and keeps its rail, is on the right side of it. */
.adv-media-card:not(.adv-media-card--entity) .adv-media-card__body {
  padding-block: var(--adv-space-26);
}
/* THE TWO LINES UNDER THE TITLE ARE ONE LINE EACH, BOTH VARIANTS (AK,
   2026-09-02). Every frame that draws this card gives them one — 419:3445's
   "Netherlands, Zeist" over "12 lawyers", 419:4518's "Article" over its date,
   553:13487's education over "Lawyer since 2007" — and the card's height is its
   photograph's, so a second line has nowhere to go: it pushed the card to 195
   with the rail still at 168.

   A long place ("Bundesrepublik Deutschland, Baden-Württemberg") and a long firm
   name ("Vanderhaeghen, Peeters & Van den Broecke Advocaten") are both ordinary
   in this network, and each of them alone was enough. Ellipsis rather than clamp
   because these are single-line by nature; the truncation says so. */
.adv-media-card__meta,
.adv-media-card__date {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.adv-media-card__date {
  margin: 0;
  font-size: var(--adv-small-size);
  line-height: 1;
  color: var(--adv-color-body);
}
.adv-media-card__meta {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
/* AN ENTITY'S THIRD LINE IS BODY, NOT THE SMALL DATE. `date` is what the engine
   calls the slot; on a firm it holds "12 lawyers" and on an expert the firm's
   name, and 419:3847 / 419:4114 set both in `Body/regular_16px` like the place
   line above them — the small style belongs to the insight card's date and
   nothing else. */
.adv-media-card--entity .adv-media-card__date {
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
/* The COMPACT firm card (this one) has no media block. Note that the design
   publishes a second, unrelated firm card — the homepage tile at 516:6773, with
   a photograph and tags — which is `.adv-firm-card` further down. Two
   components, two contexts; neither is a variant of the other. */
.adv-media-card--firm .adv-media-card__media { display: none; }

/* ---------------------------------------------------------------------
   Firm tile                                              node 516:6773
   The homepage's member-firm card: 400x579 — a 400x270 photograph above a
   panel that pins the firm's name and place to its top and its practice
   areas to its bottom.

   The card carries the surface, the border and the 12px radius (`.adv-card`)
   and clips its children, so the photograph meets the panel with square
   corners and the tile reads as one plate rather than two stacked boxes.

   Padding is the system's card padding, 34/26 — which is also exactly what
   the frame measures: an inner frame 348 wide at x=26, starting 34 below
   the panel's top edge and ending 34 above the card's bottom.
   --------------------------------------------------------------------- */
.adv-firm-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.adv-firm-card__media {
  display: block;
  height: 270px;
  flex-shrink: 0;
  background-size: cover;
  background-position: center;
  background-color: var(--adv-color-surface);
}
/* No photograph. The plate stays — a 400x309 panel floating where a 579 tile
   stood makes the row look broken rather than incomplete — and carries the
   firm's own monogram on the page surface, with the hairline that separates it
   from the panel below. The initial is real data (`short` in the network
   record), not a stand-in photograph of somebody else's building.
   [authored — the design has no empty state for this card] */
.adv-firm-card__media--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--adv-color-surface);
  border-block-end: var(--adv-border-width) solid var(--adv-color-border);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-monogram-size);
  line-height: 1;
  color: var(--adv-color-border);
}
/* 309 is the panel's own height in the frame. As a MINIMUM rather than a fixed
   height it does two things: a firm with no photograph gets exactly the 400x309
   tile (the chosen empty state — see cards/firm.html), and a long firm name
   grows the panel instead of colliding with the tags below it. */
.adv-firm-card__panel {
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--adv-space-24);
  min-height: 309px;
  padding: var(--adv-space-34) var(--adv-space-26);
}
.adv-firm-card__id { display: flex; flex-direction: column; }
/* 28/1.5 regular — the h2 step, not a card title: the tile names a firm, and the
   design sets it in the same size it sets a section's second-level heading. */
.adv-firm-card__name {
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-regular);
  font-size: var(--adv-h2-size);
  line-height: var(--adv-h2-lh);
  color: var(--adv-color-ink);
}
.adv-firm-card__place {
  margin-block-start: var(--adv-space-4);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
.adv-firm-card__badge { align-self: flex-start; margin-block-start: var(--adv-space-12); }
/* THE OFFICE CARD (1482:29934, AD-137) — the homepage's "Our offices" tile. Its
   panel is 259, not 309: the 348 content box starts 34 under the photograph, the
   title block and the tags are 34 apart, and the panel ends 34 under the tags.
   So a start-aligned column on the 34 step with the 259 as the floor, where the
   base card spreads its two blocks across 309. /firms/ keeps the base card. */
.adv-firm-card--office .adv-firm-card__panel {
  justify-content: flex-start;
  gap: var(--adv-space-34);
  min-height: 259px;
}
.adv-firm-card__tags { display: flex; flex-wrap: wrap; gap: var(--adv-space-12); }

/* Article — node 516:7576. Same rail, but 26px from the top, a 12px gap,
   a 22px Medium title, and a 10px date. */
.adv-news-card { display: flex; align-items: stretch; }
.adv-news-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-12);
  padding: var(--adv-space-26);
}
.adv-news-card__title {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-h3-size);
  line-height: var(--adv-h3-lh);
  color: var(--adv-color-ink);
}
.adv-news-card__meta {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
.adv-news-card__date {
  margin: 0;
  /* "Old/small" — the design's smallest step, and NOT the only 10px in it any
     more: the ≤860 office card's country and practice-areas lines are the same
     size (1605:21983/21984, AD-149), which is what turned the literal this rule
     carried into a token. */
  font-size: var(--adv-caption-size);
  line-height: var(--adv-caption-lh);
  color: var(--adv-color-ink);
}
.adv-news-card__author {
  display: flex;
  align-items: center;
  gap: var(--adv-space-8);
  margin-top: auto;
  font-size: var(--adv-small-size);
  color: var(--adv-color-body);
}

/* ---------------------------------------------------------------------
   Avatar [not in Figma]
   --------------------------------------------------------------------- */
.adv-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  border-radius: var(--adv-radius-pill);
  background: var(--adv-color-primary);
  color: var(--adv-color-on-navy);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
}
.adv-avatar--sm {
  width: 32px;
  height: 32px;
  font-size: var(--adv-small-size);
  background: var(--adv-color-accent-light-blue);
  color: var(--adv-color-primary-dark);
}

/* ---------------------------------------------------------------------
   Hero [not in Figma as a component]
   The frames show a hero, but it is composed per page rather than
   published as a kit component, so this stays v1's structure on new
   tokens until the homepage is built (Stage 3).
   --------------------------------------------------------------------- */
.adv-hero {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 380px;
  border-radius: var(--adv-radius-card);
  overflow: hidden;
  background: var(--adv-color-hero-navy);
  color: var(--adv-color-on-navy);
}
.adv-hero__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg,
    var(--adv-ramp-navy-90) 0%,
    var(--adv-ramp-navy-60) 60%,
    var(--adv-ramp-navy-50) 100%);
}
.adv-hero__content { position: relative; max-width: 680px; padding: var(--adv-space-60); }
.adv-hero__title {
  margin: 0 0 var(--adv-space-16);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h1-size);
  line-height: var(--adv-h1-lh);
  color: var(--adv-color-on-navy);
}
.adv-hero__subtitle {
  margin: 0 0 var(--adv-space-32);
  font-size: var(--adv-lead-size);
  line-height: var(--adv-lead-lh);
  color: var(--adv-color-on-navy);
}
.adv-hero__cta { display: flex; flex-wrap: wrap; gap: var(--adv-space-16); }

/* ---------------------------------------------------------------------
   Banner [not in Figma]
   Named `adv-callout`, not `adv-banner` (AD-153): ad blockers hide `.adv-banner`
   (see the Carousel section for the measurement).
   --------------------------------------------------------------------- */
.adv-callout {
  display: flex;
  align-items: center;
  gap: var(--adv-space-32);
  flex-wrap: wrap;
  padding: var(--adv-space-40);
  border-radius: var(--adv-radius-card);
  background: var(--adv-color-primary);
  color: var(--adv-color-on-navy);
}
.adv-callout__body { flex: 1; min-width: 220px; }
.adv-callout__eyebrow {
  margin: 0 0 var(--adv-space-8);
  font-family: var(--adv-font-mono);
  font-size: var(--adv-eyebrow-size);
  line-height: var(--adv-eyebrow-lh);
  letter-spacing: var(--adv-eyebrow-ls);
  text-transform: uppercase;
  color: var(--adv-color-on-navy);
}
.adv-callout__title {
  margin: 0 0 var(--adv-space-8);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-h3-size);
  line-height: var(--adv-h3-lh);
}
.adv-callout__text {
  margin: 0 0 var(--adv-space-16);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-on-navy);
}

/* ---------------------------------------------------------------------
   Quote [not in Figma]
   --------------------------------------------------------------------- */
.adv-quote {
  position: relative;
  margin: 0;
  padding: var(--adv-space-32);
  background: var(--adv-color-surface-alt);
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-card);
}
.adv-quote::before {
  content: "\201D";
  position: absolute;
  top: 22px;
  right: 26px;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-bold);
  font-size: 54px;
  line-height: 0.7;
  color: var(--adv-color-accent-light-blue);
}
.adv-quote__text {
  margin: 0 0 var(--adv-space-24);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  font-style: italic;
  color: var(--adv-color-ink);
}
.adv-quote__cite {
  display: flex;
  align-items: center;
  gap: var(--adv-space-16);
  border-top: var(--adv-border-width) solid var(--adv-color-border);
  padding-top: var(--adv-space-16);
  font-style: normal;
}
.adv-quote__name {
  display: block;
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-body-size);
  color: var(--adv-color-ink);
}
.adv-quote__role {
  display: block;
  margin-top: 2px;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-body);
}

/* ---------------------------------------------------------------------
   Office / contact card [not in Figma]
   --------------------------------------------------------------------- */
.adv-office {
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-card);
  background: var(--adv-color-surface-alt);
  overflow: hidden;
}
.adv-office__map { aspect-ratio: 16 / 7; display: flex; align-items: center; justify-content: center; }
.adv-office__body { padding: var(--adv-space-26); }
.adv-office__name {
  margin: 0 0 var(--adv-space-12);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-h4-size);
  line-height: var(--adv-h4-lh);
  color: var(--adv-color-primary);
}
.adv-office__address {
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-body);
}
.adv-office__address .phone { color: var(--adv-color-primary); font-weight: var(--adv-weight-medium); }
.adv-office__address .vat { color: var(--adv-color-body); font-size: var(--adv-small-size); }

/* ---------------------------------------------------------------------
   Footer                                    nodes 247:8404, 279:976
   The kit does publish a footer — it is simply named "Satellite" and
   "Master" rather than "Footer", which is why an earlier inventory
   listed it as missing.

   THE SURFACE IS NAVY, ON BOTH TIERS (2026-09-16, 1482:29973). It was dark
   grey (#3C3C3C, the one dark neutral) from the Phase 1 refresh until the
   2026-09-16 round redrew it corporate/navy — a brand change, recorded as a
   reversal in ADR-0024 §3. The satellite takes it too although no satellite
   frame was supplied in that round: the footer is one component. Every
   colour below is `--adv-color-on-navy`, and the logo is forced white by its
   filter, so nothing else depended on the grey.
   --------------------------------------------------------------------- */
.adv-footer {
  background: var(--adv-color-hero-navy);
  color: var(--adv-color-on-navy);
  /* WHAT BOTH TIERS' FRAMES NOW SHARE (1482:29973, 247:8404 — ADR-0030 §3): the logo is
     the bar's tile — the glyph 66.9 tall, starting 4 above the column headings' 47 — and
     the link columns start at the page's midpoint, x=720, because the brand takes 620
     (60 + 620 + 40). These were `.adv-footer--master`'s until the satellite frame
     arrived; the 860 block rebinds them back on the base, for both tiers. */
  --adv-footer-mark-h: 66.9px;
  --adv-footer-mark-offset: -4px;
  --adv-footer-brand-w: 620px;
  --adv-footer-brand-max: 620px;
  --adv-footer-cols-start: 0;
}
/* THE MASTER FOOTER'S OWN GEOMETRY RIDES ON CUSTOM PROPERTIES (AD-137), the device
   `.adv-nav--master` uses for the header (ADR-0022 §2): the base rules read them
   with today's values as fallbacks, `.adv-footer--master` rebinds them, and the
   860 block rebinds them back. A scoped `.adv-footer--master .adv-footer__x` rule
   would be (0,2,0) and silently beat every bare-class mobile rule below. */
.adv-footer__top {
  display: flex;
  flex-wrap: wrap;
  gap: var(--adv-space-40);
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding: 47px var(--adv-space-60) var(--adv-footer-top-pad-end, var(--adv-space-40));
}
.adv-footer__brand { flex: 1 1 var(--adv-footer-brand-w, 320px); max-width: var(--adv-footer-brand-max, 380px); }
.adv-footer__logo {
  height: var(--adv-footer-mark-h, 40px);
  width: auto;
  display: block;
  margin-block-start: var(--adv-footer-mark-offset, 0px);
  filter: brightness(0) invert(1);
}
.adv-footer__tagline {
  margin: var(--adv-footer-tagline-gap, var(--adv-space-24)) 0 0;
  /* 270 IS THE COMPONENT'S BOX AND IT IS BACK — as the base, with the master
     keeping its 380 below.

     This rule used to set 380 for both tiers, and the note under it had the
     whole picture already: "that 270 is the text box the footer component draws
     around ITS sentence — 'Practical legal support for entrepreneurs and
     businesses.', which fits the box in two lines". What it could not do was
     use it, because the tagline then in `firm.yaml` was the HERO's sentence
     serving double duty, and the master's is two authored lines that need ~305
     each; at 270 both broke badly, so the column's own 380 was taken instead.

     336:10491 is that component instance on the satellite About, and the
     satellite's tagline is now the component's own sentence (the hero keeps its
     own). So the base is the design again, and the deviation is scoped to the
     tier that actually deviates. */
  max-width: 270px;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-on-navy);
}
/* 10px "Old/small" — the design's smallest step, used only here and on the
   article card's date. Deliberately not a token: two uses, no name in Figma. */
/* THE MASTER'S TAGLINE IS TWO AUTHORED LINES, NOT A WRAPPED SENTENCE. It comes
   from `params.tagline` as a list and the template writes a <br> between the
   entries, so the break sits where the copy wants it. The longer of the two —
   "A European cooperation of independent law firms." — needs about 305 on its
   own line, so the component's 270 would wrap each authored line in half and
   turn two lines into four. 380 is the brand column's width, which leaves the
   next edit some room before it breaks again.
   A modifier and not a second base value: the two tiers draw the same footer and
   this is the one place their copy makes them differ. */
.adv-footer--master .adv-footer__tagline { max-width: 380px; }
/* THE MASTER FOOTER, MEASURED (1482:29973, 2026-09-16). Its logo is the BAR'S
   TILE — 248 x 99.2 at (29, 27), the glyph 66.9 tall at (61.2, 43.2), the same
   66.9 `.adv-nav--master` sets — where the base draws a 40px mark; the glyph
   starts 4 above the column headings' 47. Then the tagline 21 under it (131),
   "European legal cooperation" 26 under that (191), and the two link columns
   at the page's midpoint — x=720, 480 wide, `space-between` — where the base
   pushes a 510 block to the right edge (x=870). The brand takes 620 so that
   60 + 620 + 40 lands the columns on 720. The legal strip starts 49 under the
   lists (252). The logo, the brand width and the columns' start are the base's
   now (ADR-0030 §3); the tagline, the network gap and the column boxes stay the
   master's. */
.adv-footer--master {
  --adv-footer-tagline-gap: 21px;
  --adv-footer-network-gap: var(--adv-space-26);
  --adv-footer-cols-w: 480px;
  --adv-footer-col-a: 195px;
  --adv-footer-col-b: 150px;
  --adv-footer-top-pad-end: 49px;
}
/* THE SATELLITE FOOTER, MEASURED (247:8404, AD-145 — ADR-0030 §3). 280 tall. The
   bar's logo as on the master, then the firm's CITY (24/25 medium, x=61) whose line
   box starts 15 above the glyph's foot — beside the mark's "legal", 95 against
   110 — and NO TAGLINE. "Part of the Adverit legal cooperation" 31 under the city
   (151), at 14 in light blue with an 8px arrow, no full stop. The two columns start
   at 720 in a 510 row, boxes 95 and 180, `space-between`; the legal strip's text
   sits at 260 — 57 under the lists' foot (203) — LEFT-aligned, the links 41 after
   the copyright and 30 apart, and the footer ends 8 under it. */
.adv-footer--satellite {
  --adv-footer-cols-w: 510px;
  --adv-footer-col-a: 95px;
  --adv-footer-col-b: 180px;
  --adv-footer-network-gap: 31px;
  --adv-footer-network-size: var(--adv-small-size);
  --adv-footer-network-lh: var(--adv-small-lh);
  --adv-footer-network-color: var(--adv-color-accent-light-blue);
  --adv-footer-top-pad-end: 57px;
  --adv-footer-bottom-justify: flex-start;
  --adv-footer-bottom-gap: 41px;
  --adv-footer-bottom-pad: 8px;
  --adv-footer-city-gap: -15px;
}
/* The 95 box is the English column's; a translated label ("Juridische experts",
   "Domaines de droit") takes its own width rather than wrapping to a second line. */
.adv-footer--satellite .adv-footer__col { min-width: max-content; }
.adv-footer__city {
  margin: var(--adv-footer-city-gap, var(--adv-space-8)) 0 0;
  font-size: var(--adv-nav-city-size);
  line-height: var(--adv-nav-city-lh);
  font-weight: var(--adv-weight-medium);
  color: var(--adv-color-on-navy);
}
.adv-footer__network {
  margin: var(--adv-footer-network-gap, var(--adv-space-24)) 0 0;
  font-size: var(--adv-footer-network-size, 10px);
  line-height: var(--adv-footer-network-lh, 1.21);
  color: var(--adv-footer-network-color, var(--adv-color-on-navy));
}
/* The satellite's sentence ends in an 8px up-right arrow, 8 after the text (1073:9152). */
.adv-footer__network a { display: inline-flex; align-items: center; gap: 8px; }
.adv-footer__network-icon { width: 8px; height: 8px; flex: none; }
/* Two link columns, starting at the halfway mark as in the comp. */
.adv-footer__cols {
  display: flex;
  gap: var(--adv-space-60);
  flex: 1 1 var(--adv-footer-cols-w, 510px);
  justify-content: space-between;
  max-width: var(--adv-footer-cols-w, 510px);
  margin-inline-start: var(--adv-footer-cols-start, auto);
}
.adv-footer__col { display: flex; flex-direction: column; gap: 18px; }
/* The master's two columns are fixed boxes, 195 and 150 (1482:29973), so
   `space-between` puts Explore at 1050 rather than wherever its longest label
   ends. `flex-basis` only: the 560 grid ignores it. */
.adv-footer__col:first-child { flex-basis: var(--adv-footer-col-a, auto); }
.adv-footer__col:last-child { flex-basis: var(--adv-footer-col-b, auto); }
.adv-footer__heading {
  margin: 0;
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
  color: var(--adv-color-on-navy);
}
.adv-footer__list {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
}
/* `.adv-footer__network` JOINS THIS PAIR RATHER THAN GETTING ITS OWN (AD-126 item 22,
   ADR-0021 §6). The satellite's "Part of the Adverit legal cooperation." became a link;
   `.adv-footer__network` (:1648) styles the sentence and nothing inside it, so a bare
   anchor there inherited base.css's `--adv-link-color` — a light-surface link blue on a
   dark footer.

   The footer already states these two declarations TWICE, byte-identical: here and at
   `.adv-footer__links a` below. A third link group taking the same treatment is the
   component behaving consistently; a rule of its own would state it a third time and give
   the next value change three places to miss instead of two. No new value, no new token.

   The master's footer uses the same class (its own footer.html:56) but renders a <p> with
   no anchor in it, so this selector matches nothing there — checked, not assumed. */
.adv-footer__list a,
.adv-footer__text { color: var(--adv-color-on-navy); text-decoration: none; }
.adv-footer__network a { color: inherit; text-decoration: none; }
/* The satellite's e-mail is underlined at rest (247:8381). */
.adv-footer__list a.adv-footer__mail { text-decoration: underline; }
.adv-footer__list a:hover,
.adv-footer__network a:hover { text-decoration: underline; }
.adv-footer__text { font-size: var(--adv-small-size); line-height: var(--adv-small-lh); margin: 0; }

/* Bottom strip — same surface, 10px. The master sets the legal links right; the
   satellite's frame sets them left, 41 after the copyright (ADR-0030 §3). */
.adv-footer__bottom {
  display: flex;
  justify-content: var(--adv-footer-bottom-justify, space-between);
  align-items: center;
  flex-wrap: wrap;
  gap: var(--adv-space-16) var(--adv-footer-bottom-gap, var(--adv-space-16));
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding: 0 var(--adv-space-60) var(--adv-footer-bottom-pad, var(--adv-space-16));
  font-size: 10px;
  line-height: 1.21;
}
.adv-footer__links { display: flex; flex-wrap: wrap; gap: 30px; }
.adv-footer__links a { color: var(--adv-color-on-navy); text-decoration: none; }
.adv-footer__links a:hover { text-decoration: underline; }
.adv-footer__copy { margin: 0; color: var(--adv-color-on-navy); }

/* =====================================================================
   PAGE COMPOSITION                                            [design]
   ---------------------------------------------------------------------
   Everything above is a kit component with a Figma node. What follows is
   how the screens assemble them, taken from the "Adverit Design System"
   Claude Design project (templates/satellite-site).

   This layer did not exist after the first pass, and could not have: the
   Figma *variables* stop at 38px and expose no band rhythm, so a faithful
   transcription of them produced a system with no way to set a hero, a
   section headline or the spacing between bands. Those live in the
   screens, not the variables.
   ===================================================================== */

/* THE PAGE MARGIN IS PART OF THE WRAPPER, NOT ON TOP OF IT.
   Every full-width block in the design is a 1320 content column starting at
   x=60 on a 1440 frame. Writing that as `max-width: 1320` + `margin-inline:
   auto` + `padding-inline: 60` counts the margin twice: the auto margins
   already put the box at 60, and the padding then pushes the content to 120,
   leaving a 1200 column. Every band, head, rail and footer on the site was
   inset by an extra 60px, which is why the screens read as cramped and why a
   heading measured 60px off its position in the comps.
   The wrapper is the OUTER box — content column plus both margins — and the
   padding is what survives when the viewport is narrower than that. */
:root { --adv-container-outer: calc(var(--adv-container) + var(--adv-section-pad-x) * 2); }

/* Available to assistive technology, absent from the layout. Used where a page
   needs a heading for its outline that the design does not draw — the search
   screen, whose visible identity is the control itself. */
.adv-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Section label — uppercase maroon, above every band. NOT .adv-eyebrow,
   which is 12px mono, has no counterpart in the design, and survives only
   because the console still uses it. */
.adv-section-label {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-label-weight);
  font-size: var(--adv-label-size);
  line-height: var(--adv-label-lh);
  text-transform: uppercase;
  color: var(--adv-color-accent-burgundy);
}
/* THE LABEL IN THE FRAME'S OWN BOX (AD-143): 29 tall, Figma's AUTO line on the 24px
   label (1.21, the small step's), where `--adv-label-lh` reads it as 1. For a label
   whose NEXT block is measured from that box — the careers "how it works" note 26
   under it (597:18522). The vacancy page scopes the same value to its own labels.
   The text's centre does not move; only what follows it does. The 560 block's label
   rules are later and still win on phones. */
.adv-section-label--auto { line-height: var(--adv-small-lh); }

/* The satellite's `.adv-hero-title` (58/900 over a photograph, AD-119 / AD-132) retired with
   the hero it served — the 2026-09-16 Home opens on the split hero and a wordmark lockup
   (ADR-0030 §2), and its `--adv-sat-hero-*` tokens went with it. */
.adv-display {

  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-display-weight);
  font-size: var(--adv-display-size);
  line-height: var(--adv-display-lh);
  color: var(--adv-color-ink);
}
.adv-page-title {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-page-title-weight);
  font-size: var(--adv-page-title-size);
  line-height: var(--adv-page-title-lh);
  /* NAVY IS THE DEFAULT, not something a wrapper grants (AK, 2026-09-02). Every
     page title in the file binds `corporate/navy` — 343:11445 on a listing,
     336:10814 on About, 553:12714 on Contact, 522:8766 on the master. (The one
     exception, a title ON a photograph — `--on-media` — retired with the satellite's
     titled band in AD-145.) See the long note at `.adv-page-head`. */
  color: var(--adv-color-primary-dark);
}
/* The statement headline on About is navy where the homepage's band headline is
   body ink — the handoff binds corporate/navy on that node specifically. */
.adv-display--navy { color: var(--adv-color-primary-dark); }
/* The 38px step of the same display face — `Heading/semibold_38px`, the size the
   shared `.adv-cta-band__title` already hard-codes. A closing band that is NOT
   that component still wants that heading: the vacancy page's "Continue your
   application with …" is 38 semibold over 660 (597:19475), where the page's own
   title is 58. Without this the two headings render the same size and the
   closing band competes with the h1. */
.adv-display--sm {
  font-size: var(--adv-h1-size);
  line-height: var(--adv-h1-lh);
}
/* THE HOMEPAGE ABOUT HEADING GETS A LINE BUDGET — a 600 measure and three lines
   (AD-132, ADR-0021 item 21).

   A MODIFIER, NOT `.adv-band--intro .adv-display` OR `#about .adv-display`, and
   that is ADR-0021 §3's general rule rather than a preference. A descendant
   selector is (0,2,0) and a media query adds no specificity, so it would outrank
   `@media (max-width: 1100px) .adv-display { font-size: clamp(…) }` below at
   (0,1,0) and the fluid step would silently stop applying to these two headings
   — off the design width only, which is where nobody looks. A single class ties
   with `.adv-display` and loses to every later override, which is the cascade
   this file is built on.

   AND THE BARE CLASS CANNOT CARRY IT EITHER. `.adv-display` has SEVENTEEN
   template consumers across the two themes, six of them page <h1>s printing a
   name nobody chose the length of — `firms/single.html:118` a firm's,
   `experts/single.html:338` a person's, `careers/single.html` twice, both
   `detail-head.html`. A measure and a three-line cap there would truncate a long
   firm name on its own detail page, with a perfect homepage screenshot to show
   for it. Two consumers opt in by name: the satellite's `sections/intro.html`
   and the master's `sections/about.html`.

   600 IS WHAT THE SATELLITE ALREADY DREW. `intro.html` carried an inline
   `max-width:16ch`, which computes to 603.38 at 58/700 — so this is that number,
   made a token and given to the master's heading, which had no cap at all. It
   binds here, unlike on the hero: the band's column is 660.

   MEASURED AT 1440, 2026-09-08: both headings render the three lines they render
   today, and the master's widest line is 590.8 of the 600. That is the whole
   margin, which is why the budget is stated to the operator in the CMS hint
   rather than left to be discovered, and why four i18n defaults were shortened
   in this ticket rather than clipped. */
.adv-display--budget {
  max-width: var(--adv-display-measure);
  /* AD-119'S GUARD, WHICH THIS RULE MAKES NECESSARY HERE TOO. `.adv-display` has
     never carried it, and while the heading had no `overflow` a long scraped
     compound merely ESCAPED its box — visible, wrong, and readable. The clamp
     below brings `overflow: hidden` with it, so without this the same word is cut
     MID-GLYPH instead. Measured at 1440: "Arbeidsongeschiktheidsverzekering" runs
     968px in the 600 box; with this it breaks and stays inside, exactly as it
     did on the retired satellite `.adv-hero-title`. The satellite's About heading is firm-authored
     copy and reaches demo previews from a scrape, so this is the same case AD-119
     logged as a defect, arriving by a different route. */
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}
/* 52, AND THE TEMPLATE CHOSE IT (AD-132). One declaration each, because the
   decision is not here: Hugo counts the headline's runes against
   `--adv-display-budget` (55) and emits the class or does not, which gives
   exactly 58 or 52 and nothing between. `clamp()` cannot: it keys off the
   viewport, so it would step a SHORT headline down on a narrow screen and leave
   a LONG one at 58 on a wide one — the opposite of the rule — and its ramp lands
   mid-laptop (4vw gives 57.6 at 1440 and 52 at 1300).

   IT STOPS APPLYING BELOW 1100 ON ITS OWN, which is the file's cascade and not
   an omission: `@media (max-width: 1100px) .adv-display` is (0,1,0) and later in source, so the fluid step wins there and this fixed
   52 never reaches a tier that already sizes by width. Between 1101 and 1439 it
   does apply, which is right — the tracks are narrower than 600 there, so a long
   headline needs the step more, not less.

   Name note: `.adv-band--tight` above means LESS PADDING. Different block, no
   conflict, but `--tight` now means two things in this file. */
.adv-display--tight    { font-size: var(--adv-display-size-tight); }
/* Same move for the smaller headings. The master homepage puts EVERY band
   headline in navy (the reference template sets `color: var(--color-navy)` on
   each), so this is not a one-off the way `--navy` above was — hence a modifier
   that composes with `.adv-h1`/`.adv-h2` rather than a third heading class. */
.adv-heading--navy { color: var(--adv-color-primary-dark); }
.adv-subtitle {
  margin: 0;
  font-size: var(--adv-subtitle-size);
  line-height: var(--adv-subtitle-lh);
  color: var(--adv-color-ink);
  /* Same reasoning as the retired satellite hero title (AD-119): this carries scraped copy too. At 24px it
     survives a compound word on a wide viewport, but its column narrows with the layout
     and the word does not — so the guard belongs here as well, on the same inert terms. */
  overflow-wrap: anywhere;
}

/* Band — one section of the page. The screens alternate the plain page
   surface #FAF9F7 with the warm full-bleed band #F5F4F2 (`--warm`, below).

   THERE IS NO THIRD BACKGROUND (MD, 2026-09-07). This used to say the
   full-bleed band was "a cool #F5F5F5 … NOT the warm surface-alt the cards
   use, and the two are easy to confuse". tokens.css:56-62 deleted
   `surfaceCool` on 2026-09-01 because Figma's variable set has exactly two
   page backgrounds — `background/main` #FAF9F7 and `background/secondary`
   #F5F4F2 — and #F5F5F5 is neither. That note names THIS comment as the
   reason the wrong colour survived on the band, and it is the paragraph a
   reader consults to decide what "white" means on the master homepage. */
.adv-band { padding-block: var(--adv-section-gap); }
/* A short band — 42 of padding rather than 96, so it reads as an aside between
   two full bands. Currently unused: the master's "Not sure…" band was built
   with it (the design reference transcribes that band at 42) and moved to the
   full 96 on review against the Figma frame. Kept because the two artefacts
   disagree and this is the value one of them states. */
.adv-band--tight { padding-block: var(--adv-space-42); }

/* ---------------------------------------------------------------------
   THE 96 IS A RHYTHM BETWEEN BANDS, NOT PADDING INSIDE EVERY ONE.

   Both references space their bands 96 apart, and the firm sites' handoff says
   so outright ("the 96px rhythm comes from the frame's flex column — keep
   `--adv-section-gap`"). The base rule above expresses that as 96 of padding on
   each band, which is right while nothing is painted: two plain bands then sit
   96 apart... except they do not. They sit 192 apart, because both contribute.

   That went unnoticed on the firm sites, where the bands that touch are mostly
   plain. It is very visible on the master homepage, whose reference is explicit:
   a plain section is `padding: "96px 60px 0"` — the gap belongs ABOVE it and
   nothing is added below — and a painted band is 54 of padding with a 96 margin
   above it. The plate is what the reader sees, and 96 of it around the content
   makes the coloured band read as twice its designed height.

   Two modifiers rather than a rewrite of `.adv-band`: the firm screens were
   measured against the current rule and are not in this ticket's scope. */
.adv-band--flow {                                    /* plain: gap above only */
  padding-block: var(--adv-section-gap) 0;
}
.adv-band--plate {                                   /* painted: 54 inside, 96 above */
  padding-block: 54px;
  margin-block-start: var(--adv-section-gap);
}
/* No block padding at all — the band takes its spacing from whatever it sits
   against. Currently unconsumed: the master's About band used it while it was
   white and continuing the "Not sure…" plate; re-read against the frame
   (430:8224 carries no fill) it went back to the page surface at the normal
   rhythm. Kept for the next genuinely flush pairing. */
.adv-band--flush { padding-block: 0; }
/* The gap-above on its own, with no opinion about the padding inside. `--plate`
   bundles the two (96 above, 54 within) because that is what the homepage's
   painted bands do; the master About screen's values band is painted AND keeps
   the full 96 inside it, so it needs the margin without the 54. Composes onto
   `.adv-cta-band` too, which is a band by behaviour and not by class. */
.adv-band--spaced { margin-block-start: var(--adv-section-gap); }
/* The careers "why join" label, somewhere a media query can reach it (the mobile step
   wants 24). 59, NOT 60 (AD-143): 589:16363 starts the rows 83 under the label's top,
   and this label's box is 24 where the frame's is 29 — the arithmetic of `.adv-stack--rows`. */
.adv-band--why-join .adv-section-label { margin-block-end: 59px; }
/* THE CAREERS PROSE SITS 34 UNDER THE TRAIL, not 96 (AD-143, 553:14183: the crumb text
   at 1050, the label and heading at 1109). The trail carries no bottom padding, so the
   band's own top is the whole gap. */
.adv-band--careers-intro { padding-block-start: var(--adv-space-34); }
/* The WARM band — #F5F4F2, `background/secondary`, the same surface the cards
   use. About's "our approach" sits on this one AND SO DOES the homepage's
   values band: both rectangles bind the same variable (896:9785, 896:9818).

   BOTH, not one each (MD, 2026-09-07). This used to say the values band "is
   the cool #F5F5F5 … the two are a single step apart and the templates
   genuinely use both". The template it described retracted exactly that
   sentence on 2026-09-01 — theme/adverit/layouts/partials/sections/why-us.html:3-9
   carries the retraction and the node ids — and the retraction never reached
   this file. #F5F5F5 is not one of Figma's two page backgrounds. */
.adv-band--warm { background: var(--adv-color-surface-alt); }
.adv-band__inner {
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding-inline: var(--adv-section-pad-x);
}
/* The recurring band layout: section label in the left column, content in the
   right. A flex row with an auto-width label does NOT reproduce it — it hugs the
   word "About us" and starts the copy right after it.

   600 + 60 + 660, NOT `1fr 1fr`. The comment here used to say "the design splits
   these evenly … the copy at x=663 of a 1322 row, i.e. the midpoint" and then set
   an even split, which does not land on the midpoint: `1fr 1fr` on a 60 gap gives
   two 630 columns and starts the right one at 750 of the 1440 frame. 896:9773
   ("Frame 61", the "Discuss your questions…" column) is at x=722, and the
   container's midpoint is 60 + 660 = 720. The band was 30px right of where it is
   drawn, on both tiers.

   This is the same arithmetic as `.adv-page-head`, the retired satellite hero intro and the
   two modifiers below — which restate it, and did so precisely because this base
   was wrong. They are now redundant with it; left in place because they are also
   the record of where each was measured.

   `--values` (5fr 6fr) and `--media` override the columns and are unaffected. */
.adv-band__split {
  display: grid;
  grid-template-columns: minmax(0, 600px) minmax(0, 660px);
  gap: var(--adv-space-60);
  align-items: start;
}
/* "Our values" is the one band that is not an even split: its label sits at the
   page margin and the rows occupy the right 720 of a 1320 container — 5:6.
   AND `fr` DID NOT PRODUCE IT (AK, 2026-09-02) — fifth instance in this pass,
   after `.adv-approach__row`, `.adv-detail` and `.adv-split-media`, and the
   sixth where the comment above stated the frame correctly while the code
   beside it did something else. `5fr 6fr` distributes the FREE space, which on
   1320 with the inherited 60 gap is 1260 — so the columns came out 573/687 and
   the rows began at x=693 where 226:5804 begins them at 660.

   NO COLUMN GAP, and that is the whole trick of this band: the 60 that would be
   the gap is the NUMBER GUTTER. The plate is 38 and the row's own gap is 22, so
   38 + 22 = 60 and the value's NAME lands on 720, the container's midpoint,
   with its number hanging in the margin to the left. Give this grid a 60 gap as
   well and the numbers get pushed off the midpoint by exactly that much, which
   is what the 33px error was. */
.adv-band__split--values {
  grid-template-columns: minmax(0, 600px) minmax(0, 720px);
  column-gap: 0;
}
/* The master homepage's practice-areas band — 623:21944, and the panel starts
   at the container's MIDPOINT, not after the chips.

   The frame is explicit: the chip column (Frame 130) sits at x=60 and is 226
   wide — the width of its longest tag, because the tags shrink-wrap — while the
   panel (Frame 137) is a 660 box at x=**720**, which is half of 1440. So the
   split is 600 + 60 + 660, exactly the 1320 container, and the chips occupy the
   first 226 of their 600 column with the rest left as air. The same arithmetic
   as `--cta` below, arrived at from a different frame.

   IT WAS 400px, WHICH READ THE CHIPS AS THE COLUMN — a reasonable thing to
   measure and the wrong thing: it put the panel at 60+400+60 = 520 and the
   heading 200px left of where the comp draws it, out of line with every other
   band's right column. The chip column's width is a consequence of the longest
   tag; the panel's position is the design decision. */
.adv-band__split--chips { grid-template-columns: minmax(0, 600px) minmax(0, 660px); }
/* A split whose right half is a closing call to action: the section label at the
   page margin, the heading, copy and button in a 660 column starting at the
   container's midpoint + 60 (597:19550 — label at x=60, Group 213 at x=720
   w=660). 600 + 60 + 660 is exactly the 1320 container.

   NOT `--values` (5fr 6fr), which lands the right column at 693, and not the
   base 1fr 1fr, which lands it at 750. Both were tried; a call to action whose
   button does not sit on the same vertical as every other band's content is the
   kind of drift the measured modifiers exist to prevent. */
.adv-band__split--cta { grid-template-columns: minmax(0, 600px) minmax(0, 660px); }
/* A split whose right half is a photograph. Three things, all read off the comp:

   MEASURES, not a ratio — 563 of copy against a 659 plate. At `1fr 1fr` both are
   630, which narrows the photograph and moves its left edge 67px right of where
   the design puts it. `minmax(0, …)` so the pair still shrinks below 1440
   instead of overflowing the container.

   FLUSH RIGHT — `justify-content: space-between` puts the leftover width
   between the columns, so the plate's right edge lands on the band's content
   edge. Sized as fixed tracks it would instead leave a gutter there.

   TOP-ALIGNED. This started as `center`, which reads sensibly and is wrong: the
   left column is ~380 tall against a 491 photograph, so centring dropped the
   first thing in it — the chip row — about 55px below the photo's top edge. The
   comp aligns their top edges. Only the master's services band uses this
   modifier; if a future one genuinely wants centring it gets its own. */
.adv-band__split--media {
  grid-template-columns: minmax(0, 563px) minmax(0, 659px);
  justify-content: space-between;
  align-items: start;
}
/* THE VACANCY'S "ABOUT ADVERIT ⟨CITY⟩" (597:19485, AD-143): 617 of copy beside the 660
   plate, and the copy CENTRED on it — the label 40 under the plate's top, the link 25
   above its foot, for a 206 block in a 286 row. */
.adv-band__split--job-office {
  grid-template-columns: minmax(0, 617px) minmax(0, 660px);
  /* 617 + 660 leaves 43 of the 1320, not the split's 60 — `--media`'s space-between
     takes it, and a 60 gap would shrink both columns. */
  column-gap: 0;
  align-items: center;
}
/* The left column of that split: chips, heading, copy and the link on one
   rhythm. The 26 belongs to the container, not to a margin on the chip row —
   the panels are toggled with `hidden`, and a margin on a hidden sibling is a
   gap that appears and disappears with the switcher. */
.adv-switch-column {
  display: flex;
  flex-direction: column;
  gap: var(--adv-stack-gap);
  align-items: flex-start;
}
/* THE SERVICES BAND BREAKS THAT RHYTHM ONCE — 102 between the chip row and the
   panel, where every other step in the column is 26 (623:21965 starts at y=824;
   the chips end at 722).

   It is not an arbitrary 102, and that is why it is worth keeping rather than
   rounding to a scale step: it is what CENTRES THE PANEL ON THE PHOTOGRAPH.
   The plate runs 677→1168, centre 922.5; the panel runs 824→1021, centre
   922.5 — exactly. The chips sit at the plate's top edge and the copy sits at
   its middle, which is the composition, and 102 is what falls out of it for
   the copy the frame draws.

   IT IS EXPRESSED AS THE GAP ANYWAY, not as real centring, because centring
   this in CSS means taking the chips out of the flow they belong to: a grid
   row below the chips centres at 945, not 922.5, since it can only centre in
   what the chips leave. So the number reproduces the frame exactly, and the
   reasoning above is here for the day the copy grows — a longer panel keeps
   this top edge instead of staying centred, which is a question for design,
   not a bug to fix silently.

   Keyed on the ROW variant, so the practice-areas band — a chip column beside
   its panel, no stacking, no plate — keeps the 26 it shares with every other
   stack in the system. */
.adv-switch-column:has(> .adv-switch-chips--row) { gap: 102px; }
/* A photograph as one half of a split — the services band's 659x491 (node
   430:8177). `.adv-split-media` is the About screen's much larger version with
   its own grid; this is just the plate. */
/* NO IMAGE CONFIGURED. The slot is real — `servicesImage` / `contactImage` in
   the CMS front matter fill it — but its default fill is `surface-alt`, which on
   a warm band is the band's own colour: the plate vanishes and the row reads as
   a column of text with a hole beside it.

   So the empty state states itself: the page surface, the system's 1px border,
   and a low-contrast diagonal hatch in the two neutral tokens, which reads as
   "a picture belongs here" rather than as a blank panel someone forgot.

   [authored — the design has no empty state for these plates] and deliberately
   NOT `.adv-imgph`: that one is styleguide scaffolding, says so in its own
   comment, and its hatch is loud enough to look like a rendering fault on a
   real page. Same idea, quieter, and allowed to ship. */
.adv-band__media--empty {
  background-color: var(--adv-color-surface);
  background-image: repeating-linear-gradient(45deg,
    transparent 0 14px,
    var(--adv-color-surface-alt) 14px 28px);
  border: var(--adv-border-width) solid var(--adv-color-border);
}
/* `.adv-band__media--services` used to sit here and lost — see the base rule
   below, where it now lives. */
/* The mobile-only inline plate (see sections/services.html) — hidden until
   the mobile step swaps it in for the plates column. */
.adv-band__media--inline { display: none; }
.adv-listing-photo { display: none; }
.adv-lede-mobile { display: none; }
/* `.adv-article-areas-label` was here, hidden above the mobile step. The label
   is drawn on the DESKTOP frame too (492:4581) — the row simply lives below
   the body on both tiers now, so there is nothing left to hide and nothing left
   to reorder. See `.adv-article-areas`. */

/* ---------------------------------------------------------------------
   Expert detail                          nodes 307:6047 / 704:30027
   The desktop screen exists now (AK, 2026-08-31); this used to be a
   constrained single column because it did not.

   311:6801 is the master's `600 + 60 + 660` again — the right column
   starts at 720, the container's midpoint, exactly as the practice-areas
   band, the articles head, the About map and every closing band do.

     left   a 494x494 portrait, and 26 under it two sub-columns at 0 and
            330 inside the 600 (the frame's x=60 and x=390)
     right  the name at 58/70, role and place under it, the outlined CTA
            at the column's right edge, and the biography blocks on a 34
            rhythm with 12 between each label and its text
   --------------------------------------------------------------------- */
/* 45 UNDER THE BREADCRUMBS (307:6050 ends at 405, the portrait opens at 450).
   `.adv-breadcrumbs` carries no bottom padding, so on this tier every detail
   page supplies its own gap below the trail. This was 42 — matched to the
   insight page's `--adv-space-42` title gap, "one off-scale token is not worth
   3px" — until AD-139 settled the detail rhythm (ADR-0025 Amendment 3): 307:6269
   puts the portrait at 450 = 380 + 25 + 45 (416 since the trail moved to 26 under
   the plate, ADR-0030 Amendment 1 §6 — the 45 is unchanged), the same 45 the practice-area and
   service heads already use (`.adv-detail-head--indent`). A documented literal,
   as theirs is. The article keeps its 42; its frame was not redrawn. */
.adv-expert-detail {
  display: grid;
  grid-template-columns: minmax(0, 600px) minmax(0, 660px);
  justify-content: space-between;
  gap: var(--adv-space-60);
  align-items: start;
  margin-block-start: 45px;
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding-inline: var(--adv-section-pad-x);
}
.adv-expert-detail__aside,
.adv-expert-detail__main { display: flex; flex-direction: column; }
/* THE NAME COLUMN AND THE CTA SHARE A ROW at the top of the right column —
   343:12258 sits at x=1170, hard against the container's right edge, level with
   the name at y=450/460. A flex row rather than a float so the button keeps its
   own height and the identity block keeps the measure. */
.adv-expert-detail__main {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  row-gap: 64px;
}
.adv-expert-identity { grid-column: 1; }
/* Nudged down against the name: 343:12258 sits at y=460 where the name block
   starts at 450, so the button lines up with the cap-height of a 70px line
   rather than with the top of its box. The frame's exact 10, a documented
   literal (the spacing scale has no 10 step): this was 8 — "a one-off token for
   an optical nudge is a worse trade than 2px" — until AD-139's rhythm pass
   measured every head against its frame, and 458 was the one number left off. */
.adv-expert-cta { grid-column: 2; justify-self: end; margin-block-start: 10px; }
/* THE BUTTON CARRIES BOTH LABELS AND THE WIDTH PICKS ONE — the generic
   "Contact legal expert" the desktop frame draws (343:12258) and the named
   "Contact Wim Smet" the 402 frame draws (760:18353). Same device as
   `view-all.html`'s long/short pair, and for the same reason: one control, two
   frames, no second element in the markup to drift out of sync. */
.adv-expert-cta__named { display: none; }
.adv-expert-bio { grid-column: 1 / -1; }
.adv-expert-name {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-display-weight);
  font-size: var(--adv-display-size);
  line-height: var(--adv-display-lh);
  color: var(--adv-color-primary-dark);
}
/* Role and place are two 25px lines 4 apart under a 70 name (307:6628 puts the
   pair at +78 of a 132 block). */
.adv-expert-role {
  margin: var(--adv-space-4) 0 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
.adv-expert-identity .adv-expert-role:first-of-type { margin-block-start: var(--adv-space-8); }
/* "Legal expert at ADVERIT ANTWERP" (307:6271): the office in the primary blue,
   like the card's and the insight byline's, and a link to the firm's page. */
.adv-expert-office { color: var(--adv-color-primary); text-decoration: none; }
a.adv-expert-office:hover { text-decoration: underline; }
/* The four biography blocks, 34 apart, each a label 12 above its copy, in a
   619 column (307:6661 — the frame's measure, a documented literal; the grid
   track is 660). */
.adv-expert-bio { display: flex; flex-direction: column; gap: var(--adv-space-34); max-width: 619px; }
.adv-expert-bio__block { display: flex; flex-direction: column; gap: var(--adv-space-12); }
.adv-expert-bio__block .adv-section-label { margin: 0; }
/* THE FIRM'S OWN PROSE (AD-139, ADR-0026). `intro` and `experience` are plain
   text from the CMS's `text` widget, printed escaped; `pre-line` keeps the
   firm's line breaks without letting their indentation through. The body is
   Markdown in `.adv-prose`, whose paragraphs sit 16 apart here (307:6661's two
   paragraphs) against the article's 24 — `:not(:last-child)` because the base
   rule that zeroes the last child is less specific than this one. All of it
   in ink (the frame's #3C3C3C), not the article body's secondary grey. */
.adv-expert-bio__text {
  margin: 0;
  white-space: pre-line;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
.adv-expert-bio .adv-prose > :is(p, ul, ol, h1, h2, h3, h4):not(:last-child) { margin-block-end: var(--adv-space-16); }
.adv-expert-bio .adv-prose :is(p, li) { color: var(--adv-color-ink); }
/* Education is a LIST, not prose (307:6705): the years at x=0 and the
   institution at x=122 — a 122 track with no gap, the frame's own offset —
   with the degree under the institution in the secondary grey. */
.adv-expert-education { display: flex; flex-direction: column; gap: var(--adv-space-16); margin: 0; padding: 0; list-style: none; }
.adv-expert-education__row { display: grid; grid-template-columns: 122px minmax(0, 1fr); column-gap: 0; row-gap: var(--adv-space-12); color: var(--adv-color-ink); }
/* A ROW WITHOUT YEARS (AD-150, ADR-0030 Amendment 13). `years` is optional in the CMS; the
   templates then print no years cell and mark the row `--undated`, and its one track puts the
   institution and degree at x=0 instead of 122 with nothing to their left. A dated row beside
   it keeps the frame's offset. At ≤560 every row is one track already (below). */
.adv-expert-education__row--undated { grid-template-columns: minmax(0, 1fr); }
.adv-expert-education__years { color: var(--adv-color-ink); }
.adv-expert-education__institution,
.adv-expert-education__degree { display: block; }
.adv-expert-education__institution { font-weight: var(--adv-weight-medium); }
.adv-expert-education__degree { color: var(--adv-color-body); }

.adv-expert-photo {
  width: 494px;
  max-width: 100%;
  aspect-ratio: 1;
  border-radius: var(--adv-radius-card);
  background-size: cover;
  background-position: center;
}
.adv-expert-photo--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--adv-color-accent-light-blue);
  color: var(--adv-color-primary-dark);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-monogram-size);
}
.adv-expert-sub { margin: var(--adv-space-8) 0 0; }
/* TWO SUB-COLUMNS 26 UNDER THE PORTRAIT (311:6799 at x=60 / 311:6800 at x=390 —
   0 and 330 inside the 600 column, which is the 122 the education list uses
   again at a different scale). A column with no slots filled collapses instead
   of leaving a labelled gap. */
.adv-expert-facts {
  display: grid;
  grid-template-columns: 330px minmax(0, 1fr);
  align-items: start;
  margin-block-start: var(--adv-space-26);
}
.adv-expert-facts__col { display: flex; flex-direction: column; gap: var(--adv-space-34); }
.adv-expert-facts__col:empty { display: none; }
.adv-expert-fact { display: flex; flex-direction: column; gap: var(--adv-space-12); }
/* THE FACT LABEL IS 14px SECONDARY, NOT THE 24 BURGUNDY SECTION LABEL. 311:6789
   and its siblings measure 17 tall — a 14px line — where `.adv-section-label` is
   the uppercase 24 that heads a whole band. Using that here made "Languages"
   shout louder than the person's name.
   The colour is #51595F (`color-body`), not ink: every one of these four labels
   reads secondary in the frame, one step back from the values under them, which
   is what makes the pair read as label-then-fact rather than two equal lines. */
.adv-expert-fact__label {
  margin: 0;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-body);
}
.adv-expert-fact__tags { display: flex; flex-wrap: wrap; gap: var(--adv-space-8); }
/* THE VALUE IS 14/17, THE SAME SIZE AS ITS LABEL — only the colour separates
   them (311:6788 measures 17 tall, as does its "Languages" label above it, and
   the contact rows beside it are 14 too). It inherited the page's 16/25, which
   made "English" a step larger than the e-mail and phone directly above it in
   the same column — the one place on this page where two sibling facts were set
   at different sizes. 402 puts these back to 16 (704:30329), where the frame
   does size them up. */
.adv-expert-fact__value {
  margin: 0;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
}
.adv-expert-fact__value a { color: var(--adv-color-primary); }
/* The e-mail is the one contact row the frame draws in corporate blue (309:6776);
   the phone and the address are ink. That is the frame's own logic — it makes a
   link look like a link — and it holds here even though we also wrap the phone
   in `tel:` for usability, which the frame could not. Scoped to this page rather
   than pushed into `.adv-contact-list`, whose satellite frame is all-ink. */
.adv-expert-detail .adv-contact-list a[href^="mailto:"] { color: var(--adv-color-primary); }

/* THE SATELLITE EXPERT PAGE (343:11878 as redrawn, AD-145 — ADR-0030 §7): the master's grid
   with the satellite's own values — the biography 58 under the name block (553 → 611), the
   portrait as an <img>, and the contact rows as the frame draws them: glyphs 28 × 22,
   22 × 22 and 19.5 × 24 in rows 30 / 28 / 32, 2 apart, the e-mail underlined IN INK
   (the master's is blue). */
.adv-expert-detail--sat .adv-expert-detail__main { row-gap: 58px; }
img.adv-expert-photo { display: block; object-fit: cover; }
/* Two classes: the base list (further down) sets its 8 gap at one. */
.adv-contact-list.adv-contact-list--frame { gap: 2px; }
.adv-contact-list--frame li { min-height: 28px; }
.adv-contact-list--frame .adv-contact-list__mail { min-height: 30px; }
.adv-contact-list--frame .adv-contact-list__pin { min-height: 32px; }
.adv-contact-list--frame .adv-contact-list__mail .adv-icon--meta { width: 28.5px; height: 22.5px; }
.adv-contact-list--frame .adv-contact-list__pin .adv-icon--meta { width: 19.5px; height: 24px; }
.adv-expert-detail--sat .adv-contact-list a[href^="mailto:"] {
  color: var(--adv-color-ink);
  text-decoration: underline;
}

/* The mobile filter sheet's own chrome (trigger, bar, bottom actions) —
   desktop keeps the inline pills and never sees these. */
.adv-filters-open,
.adv-filters-bar,
.adv-filters-head,
.adv-filters-actions { display: none; }
/* The stack of plates a switcher swaps between. One is shown at a time, so the
   wrapper takes the grid cell and each plate fills it; with no JS they simply
   stack, which is what every other part of this band does without a script. */
.adv-band__plates { display: flex; flex-direction: column; gap: var(--adv-space-24); }
.adv-band__plates > * { flex: 1; }
.adv-band__media {
  min-height: 491px;
  border-radius: var(--adv-radius-card);
  background-color: var(--adv-color-surface-alt);
  background-size: cover;
  background-position: center;
}
/* AFTER the base rule, not before: both are one class deep, so the cascade
   decides and the loser is whichever is written first. */
.adv-band__media--tall { min-height: 660px; }   /* the closing CTA's 625x660 plate */
/* The services plate crops to the frame's own focal point — `46.523% 90.873%`,
   near the BOTTOM edge — instead of the base rule's centre.

   IT USED TO BE WRITTEN ABOVE THE BASE RULE and therefore never applied: same
   one-class depth, so `background-position: center` won on order alone. The
   design's crop was authored, documented to three decimals, and dead — which is
   why every plate had been showing the middle of its photograph. The comment
   above exists because `--tall` was caught by exactly this first.

   What it does and does not change: with `cover` the vertical half only bites on
   a source TALLER in proportion than the 659x491 plate. Of the four service
   photographs only `services-var1` is portrait, so that is the one that visibly
   drops to its foot; for the three landscape shots cover is height-driven and
   this shifts the crop 3.5% left, nothing more. */
.adv-band__media--services { background-position: 46.5% 90.9%; }
/* UNUSED SINCE 623:21979, kept the way `--tight` and `--flush` are kept. It was
   the master homepage's "Not sure what kind of legal support you need?" band,
   read off 430:8177 as the one band on pure white. `623:21979`, read 2026-08-31,
   fills that rectangle `background/main` #FAF9F7 — the page surface — and sizes
   it to its own content, so the band has neither a plate nor padding of its own
   and carries `--flow` + `--help` instead.

   "THE CURRENT FRAME" WAS THE WORDING HERE AND IT NO LONGER PICKS OUT ONE FRAME
   (MD, 2026-09-07): `623-21932`, the desktop frame, does not draw this band at
   all now — see the note below — while the mobile frame does. The 2026-08-31
   reading stands for the band as the mobile tier draws it; it is not a statement
   about the desktop composition. Nothing else in either theme asks for a white
   band; this stays for the next one that genuinely does. */
.adv-band--white { background: var(--adv-color-white); }
/* "NEED HELP?" (1482:29871). ON EVERY TIER SINCE 2026-09-16 (AD-137) — it was
   mobile-only from AD-126 item 19 (ADR-0021 §8), and this rule was the switch
   that hid it on desktop. The 2026-09-16 frame draws it first after the hero,
   so the switch is gone and ADR-0021 §8 records the reversal.

   What `--help` carries now is the frame's own. The group is 239 tall with its
   heading 18 in and its pill ending 18 short of the bottom, so the content is
   inset 18 on both edges — which is also what puts Services 96 below it at the
   frame's y. Inside, 18 between the heading, the line and the pill (heading
   18→110, line 128→153, pill 171→221), and the line in Text Main rather than
   the Text Secondary `.adv-band__text` defaults to — on one line, where the
   base caps that class at 544. */
.adv-band--help .adv-band__inner { padding-block: 18px; }
.adv-band--help .adv-stack { gap: 18px; }
.adv-band--help .adv-band__text { max-width: none; color: var(--adv-color-ink); }

/* ---------------------------------------------------------------------
   Chip switcher                                          node 430:8177
   A set of category tags selects which panel of copy shows beside them:
   a column on the practice-areas band, a row on the services band.

   The chips are ANCHORS and every panel is rendered. With no JS the page
   is a readable stack of areas, each linking to the directory filtered to
   it; JS collapses that stack to one panel at a time. See site.js.
   --------------------------------------------------------------------- */
.adv-switch-chips {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-16);
  align-items: flex-start;
}
.adv-switch-chips--row {
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--adv-space-8);
  /* CENTRED, not top-aligned. The active category tag is deliberately bigger
     than an inactive one — 183x45 against 105x37, a size step, not just a
     recolour (see `.adv-badge--active`). Top-aligned, that difference hangs the
     selected chip below the row; centred, the row keeps one axis. */
  align-items: center;
  /* THE ROW IS WIDER THAN ITS COLUMN, and 623:21973 is explicit about it: the
     chips span 622 (x=60 to 682) while the panel title and copy beneath them
     hold a 563 measure, and the photograph does not start until 722. So the
     row reaches into the split's gutter and nothing collides.

     It has to be said, because the column is 563 and four chips need 622 —
     held to the column the fourth wrapped to a second line, against a comp
     that fits one. `max-content` takes the row's natural width; the cap is the
     column plus the split's own 60px gap, which is the gutter's guaranteed
     minimum (`--media` adds the leftover on top via space-between). So the
     row grows into space that is always there and stops before the photograph
     at every width, and a longer set of labels still wraps rather than
     overlapping it. */
  width: max-content;
  max-width: calc(100% + var(--adv-space-60));
}
/* A section CTA whose listing is not built yet. The design's own disabled
   treatment (`.adv-btn[aria-disabled]`) is a filled grey pill, which shouts on a
   band where the live CTAs are outlines — so an unbuilt one keeps the outline
   and goes muted, matching the inert nav items and `.adv-link-more`. */
.adv-btn--secondary[aria-disabled="true"] {
  background: transparent;
  border-color: var(--adv-color-border);
  color: var(--adv-color-ink-muted);
  cursor: default;
}
/* The label + copy + cards stack in the partner-firms band: 34 between the copy
   and the row of cards, which is the card's own padding step, not a section gap. */
.adv-card-row--spaced { margin-block-start: var(--adv-space-34); }
.adv-switch-panel {
  display: flex;
  flex-direction: column;
  gap: var(--adv-stack-gap);
  align-items: flex-start;
}
/* THE CLOSING CTA (1482:29966, 2026-09-16). Its column is centred on the 660
   plate — 308 of copy starting 176 down — with 34 between the statement, the
   line and the button (it was 48 between a statement and a button in the
   430:8177 comp). The statement is set to its frame box, 481, which is what
   breaks "Need support / across borders?"; the line to its 459, in Text Main.
   The plate is 625 wide, flush with the container's right edge at x=1380 —
   narrower than the 660 track it sits in. Only the homepage renders this. */
.adv-switch-panel--cta {
  align-self: center;
  gap: var(--adv-space-34);
}
.adv-switch-panel--cta .adv-display { max-width: 481px; }
.adv-switch-panel--cta .adv-band__text { max-width: 459px; color: var(--adv-color-ink); }
.adv-band__split:has(> .adv-switch-panel--cta) > .adv-band__media--tall {
  justify-self: end;
  width: 625px;
}

/* Cross-fade on switch. A DISSOLVE and nothing else: the band is a switcher,
   not a slideshow, so the outgoing panel — and on the services band the
   photograph that belongs to it — goes to zero and the incoming one comes back
   from it, with no slide, no scale, nothing that implies a direction the
   content does not have.

   240ms, written here and NOWHERE ELSE: site.js reads this duration back off
   the element with getComputedStyle to know when the panel is invisible and
   the swap can land. Two numbers that have to agree should not be two numbers.
   (The literal follows the carousel's own 420ms — motion has no measured
   provenance in the file, see the Motion block in tokens.css, and
   --adv-transition-fast is the 0.15s hover step, too quick to cover a swap.)

   Scoped under [data-switcher] rather than put on .adv-band__media outright:
   that class is the plate on every band in the theme, and only these two swap
   what is behind it. */
.adv-switch-panel,
[data-switcher] .adv-band__media {
  transition: opacity 240ms var(--adv-ease);
}
[data-switcher][data-switching] .adv-switch-panel,
[data-switcher][data-switching] .adv-band__media { opacity: 0; }
/* Reduced motion gets the instant swap, and site.js reads the 0s back and
   skips its own wait with it — so the band still rotates, it just cuts. */
@media (prefers-reduced-motion: reduce) {
  .adv-switch-panel,
  [data-switcher] .adv-band__media { transition: none; }
}
/* "7 experts · 3 offices" — corporate blue, small. The count line, not a caption:
   the Home practice-area and services panels (ADR-0030 Amendment 2 §5). */
.adv-switch-panel__meta {
  margin: 0;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-primary);
}
.adv-switch-panel__text {
  margin: 0;
  max-width: 400px;   /* the comp's measure; the panel itself is 660 */
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-body);
}

/* HOW WE CAN HELP — a practice area's services and each pair's topics, both tiers (AD-162,
   ADR-0038 §AD-162 §4 and §7; 294:3588 / 343:11471, 681:27056 at 402). The partial is
   `partials/how-we-can-help.html`, mirrored; the behaviour is the homepage's chip switcher
   and its 240 ms fade (`.adv-switch-panel`, above), with no autoplay.

   Measured in 294:3588 (the 1320 box): the label (24 Medium caps, its AUTO 29 box) → 26 →
   the chips (gap 16, rest 37 / active 45 — the `.adv-badge` states, centred on one axis) →
   54 → the panel: the heading (38 Semi Bold navy, 46) → 16 → the service's text (16 / 25
   ink, 517 wide) beside the topics at 663, 657 wide, level with the heading. A topic row
   is the name (24 / 1.5 ink) → 12 → the count (14, blue figures, grey dot) = 65; "View
   topic ↗" (16 Medium blue) ends at 1320, centred on the row (+20); the rows are a V
   stack of gap 26 whose separator is a LINE of no height, so the pitch is 65 + 52 = 117.

   THE VALUES NO TOKEN CARRIES are scoped here (ADR-0025 §5's pattern); a second consumer
   would make them tokens, in all three files. The rest is tokens: 26, 16, 12, 24, 34,
   the lead / body / small / caption type, the 8 mobile radius, the mobile tile gap. */
.adv-help {
  --adv-help-panel-gap: 54px;    /* chips → panel (294:3588) */
  --adv-help-col-gap: 146px;     /* 517 + 146 + 657 = the 1320 box */
  --adv-help-row: 65px;          /* a topic row: the name's 36 + 12 + the count's 17 */
  --adv-help-m-heading: 32px;    /* 681:27056: the 402 heading, 32 Medium / 1.1 */
  --adv-help-m-text-lh: 20px;    /* 681:27056: the 402 text, 14 / 20 */
}
/* Its own gap and measure over `--row`'s: 16 between chips, and never wider than the box
   (`--row` lets a band's chips run 60 into the page margin). Single-class and after
   `--row`, so the ≤860 gap and the ≤560 scroller (both later) still win. */
.adv-help__chips {
  margin-block-start: var(--adv-space-26);
  gap: var(--adv-space-16);
  max-width: 100%;
}
/* The service's two names (MD, 2026-09-26): `name` here, `short` at ≤560. */
.adv-help__short { display: none; }
/* After `.adv-switch-panel` in the source, so the grid wins over its flex column; the
   fade and `[hidden]` (base.css, !important) are untouched. The gap is on every panel —
   the hidden ones have no box — so it cannot double. */
.adv-help__panel {
  display: grid;
  grid-template-columns: minmax(0, 517fr) minmax(0, 657fr);
  column-gap: var(--adv-help-col-gap);
  align-items: start;
  margin-block-start: var(--adv-help-panel-gap);
}
.adv-help__lead {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-16);
}
.adv-help__heading {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h1-size);
  line-height: var(--adv-h1-lh);
  color: var(--adv-color-primary-dark);
}
/* THE HEADING LINKS TO ITS PAGE (AD-173, ADR-0038 §AD-173): the service's on an area page, the
   area's on a service or topic page. The link is the heading's text, navy and not underlined —
   the heading as it was — with the site's focus ring; burgundy under the pointer below. A
   heading without a page is plain text. */
.adv-help__heading-link {
  color: inherit;
  text-decoration: none;
}
a.adv-help__heading-link:focus-visible {
  outline: var(--adv-focus-ring-width) solid var(--adv-focus-ring);
  outline-offset: var(--adv-focus-ring-offset);
}
.adv-help__text {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
.adv-help__topics {
  margin: 0;
  padding: 0;
  list-style: none;
}
/* `content-box`: the 65 is the row, and the rule's 26 + 1 + 25 sit outside it. The second
   track is `1fr` so a topic with no count line (nobody attached yet) still has a 65 row and
   its "View topic" sits where every other row's does (+20), not on the name alone.

   THE WHOLE ROW IS THE LINK (AD-172, ADR-0038 §AD-172 §1): the ≤560 card's technique at every
   width. The row is the containing block of the link's `::after` (below), which covers its
   padding box — the 25 under the rule and the 65 row; the 26 margin over the next row's rule
   stays a gap. */
.adv-help__topic {
  position: relative;
  box-sizing: content-box;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto 1fr;
  column-gap: var(--adv-space-26);
  min-height: var(--adv-help-row);
}
.adv-help__topic + .adv-help__topic {
  margin-block-start: var(--adv-space-26);
  padding-block-start: calc(var(--adv-space-26) - var(--adv-border-width));
  border-block-start: var(--adv-border-width) solid var(--adv-color-border);
}
/* A Dutch or German compound ("Aandeelhoudersovereenkomsten") is wider than the name's
   track once the split narrows (~230 at 861): it breaks, hyphenated in the two
   compounding languages, rather than running under "View topic" — the `--long-words`
   rule of the area cards. */
.adv-help__topic-name {
  grid-column: 1;
  overflow-wrap: anywhere;
  font-size: var(--adv-lead-size);
  line-height: var(--adv-lead-lh);
  color: var(--adv-color-ink);
}
.adv-help__topic-name:is(:lang(nl), :lang(de)) { hyphens: auto; }
/* The area card's count line: the figures blue, the dot body grey, a figure never split. */
.adv-help__topic-meta {
  grid-column: 1;
  align-self: start;
  margin-block-start: var(--adv-space-12);
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-body);
}
.adv-help__stat {
  white-space: nowrap;
  color: var(--adv-color-primary);
}
.adv-help__view {
  grid-column: 2;
  grid-row: 1 / -1;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  font-weight: var(--adv-weight-medium);
  color: var(--adv-color-primary);
  text-decoration: none;
}
/* The stretched link (AD-172): the anchor's `::after` covers the row, so a click on the name,
   the count line or the space between opens the page, and the label's hover colour below
   shows with the pointer anywhere on the row. The anchor stays where it is and keeps its
   focus ring above 560; out of the flex flow, the `::after` adds no gap. A row without a page
   is a `<span>` and has none. A SECOND LINK IN A ROW would sit under this one — it needs its
   own stacking (`how-we-can-help.html`'s header note). */
a.adv-help__view::after {
  content: "";
  position: absolute;
  inset: 0;
}
/* No topic page yet (AD-164 builds them): the label stays, inert and muted — the rule of
   "Discuss your legal matter" (`.adv-btn--secondary[aria-disabled]`) and the inert nav. */
.adv-help__view[aria-disabled="true"] {
  color: var(--adv-color-ink-muted);
  cursor: default;
}
/* BURGUNDY UNDER THE POINTER, NOT UNDERLINED (AD-172 A1, ADR-0038 §AD-172 Amendment 1 §1):
   the `button` set's `state=hover` (513:4490) draws the label and the ↗ in #652C35 with no
   underline — every blue link's hover here (`.adv-link-more`, the rail, the crumbs). The ↗
   follows the label (`.adv-icon`). The inert `<span>` has none.
   THE ROW'S NAME FOLLOWS (AD-173, ADR-0038 §AD-173 §2): the pointer anywhere on the row is on
   the link's `::after`, so the name turns burgundy with "View …"; an inert row does not. The
   panel's heading link (above) turns burgundy the same way. */
@media (hover: hover) {
  a.adv-help__view:hover { color: var(--adv-hover-accent); }
  .adv-help__topic:has(> a.adv-help__view:hover) .adv-help__topic-name { color: var(--adv-hover-accent); }
  a.adv-help__heading-link:hover { color: var(--adv-hover-accent); }
}
/* TOPICS BY PRACTICE AREA — the block above, switched by THE SITE'S FILTER PILL (AD-163,
   ADR-0038 §AD-163 §4 and §7; 336:7720 / 343:12313 at 1440, 1734:29837 at 402). The pill is
   `.adv-filter` over a `.adv-filter-panel` — the hero's selects' pattern, `.adv-filter-wrap`
   placing the menu under it — and each row is one of the switcher's chips: an anchor,
   current by `aria-current` (the row's selected style above).

   Measured in 336:7720 (the 1320 box, block 1734:31366): the label (24 Medium caps, its
   AUTO 29) → 24 → the pill ("Frame 14", 208 × 60: the facet pill as it is) → 54 → the
   panel: the heading (38 Semi Bold navy, 46) → 16 → the area's text (16 / 25 ink) beside
   the topics, level with the heading. THE SPLIT IS 660 | 660, where the area page's is
   517 + 146 + 657, and the panel stacks at ≤860 as the area page's does. The rows are How
   we can help's.

   48 BETWEEN THE TEXT AND THE TOPICS (AD-164, ADR-0038 §AD-164 Amendment 1). The frames draw
   the two columns touching (1734:30746: the text box 60–720, the topics from 720) and MD kept
   that 0 down to 861 at the AD-163 plan; the frame's sample text only happens to wrap short of
   it (its longest line is ~605 of 660). A real area's text ran to 6 px from a topic's name on
   dev (Commercial law, 2026-09-28). So the LEAD — heading and text — ends 48 short of the
   topics, which stay at the frame's 720: 612 wide at 1440, which the frame's own text still
   fits line for line. Stacked (≤860) it has no neighbour and no gutter.

   Every value is a token or the block's own, so nothing is scoped here. Every rule sits
   under the modifier at (0,2,0), or on the menu's own class: the block's rules and the
   ≤1100 / ≤860 / ≤560 ones are single-class, and AD-162's page must not move. */
.adv-help__menu { margin-block-start: var(--adv-space-24); }
/* ONE ENTRY DRAWS NO PILL (ADR-0038 §AD-172 Amendment 1 §2): the label is followed by the
   panel, and the panel's heading sits 24 under it at every width — the block's label →
   first child, as label → pill is. MD at the plan, over the pill's 54. (0,3,0), so the
   base's 54 and the ≤560 34 / 24 do not reach it. */
.adv-help--menu .adv-section-label + .adv-help__panel { margin-block-start: var(--adv-space-24); }
/* A PANEL OPENED BY THE URL'S HASH (AD-164, ADR-0038 §AD-164 §6): a topic page's "View
   service" lands on `/services/<slug>/#topics-<area>`. The browser jumps to the panel by
   itself (more than once, while the page loads) and the MIRRORED script does too, so the
   panel — its heading naming the chosen area — stops below the site's sticky bar: the bar's
   row and its 1 px rule, and the mobile bar's at ≤560. A panel is scrolled to only then (and
   by a no-JS chip, which lands the same way). */
[data-switcher-panel] { scroll-margin-top: calc(var(--adv-nav-h) + var(--adv-border-width)); }
.adv-help--menu .adv-help__panel {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: 0;
}
.adv-help--menu .adv-help__lead { padding-inline-end: var(--adv-space-48); }
/* A long area name wraps inside the menu rather than widening it: the row is `nowrap` for
   the listings' short values. */
.adv-help--menu .adv-filter-panel__row { white-space: normal; }
/* A Dutch or German compound in the heading breaks at a syllable (ADR-0033 Amendment 1). */
.adv-help--menu .adv-help__heading:is(:lang(nl), :lang(de)) { hyphens: auto; }
/* Body copy in a band, at the measure the comp gives it. Three widths appear on
   the master homepage — 400 in a switch panel (above), 544 under the About
   statement, 742 under the partner-firms label — and they are the design's, not
   a typographic rule, so they are named rather than inlined per template. */
.adv-band__text {
  margin: 0;
  max-width: 544px;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-body);
}
.adv-band__text--wide { max-width: 742px; }
/* THE WHOLE COLUMN, NO MEASURE: About's vision and mission run the full 660 of
   their column (1482:33819, 1482:33822 — AD-138), where the 544 cap broke them a
   line later than the frame and grew the band by 50. */
.adv-band__text--fill { max-width: none; }
/* BODY COPY IN INK, not the secondary grey (AD-143): the careers intro (589:16352), the
   positions lede and the vacancy page's office copy are `text/main` in their frames. */
.adv-band__text--ink { color: var(--adv-color-ink); }
.adv-stack {
  display: flex;
  flex-direction: column;
  gap: var(--adv-stack-gap);
  align-items: flex-start;
}
/* Three other rhythms the same stack takes. Two are measured on the master About
   screen's description column (279:2389): 34 between its four blocks — the
   statement, the running copy, "Our vision" and "Our mission" — and 12 between
   a heading and the paragraph that belongs to it. Modifiers rather than three
   more layout classes: it is the same stack at a different step. */
.adv-stack--wide  { gap: var(--adv-space-34); }
/* A LABEL AND THE CARD ROW UNDER IT, 63 APART TOP TO TOP (385:5003 → 385:5005, AD-142;
   About's offices head is the same 63, 1482:33863). The label's box is 24 here and 29 in
   the frame, so 39 is what is left. Restated as the stack's own gap in the ≤860 block,
   where the tiers keep their rhythm. */
.adv-stack--labelled { gap: 39px; }
/* A LABEL AND THE LONG ROWS UNDER IT, 83 APART TOP TO TOP (AD-168): About's values (1655:25406 →
   1655:25373) and Join's benefits (385:5073 → 385:5038's list). The frame's 54 is measured from its
   label's 29 box; ours is 24, so 59 — the careers "why join" arithmetic. Restated at ≤860 (54,
   what the old Join steps kept there) and ≤560 (24, why-join's 402). */
.adv-stack--rows { gap: 59px; }
.adv-stack--tight { gap: 12px; }
/* About's "our approach" band (336:11104), label to the first row.
   A MODIFIER AND NOT A MARGIN ON THE LABEL, which is what this was: the label
   carried an inline `margin-bottom` INSIDE a `.adv-stack`, and flex `gap` and
   margin ADD. 26 + 54 rendered 80 where the frame asks for 56 — measured on
   /en/about/ at 1440, label box 1988.34..2012.34 against the rows at 2092.34.
   The same stacking the homepage's band rhythm was corrected for, one level
   down: there two paddings met, here a gap and a margin.
   The offices band below it looks identical and is NOT affected — its inner is a
   plain `.adv-band__inner` with no stack, so its label's margin is the only
   spacing in play. Which is exactly why this one survived review. */
.adv-stack--approach { gap: var(--adv-sat-approach-gap); }
/* A row of buttons — the hero's two CTAs, About's pair. 14px is the design's
   gap between adjacent buttons (336:10816), narrower than any spacing step. */
.adv-cta-row { display: flex; gap: 14px; flex-wrap: wrap; }

.adv-card-row { display: flex; gap: var(--adv-card-gap); align-items: stretch; }
.adv-card-row > * { flex: 1 1 0; min-width: 0; }
/* A row of fewer than three firm tiles must not inflate to fill the container.
   The design draws this card at 400 wide (516:6773) and nothing in the frame
   makes it wider; with `flex: 1 1 0` a one-firm network rendered a single
   1320-wide tile — a photograph letterboxed to 1320x270 (or the monogram
   floating in a 1320-wide empty plate) over a 309px panel holding the name at
   its top and the tags at its bottom, with the hole between them.

   A CAP, not a basis: at three across the row already computes 400 each
   (1320 = 400*3 + 60*2), so this never binds on the designed row — it only
   stops one or two cards from stretching. Below 1100 the wrap rule bases them
   at 50%, which the cap also holds to 400; the 402 rail fixes its own 270
   basis and is untouched. */
.adv-card-row:has(.adv-firm-card) > * { max-width: 400px; }
/* The careers landing's three postings (AD-143): the same cap, for a network with one
   or two openings. */
.adv-card-row:has(.adv-vacancy-card) > * { max-width: 400px; }

/* ---------------------------------------------------------------------
   Large practice-area card                               node 288:3219
   400x290, a numbered maroon badge, a 28px INK title over body copy that
   starts at a FIXED 96 inside a 171px box (item 15 — it used to be pinned
   to that box's BOTTOM, which is why its top moved with its own length).

   THE TITLE WAS 38 AND NAVY, and both were the same mistake read twice (AK,
   2026-08-31). The component names its title style `Heading/regular_28px` —
   `--adv-h2-size`, which the token file's own h4 note already identified as the
   card-title role — in EVERY variant, and colours it `#3C3C3C` at rest. The
   navy is the HOVER colour: 288:3219's `hover` variant is the only one that
   sets `#122448`, and tokens.json's `cardHoverWash` spells out "plus scale(1.05)
   and the title to navy". We were painting the hover state at rest, which is
   why hover then had nothing left to say.

   This is a SECOND card family, not a replacement: the compact 475x168
   cards above are what the listing screens use, and this is what the
   homepage rows use. Both are in the file; an earlier pass saw only one.
   --------------------------------------------------------------------- */
.adv-area-card {
  position: relative;
  display: block;
  min-height: 290px;
  padding: 22px var(--adv-space-26) var(--adv-space-26);
  background: var(--adv-color-surface-alt);
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-card);
  text-decoration: none;
}
.adv-area-card__num {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-pill);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: 1;
  color: var(--adv-color-accent-burgundy);
}
/* The mobile EXPANDED card's explore row and corner arrow (664:25866 via
   760:17096) — mobile-only furniture, hidden until the ≤560 block shows
   them on the stack's first card. */
.adv-area-card__more,
.adv-area-card__corner { display: none; }
/* ITEM 15: A FIXED 12, NOT `justify-content: space-between` (AD-126, 288:3219).
   `space-between` pinned the copy to the FOOT of the 171 box — `__more` is
   `display: none` above 560, so the box has exactly TWO rendered children on
   desktop — and the copy's top was therefore `171 - (lines x 25)`: 121 under a
   two-line description, 96 under a three-line one. `areas.yaml` runs 59 to 91
   characters, i.e. BOTH, so a three-up row started its copy on two heights 25px
   apart. That is the report, exactly; the title never moved.

   The frame does not DISTRIBUTE the free space, it RESERVES it:

       171  =  84                 +  12              +  75
               two title lines       --adv-space-12     three body lines
               of 28 / 1.5                              of 16 / 25

   so the gap is a fixed 12 and the title below carries the two-line slot. No new
   token and no new value: every number here is already in the token file. */
.adv-area-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-12);
  min-height: 171px;
  margin-top: var(--adv-space-16);
}
/* The description and the explore line, wrapped for the list view (AD-162: its row
   centres the one on the other — `.adv-grid--list .adv-area-card__tail`). Everywhere
   else the wrapper is not a box, so the grid card, the ≤560 accordion and the
   homepage keep their two children exactly where they were. */
.adv-area-card__tail { display: contents; }
.adv-area-card__title {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-card-title-weight);
  font-size: var(--adv-card-title-size);
  line-height: var(--adv-card-title-lh);
  color: var(--adv-color-ink);
  /* TWO LINES, RESERVED WHETHER OR NOT THEY ARE USED (288:3219, read and
     measured 2026-09-05). Be honest about which half is measured:

     MEASURED — the body box is a fixed 348 x 171, the copy's top edge a fixed 96
     from that box's top, the copy exactly three lines, the title's line box 42.
     DERIVED — that the 96 is a two-line slot (84) plus a 12 gap. All four
     variants draw a ONE-line title, so the frame never draws the two-line case
     itself; what it does fix is a 171 box with the copy's top at 96, and a
     second title line cannot push that copy down without overflowing a height
     the design fixes. `96 - 2 x 42 = 12` is --adv-space-12, not a new value.

     TWO LINES ARE LIVE, not a hypothetical the clamp defends against: at 348 the
     28px labels "Commercial & Corporate Law" and "Damage, Liability and Claims"
     wrap today — measured in the browser, 2 of 18 (the brief's third example,
     "Public & Administrative Law", does NOT wrap) — and the labels are
     translated per locale (`area_<token>` in each theme's i18n/), so English is
     not the test. Unclamped, a third line pushed __text out of the 171 box and
     the card past its designed 290 — and `grid-auto-rows: 1fr` (`.adv-grid`
     below) then dragged every card in the row to that height.

     `2em`, NOT A LITERAL 84px, and this one is load-bearing rather than tidy:
     `@media (max-width: 1100px)` re-clamps this type to `clamp(26px, 3vw, …)`.
     In `min-height`, `em` resolves against the element's OWN font-size, so
     `2em x 1.5` IS "two of this element's line boxes" at every width — 84 at the
     design width, 78 at the floor — and needs no second declaration inside the
     query. A literal 84 would over-reserve by 6px across the whole 561-1100
     band. Not `lh`, which would say it more directly: the stylesheet uses that
     unit nowhere, and this is not the change that introduces a units baseline. */
  min-height: calc(2em * var(--adv-card-title-lh));
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.adv-area-card__text {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-body);
  /* THREE LINES, then an ellipsis — 288:3219's own paragraph box is 348 x 75 at
     y=96, i.e. three lines of 16/25, and 96 + 75 = 171 closes the box flush.
     Without it a fourth line pushes the body past its 171 floor and the card
     past 290, and `grid-auto-rows: 1fr` (`.adv-grid` below) drags every card in
     the row to that height.

     AT THE DESIGN WIDTH NOTHING SHIPPED IS CUT, BUT BELOW IT SOME IS — measured,
     not assumed. `areas.yaml` runs 59 to 91 characters and never exceeds three
     lines at any width the grid produces. `services.yaml` reaches 118, and in
     the 561–860 TWO-UP band the card narrows to ~304 (inner ~252), where two of
     the nine descriptions clip. That is accepted here for the same reason
     `.adv-insight__excerpt` accepts it above: every master service card is an
     `<a>` to `/services/<slug>/`, so the tail is DEFERRED to the detail page,
     not lost. A consumer whose copy has nowhere to defer to must opt out —
     `--benefit` does, immediately below.

     The satellite ALSO truncates server-side — both its cards render
     `{{ . | plainify | truncate 130 }}` — so the same string is capped from two
     ends. Harmless: a CSS ellipsis replaces the tail rather than appending to
     it. THE TRUNCATE STAYS, but NOT because it keeps the search index and the
     copy in step — it does the opposite. `data-title` (practice-area `:100`,
     service `:41`) is built from the UNTRUNCATED summary on purpose, so search
     matches text the card does not show; the truncate caps only what renders.
     Do not "reconcile" the two by truncating `data-title`, which would shrink
     the haystack for every satellite listing. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}
/* THE BENEFIT CARD OPTS OUT OF THAT CEILING, AT EVERY WIDTH — and the exemption
   belongs to the modifier, not to a breakpoint. The ceiling above is a listing
   device: it stops one long description dragging a `grid-auto-rows: 1fr` row of
   variable-length copy. `/join/`'s band is three near-equal strings on its own
   frame (750:36858), so the clamp has no work to do there — and it has a cost.
   In the 561–860 two-up band the benefit card narrows to ~270 and ALL THREE of
   `join.yaml`'s texts (112, 116, 118 characters) clip; `_default/join.html:92`
   renders them as `<div>`, not links, so unlike the service cards above there is
   no detail page to defer the tail to and the copy is simply gone.

   `overflow` is restored with `display`, not just the display: the base's
   `overflow: hidden` is half of the clamp, and on a flex item it ALSO suppresses
   the automatic minimum size (Flexbox §4.5 applies it only when `overflow` is
   `visible`), so leaving it would keep the copy shrinkable-and-clipped. Undo
   both or neither. `display: block` rather than a larger line-clamp, because a
   line count with no frame behind it is what rule 5 exists to stop. */
.adv-area-card--benefit .adv-area-card__text {
  display: block;
  overflow: visible;
}
/* THE CARD WITHOUT ITS NUMBER (385:5005, AD-142 — Join's benefits then, its "how it works" since
   AD-168, and the satellite's number-less practice-area card): the 348 x 171 body
   at (26, 34) with nothing above it, so the card is 34 + 171 + 34 = 239 at 1440, and the
   copy sits at the body's FOOT (`justify-between` in the frame — the title keeps its
   two-line slot, so a three-line text lands at 96 either way). The 560 block's
   `--benefit` rules are the same weight and later, so the 402 card keeps its 196. */
/* 33 + the 1px border, because Figma draws the stroke INSIDE the 239 and CSS adds it
   outside (the correction `--benefit` makes at 402). */
.adv-area-card--plain { min-height: 239px; padding-block: calc(var(--adv-space-34) - var(--adv-border-width)); }
.adv-area-card--plain .adv-area-card__body { margin-top: 0; justify-content: space-between; }
/* JOIN'S "HOW IT WORKS" CARDS (385:5002, AD-168 — the `--plain` card the benefits were): the
   copy starts 130 under the card's top WHATEVER ITS LENGTH, as the frame's three do at two lines
   and at three, so the body packs from the top — the title's two-line slot (84) and the base 12
   under the 34 — not from the foot, where a two-line text landed at 155. `--benefit` is Join's
   card alone (the satellite's number-less practice-area card keeps `--plain`'s foot); the 560
   block's `--benefit` body is the same weight and later, so the 402 box keeps its own. */
.adv-area-card--benefit .adv-area-card__body { justify-content: flex-start; }

/* ---------------------------------------------------------------------
   Large expert card                                     node 343:11153
   400x604 — portrait on top with the card's radius, details below.
   --------------------------------------------------------------------- */
.adv-person-card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  border-radius: var(--adv-radius-card);
  overflow: hidden;
}
.adv-person-card__photo {
  display: block;
  width: 100%;
  aspect-ratio: 400 / 399;
  object-fit: cover;
}
/* No photo yet — the initials on the card surface, at the portrait's own
   aspect ratio so a row of cards does not go ragged when one lawyer has an
   image and the next does not. NOT `.adv-imgph`, which is styleguide
   scaffolding and says so. [authored — the design has no empty state] */
.adv-person-card__photo--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--adv-color-accent-light-blue);
  color: var(--adv-color-primary-dark);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-monogram-size);
  line-height: 1;
}

/* Panel occupies the bottom 33.94% of the card; measured from its own top edge
   the name sits at 32, the role 4 below it and the credentials 21 below that.

   `display: flex` is load-bearing, not decoration. The markup uses <span> for
   the panel and its lines so the whole card can be one <a>, and a span with no
   display is INLINE — the name, role and both credential lines run together
   into a single paragraph, and the margins below silently do nothing, because
   block margins do not apply to inline boxes. */
.adv-person-card__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: var(--adv-space-34) var(--adv-space-26);
  background: var(--adv-color-surface-alt);
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-block-start: none;
  /* THE PANEL CARRIES THE BOTTOM RADIUS ITSELF — it cannot be left to the
     card's `overflow: hidden`.

     A rounded parent with `overflow: hidden` clips what its children PAINT, and
     a square-cornered child painting a 1px border has that border sliced away
     exactly across the corner arc. The result is a card whose outline fades out
     at the bottom two corners while the top two look fine — because up there
     the child is a photograph, which has no border to lose.

     Matching the parent's radius means the border follows the same arc and
     there is nothing left for the clip to remove. */
  border-end-start-radius: var(--adv-radius-card);
  border-end-end-radius: var(--adv-radius-card);
}
/* 28/1.5 in body ink — the bound `Heading/regular_28px` style, NOT the 38px navy
   card title. The Claude Design snapshot of this component still carries 38/navy;
   the live Figma node (343:11223) has moved to 28/ink, and the file wins. Worth
   knowing that the two sources can disagree on a component this specific. */
.adv-person-card__name {
  margin: 0 0 var(--adv-space-8);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-regular);
  font-size: var(--adv-h2-size);
  line-height: var(--adv-h2-lh);
  color: var(--adv-color-ink);
}
.adv-person-card__role,
.adv-person-card__meta {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
.adv-person-card__name { margin-block-end: var(--adv-space-8); }
/* 26 to the credentials and 26 again to the tags — the panel is three blocks on
   one rhythm, not four lines with hand-picked gaps. */
.adv-person-card__role { margin-block-end: var(--adv-space-26); }

/* THE 604 CARD (1484:36538 — the 2026-09-16 Home and About, AD-145): measured from the
   panel's top, the name at 32, the role 4 under it, the two credential lines 21 under
   that, and 31 to the foot — 399 + 32 + 42 + 4 + 25 + 21 + 50 + 31 = 604, the frame's
   height (the base panel's 34 / 8 / 26 / 34 gave 619). A modifier: the base card is the
   one the 402 row and the styleguide still draw. Figma strokes inside the 604 and CSS
   adds the panel's bottom border outside its padding, so the 31 gives it back. */
.adv-person-card--compact .adv-person-card__body {
  padding-block: 32px calc(31px - var(--adv-border-width));
}
.adv-person-card--compact .adv-person-card__name { margin-block-end: var(--adv-space-4); }
.adv-person-card--compact .adv-person-card__role { margin-block-end: 21px; }

/* THE LISTING'S EXPERT CARD — OFFICE FIRST, 400 × 693 (300:5545, AD-139; the satellite's
   343:11850 since AD-145). A MODIFIER, because `.adv-person-card` is also the Home / About
   card and the 402 row. `--listing` since ADR-0030 §7 (it was `--office`, master-only):
   the satellite prints the lawyer's EDUCATION in the office line's slot, in ink, and the
   master's office line keeps its blue `__office` span.

   Three groups 26 apart — [name + role, no gap] · [the office line] · [chips] —
   in a card whose height is the frame's at 1440: 399 photo, then 34 + 67 + 26 +
   25 + 26 + 82 + 34 = 294 of panel, where 82 is two chip rows (37 + 8 + 37).
   693 is a documented literal (no token binds a card height). The chips stop
   riding `margin-block-start: auto` — the height is fixed, so there is no slack
   to pin them against — and the chip block is the one thing that gives: a
   two-line name leaves it 40, which shows one row and drops the second whole.
   Below the 1440 tier the height is released (the ≤1439 block). */
.adv-person-card--listing { height: 693px; }
.adv-person-card--listing .adv-person-card__photo { flex-shrink: 0; }
.adv-person-card--listing .adv-person-card__body {
  gap: var(--adv-space-26);
  min-height: 0;
  /* Figma strokes INSIDE the 693 and CSS adds the panel's bottom border
     outside its padding, so the 34 gives the border back — or the second chip
     row loses its bottom pixel to the clip. */
  padding-block-end: calc(var(--adv-space-34) - var(--adv-border-width));
}
.adv-person-card--listing .adv-person-card__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  flex-shrink: 0;
}
.adv-person-card--listing .adv-person-card__name,
.adv-person-card--listing .adv-person-card__role { margin-block-end: 0; }
/* One line, at most 290 (the frame's text box): "Adverit Barcelona, Spain". */
.adv-person-card--listing .adv-person-card__meta {
  flex-shrink: 0;
  max-width: 290px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.adv-person-card--listing .adv-person-card__office { color: var(--adv-color-primary); }
/* The satellite's second credential line is the 402 row's only (see the 560 block). */
.adv-person-card__meta--m { display: none; }
.adv-person-card--listing .adv-person-card__tags {
  margin-block-start: 0;
  padding-block-start: 0;
  min-height: 0;
  overflow: hidden;
}

/* ---------------------------------------------------------------------
   Numbered value row + rule
   --------------------------------------------------------------------- */
.adv-values { display: flex; flex-direction: column; gap: 23px; }
.adv-value {
  display: grid;
  /* Read through properties (AD-140 / TD-21): `.adv-values--fluid` below lets
     the master's rows give below 1440. The fallbacks are the values every other
     row keeps. */
  grid-template-columns: var(--adv-value-cols, 38px 1fr 330px);
  gap: 22px;
  row-gap: var(--adv-value-row-gap, 22px);
  align-items: center;
}
/* THE MASTER'S VALUE ROWS GIVE BELOW 1440 (AD-140, TD-21). About's and the
   careers landing's rows sit in the right column of `.adv-band__split--values`,
   which shrinks with the page, but the 330 description track did not — so the
   row ran past the viewport at 861–1275 (EN), to 1329 (NL) and 1366 (DE; its
   value names are the longest). The track now gives first; at 1440 it still
   reaches its 330 before `1fr` takes the rest, so the frame's row (279:2399) is
   unchanged. At ≤1100 the description goes under the name — the ≤1100 block. */
.adv-values--fluid { --adv-value-cols: 38px 1fr minmax(0, 330px); }
/* THE CAREERS STEP NAMES TAKE THEIR FRAME LINE BOX (AD-143, 597:18501): 38/600 on
   AUTO (46), so a two-line name is a 92 row and the pitch the frame's 138 — About's
   rows keep the 38 box their frame draws. The 560 block's name rules are later. */
.adv-values--careers .adv-value__name { line-height: var(--adv-h1-lh); }
/* THE SAME ROW ACROSS A WHOLE CONTAINER, not the right half of a split. The base
   grid above is sized for About and the careers "how it works", where the rows
   live in a 720 column: `1fr` for the name, a 330 description beside it.

   The careers landing's "why join" puts its label ABOVE and runs the rows the
   full 1320 (589:16363). With the base rule `1fr` then swallows the slack — the
   name column measured 908, more than half the container, and the description
   ended up at 1050 with nothing to align to.

   MEASURES, NOT RATIOS, and they are the frame's own: the description starts at
   660 — exactly the container's midpoint — and, since the 2026-09-16 round
   (AD-143), runs the other 660 (it was 550). The name column is 578 (60 → 638):
   the frame's 540 box plus the 38 the uniform gutter cannot take (the arithmetic
   Join's retired steps rows used, AD-142). `minmax(0, …)` on both, so a long name in DE wraps inside its column
   and the pair still shrinks below 1440.

   And the round's rhythm: the name on its AUTO box (46), rows 26 apart, the rule the
   container's full 1319 rather than starting at the name — 102 a row, as drawn. */
.adv-values--wide { gap: var(--adv-space-26); }
.adv-values--wide .adv-value { grid-template-columns: 38px minmax(0, 578px) minmax(0, 660px); }
.adv-values--wide .adv-value__name { line-height: var(--adv-h1-lh); }
.adv-values--wide .adv-rule { margin-inline-start: 0; }
/* LONG VALUES, TOP-ALIGNED (AD-168, ADR-0025 Amendment 23): About's five values (1655:25371) and
   Join's five benefits (385:5038) are `--wide` rows whose text runs to several paragraphs. Three
   differences from the careers rows, all drawn:
     - TOP-ALIGNED — the frame's rows are cross-axis MIN, where the base row centres; a three-
       paragraph text beside a centred one-line name leaves the name floating mid-row;
     - the ring on the NAME'S FIRST LINE — 4 below the name's top, half of its AUTO box (46) less
       the ring's 38, computed from the tokens so a type change moves it;
     - paragraphs 16 apart (`Body/regular_16px`'s paragraph spacing), each its own `.adv-value__text`
       inside ONE grid item, `.adv-value__body` — a second paragraph as a grid item of its own drops
       into the next grid row's 38 ring column (latent since AD-159, which split the paragraphs).
   A modifier and not a change of `--wide`: the careers "why join" rows keep their centring. The
   ≤1100 block puts the text under the name; at ≤560 `--wide`'s own stack takes over. */
.adv-values--top .adv-value { align-items: start; }
.adv-values--top .adv-value__num {
  margin-block-start: calc((var(--adv-h1-lh) * var(--adv-h1-size) - 38px) / 2);
}
.adv-value__body { grid-column: var(--adv-value-text-col, auto); }
.adv-value__body > .adv-value__text + .adv-value__text { margin-block-start: var(--adv-space-16); }

/* ── Vacancy detail, desktop composition (589:17473) ──────────────────────────
   Three columns under a title that belongs to the MIDDLE one: 235 of tags and
   dates, 619 of copy, 330 of the partner firm. The widths are the frame's; the
   gaps are not — it draws 94 and 41, which is the right column's 270 of content
   sitting left inside a 330 slot rather than two considered measures, so the
   136 of slack is split evenly instead.

   DOM order is meta → firm → copy, which is the 402 stack (760:13351). The grid
   places by column, so the desktop reads left → middle → right without `order`
   and without the mobile needing any. Below 560 the whole thing collapses to one
   column and the source order is what shows. */
.adv-job-layout {
  display: grid;
  /* FIVE TRACKS, two of them empty spacers, because the frame's gaps are NOT
     equal: 95 between the meta and the copy, 41 between the copy and the firm
     (597:19555 — columns at x=60.5, 389.5 and 1049.5). Splitting the slack
     evenly put the copy 27px left of where the design has it, and the title
     with it. 235 + 95 + 619 + 41 + 330 is exactly the 1320 container, so the
     tracks carry the measurement instead of a `gap` that cannot be asymmetric. */
  grid-template-columns: 235px 95px minmax(0, 619px) 41px 330px;
  align-items: start;
  /* 56 FROM THE TITLE'S FOOT TO THE COLUMNS, 45 FROM THE TRAIL TO THE TITLE (AD-143,
     589:17473: the trail at 380, the h1 450..520, the columns at 576 — all 34 higher
     since the trail sits 26 under the plate, ADR-0030 Amendment 1 §6). 45 is the
     detail rhythm every master detail head uses (ADR-0025 Amendment 3); 56 is the
     frame's, a documented literal — the scale has no 56. */
  row-gap: 56px;
  max-width: var(--adv-container);
  margin-inline: auto;
  padding-block-start: 45px;
}
/* The title STARTS on the copy column and runs to the container's right edge —
   the frame gives it 703 at x=390 (597:19089), which is 84 wider than the 619
   copy column under it. Pinned to column 3 alone, "Junior Corporate Lawyer"
   wrapped to two lines at 58px and pushed all three columns, the partner-firm
   band and the closing band 70px down the page.
   Spanning to `-1` costs nothing: the title is the grid's ONLY row-1 item, so
   the firm and meta columns it crosses are empty there. */
.adv-job-layout__title { grid-column: 3 / -1; grid-row: 1; }
.adv-job-layout__meta  { grid-column: 1; grid-row: 2; }
.adv-job-layout__body  { grid-column: 3; grid-row: 2; }
.adv-job-layout__firm  { grid-column: 5; grid-row: 2; }
/* The copy blocks keep the 34 rhythm the stack gave them when this was one
   column; the grid only decides where the column sits, never what is in it. */
.adv-job-layout__body,
.adv-job-layout__meta,
.adv-job-layout__firm { display: flex; flex-direction: column; gap: var(--adv-space-34); }
/* The firm photograph is 660 x 286 in its own band (597:19473) — squatter than
   the listing plate it borrows its class from.

   `display: block` is not redundant: `.adv-listing-photo` is `display: none` at
   every width above the mobile step, because everywhere ELSE it exists it IS the
   mobile stand-in for a band. Here it is a desktop element in its own right and
   has to switch itself back on, or the about-the-firm band renders as copy with
   an empty half beside it. */
/* AN ASPECT RATIO, NOT A HEIGHT. 660 x 286 is what the frame draws at 1440
   (597:19473), but the column holding it is `minmax(0, 659px)` and shrinks with
   the viewport — measured 360 wide at a 900 window. Pinned by `min-height` the
   photograph kept its 286 while narrowing, so the crop tightened as the screen
   got smaller. Worse, `min-height` + the mobile `aspect-ratio` resolved the
   width FROM the height, which is how a 362-wide plate ended up overflowing a
   280 column on every phone under 402. The ratio holds the shape at every
   width and lets the track decide the size. */
.adv-job-firm-photo { display: block; aspect-ratio: 660 / 286; }
/* In the 235 column the two dates stack; they were a row when this block sat
   full-width under the title. 26 BETWEEN THE TAGS, "Posted" AND THE DEADLINE, and the
   tags at the column's top (AD-143, 597:19554: 0 / 108 / 172 with the tags 82 tall):
   the column's own gap, with the blocks' mobile-tier margins cleared. */
.adv-job-layout__meta { gap: var(--adv-space-26); }
.adv-job-layout__meta > .adv-job-tags,
.adv-job-layout__meta > .adv-job-meta { margin-block-start: 0; }
.adv-job-layout__meta .adv-job-meta { flex-direction: column; gap: var(--adv-space-26); }
.adv-job-layout__meta .adv-job-tags { flex-wrap: wrap; }
/* EVERY LABEL ON THE VACANCY PAGE SITS IN THE FRAME'S 29 BOX (597:19450: the copy 41
   under the label's top, "Hiring office" 55 above its row) — `--auto`'s value, scoped
   here rather than written on nine labels. */
.adv-job-layout .adv-section-label,
.adv-band__split--job-office .adv-section-label { line-height: var(--adv-small-lh); }
/* The copy is ink here (597:19451, 597:19454), not the secondary grey. */
.adv-job-layout__body .adv-band__text,
.adv-job-layout__body .adv-job-list { color: var(--adv-color-ink); }
/* HIRING OFFICE (597:19547, AD-143): the label, the 270 x 78 office row, the line and
   the outlined button, 26 apart. The row is the compact reference row
   (`.adv-person-mini`) with its name 16/500/25 in BLUE at the row's top + 7 and the
   country 14/400 in ink 5 under it (597:19541) — bound through the row's hooks, as the
   detail rails and the article byline bind theirs. */
.adv-job-office {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--adv-space-26);
}
.adv-job-office__row {
  --adv-person-mini-align: flex-start;
  --adv-person-mini-name-inset: 7px;
  --adv-person-mini-name-lh: var(--adv-body-lh);
  --adv-person-mini-name-color: var(--adv-color-primary);
  --adv-person-mini-role-size: var(--adv-small-size);
  --adv-person-mini-role-lh: var(--adv-small-lh);
  --adv-person-mini-role-color: var(--adv-color-ink);
}
.adv-job-office .adv-band__text { color: var(--adv-color-ink); }
/* THE RING IS NEUTRAL, THE DIGITS ARE BURGUNDY. Both were burgundy while this
   block was unused; the frame that finally used it (279:2399, master About)
   binds `borders/light` on the circle and `corporate/burgundy` on the number.
   A burgundy ring reads as three small badges in a row and pulls the eye off
   the value names, which are the content. */
.adv-value__num {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-pill);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: 1;
  color: var(--adv-color-accent-burgundy);
}
/* Navy, not body ink — `corporate/navy` on 279:2398. Same call every heading on
   the master makes (see `.adv-heading--navy`); it is baked in here rather than
   left to a modifier because a value name has no other colour. */
.adv-value__name {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h1-size);
  line-height: 1;
  color: var(--adv-color-primary-dark);
  /* BALANCED, NOT GREEDY (AK, 2026-08-31 — "Learn about the role" broke a word
     too late). The careers frame draws all three of its step names over two
     lines at 260 / 238 / 248 wide inside a 330 column — three near-equal boxes
     that do not fill the column, which is the signature of balanced wrapping
     rather than of three hand-set widths. Greedy wrapping packs the first line
     to the column edge instead, so "Learn about the / role" fitted where the
     frame draws "Learn about / the role"; the other two already broke at the
     same place either way, which is why only one of the three looked wrong.

     A property of the NAME and not of the careers page: every value name in the
     system is a short display title in a fixed column, and a lonely last word is
     the failure mode of all of them. Degrades to normal wrapping where
     `text-wrap` is unsupported — the pre-2026-08-31 rendering, not a broken
     one. */
  text-wrap: balance;
}
.adv-value__text {
  margin: 0;
  grid-column: var(--adv-value-text-col, auto);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}

/* The rule is 660 of the row's 720 and hangs off the right edge, so it starts
   level with the value's NAME rather than with its number. */
.adv-rule {
  height: 1px;
  border: 0;
  margin: 0 0 0 60px;
  background: var(--adv-color-rule);
}

/* ---------------------------------------------------------------------
   Wide insight row — 330px square image beside title/tags/excerpt/date
   --------------------------------------------------------------------- */
.adv-insight { display: flex; gap: 18px; text-decoration: none; }
.adv-insight__media {
  flex-shrink: 0;
  width: 330px;
  height: 330px;
  object-fit: cover;
  background-size: cover;
  background-position: center;
  border-radius: var(--adv-radius-card);
}
/* NO PHOTOGRAPH IS THE NORMAL CASE ON THE MASTER, so the plate is kept and
   filled with the FIRM'S MONOGRAM rather than dropped or filled with stock.

   Dropped, the row collapses to text and reads as a different component beside
   a sibling that has an image — the design draws a 330 square and the rhythm of
   the two-up grid depends on it. Filled with a stand-in photograph, it would
   illustrate one firm's article with another firm's picture, which is a claim
   rather than a placeholder. The monogram is real data about the source.

   Same treatment, same tokens as `.adv-firm-card__media--empty`; the difference
   is the border, which that one needs because its plate sits above a panel and
   this one stands alone. */
.adv-insight__media--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--adv-color-surface);
  box-shadow: inset 0 0 0 var(--adv-border-width) var(--adv-color-border);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-monogram-size);
  line-height: 1;
  color: var(--adv-color-border);
}
.adv-insight__body {
  display: flex;
  flex-direction: column;
  gap: 18px;
  align-items: flex-start;
  padding-block: 0 var(--adv-space-16);
}
.adv-insight__title {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-h3-size);
  /* 27, NOT 22, AND TWO LINES AT MOST. 430:8832 draws every card title in a
     54px box — two lines of 27 — and the long ones end in an ellipsis, which is
     the design saying the title is clamped rather than allowed to push the card.
     At `line-height: 1` and no clamp ours ran to four lines of 22, taking the
     card from the drawn 330 to 381 and the two-up grid's row pitch from 384 to
     435. The clamp is the reason the frame's own titles read "Obligation to
     withhold payment on invoices…". */
  line-height: 27px;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  color: var(--adv-color-primary-dark);
}
.adv-insight__tags { display: flex; gap: var(--adv-space-12); flex-wrap: wrap; }
/* ONE TAG ROW IN THE CAROUSEL ON EVERY TIER (TD-17, AD-139). The 402 rule
   further down has said this since AK's 2026-09-02 pass; the desktop card did
   not, so two long labels wrapped to 86 and took the slide from the frame's
   330 to 347 (measured on /services/consultancy-advice/). 307:6679 draws one
   row of 37 — the badge's 17 line + 9 + 9 + the two 1px borders. `max-height`
   rather than `nowrap`, for the reason the 402 rule gives: the overflow row
   is dropped whole instead of a pill being sliced. The grid card on the
   insights listing keeps its wrap; only the carousel's box is fixed. */
.adv-reel .adv-insight__tags { max-height: 37px; overflow: hidden; }
/* FIVE LINES, then the card stops. The excerpt had no ceiling at all above 560,
   and the aggregated summaries are not a fixed length — they run from 93 to 1209
   characters — so the longest ones were rendering THIRTY-SIX lines and taking the
   card from its designed 330 to 1154. One long summary was resizing the row.

   Five is the comp's own maximum: the listing frame (431:9291) draws its
   summaries at 75 to 125px on a 25px line, i.e. three to five lines. The card is
   a lede into the article, and the full summary is on the article's own page —
   nothing is lost here, only deferred. Mobile clamps tighter (3) further down,
   where the card is smaller. */
.adv-insight__excerpt {
  margin: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 5;
  overflow: hidden;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
.adv-insight__date {
  margin: auto 0 0;
  font-size: 10px;
  line-height: 1.21;
  color: var(--adv-color-ink);
}
/* THE FOOT ROW (297:3870, AD-138 — master only, the satellite's article card has
   no byline): "By ⟨author⟩ · ⟨office⟩" on the left, the date on the right, both
   `Old/small` 10/400 ink, the office in corporate blue (1343:21146). The row takes
   the body's full width and its bottom, where the date used to sit alone. */
.adv-insight__foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--adv-space-12);
  align-self: stretch;
  margin-block-start: auto;
}
.adv-insight__foot .adv-insight__date { margin: 0; }
.adv-insight__byline {
  font-size: 10px;
  line-height: 1.21;
  color: var(--adv-color-ink);
}
.adv-insight__office { color: var(--adv-color-primary); }
/* DATE ONLY (AD-143, ADR-0025 Amendment 8 C — master only): the insights pages draw
   the foot as the article's date alone, its 12px box at the card's 314 (430:8832,
   422:6516), where the byline row's sits at 302. The body's bottom padding is what
   places it: 330 − 12 − 4. The rails keep the byline row above. */
.adv-insight--date-only .adv-insight__body { padding-block-end: var(--adv-space-4); }

/* Hero — the base the master's homepage hero (`.adv-page-hero--home`) builds on. The
   satellite's full-bleed-photo variant (`__intro`, `__media`, `__search`) retired in
   AD-145: the firm Home opens on `.adv-about-hero--home` (ADR-0030 §2). */
.adv-page-hero { position: relative; }
/* ---------------------------------------------------------------------
   Search entry screen                                    node 896:9585
   A question, one 1320 field and the popular topics — on the PAGE
   SURFACE. The master's search screen used to be a 742px photograph
   with the compound control floating dead centre of it; those rules
   retired with the satellite's photograph hero (AD-145).

   The frame's geometry, all measured from a 60px header: the heading at
   y=157 — 96 under the bar, the page's own section gap — the field at
   356, and the popular row at 428, 12 under the field's foot and 26 in
   from its left edge. The 96 is `--adv-section-gap` and survives the
   master's 99px bar untouched (AD-131): only the absolute y moves, to
   196 on that tier. The invariant here was always the gap.
   --------------------------------------------------------------------- */
/* IT CLOSES AT THE GAP IT OPENS WITH (ADR-0021 §1, AD-126 item 10). The foot
   was 0, and on this screen alone nothing follows the section but the footer —
   the closing CTA band lives inside the RESULTS panel, not here — so the
   "Popular:" row sat on the page's bottom edge. One existing token, mirroring
   the top; the mobile tier follows for free, since --adv-section-gap is already
   remapped to --adv-m-band-gap at 560. */
.adv-search-entry {
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding: var(--adv-section-gap) var(--adv-section-pad-x) var(--adv-section-gap);
}
.adv-search-entry__title {
  max-width: 990px;
  /* 129 is the frame's own: heading box 157→227, field at 356. Not a scale
     step and not built from two — it is one measured distance and says so. */
  margin: 0 0 129px;
}

/* ---------------------------------------------------------------------
   Master homepage hero                     node 1482:29818 (2026-09-16)
   ONE CENTRED, FULL-BLEED COLUMN (ADR-0024 §6): the wordmark, the headline,
   the subtitle, the search pill and "Popular:", over the abstract render on
   the secondary surface. It replaced the 2026-09-08 split row (the wordmark
   beside the headline, AD-131) and the photograph with the search and three
   quick-link tiles floating on it — every rule and token those needed left
   with them.

   IT STARTS AT y=0, UNDER THE BAR. The header is sticky and keeps its 99 in
   flow — plus its 1px hairline, which is in the box even while transparent,
   so 100, as the frame's Header instance measures — and the hero pulls itself
   up by exactly that much; the bar is
   transparent while the hero's wordmark shows (`.adv-nav--home`). A NEGATIVE
   MARGIN, NOT A FIXED BAR: `position: fixed` would take the header out of
   every other page's flow. `--adv-nav-h` is the bar's one height on both
   tiers (ADR-0030 §1), so this section reads it directly. The bar's
   `--adv-z-header` keeps it on top.

   The render layer is `isolation` + a negative z-index, so it paints above
   the band's own fill and below every child without any of them needing a
   z-index of its own.
   --------------------------------------------------------------------- */
.adv-page-hero--home {
  isolation: isolate;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: var(--adv-hero-home-min-h);
  margin-block-start: calc(-1 * (var(--adv-nav-h) + var(--adv-border-width)));
  padding: var(--adv-hero-home-pad-top) var(--adv-section-pad-x) 0;
  background: var(--adv-color-surface-alt);
  text-align: center;
}
/* A CHILD ELEMENT, NOT A `::before`: the render arrives as inline
   `background-image` declarations from `func/image-css.html` (that is how
   `image-set()` is delivered on this site), and an inline style cannot reach
   a pseudo-element. No image configured → no element, and the band is the
   plain secondary surface.

   FULL OPACITY. The frame draws the render at 73% over #F5F4F2, but the file
   the designer exported (`img/hero.jpg`) already IS that composite: against
   Figma's own render of 1482:29818 it measures a mean error of 0.6 as it is,
   and 3.1 with another 73% applied. Dimming it again would wash it out. */
.adv-page-hero__render {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-size: cover;
  background-position: center;
}
/* THE HERO WORDMARK IS THE BAR'S LOGO TILE AT 2.174x, one asset at two sizes,
   and all four of the frame's numbers say so: 539/248, 215.6/99.2,
   399.15/183.65 and 145.39/66.9 are the same ratio to three figures. So it is
   written the way the tile is — a glyph height plus the insets around it —
   rather than as a fixed box. THE BOX IS THE TILE, PADDING INCLUDED. The
   2026-09-16 frame (1482:29830) keeps it to the pixel — 539 x 215 — and only
   moves it: centred above the headline at y=112, where AD-131 had it as the
   left column. The tile's insets at 2.174x: (99.2 - 66.9) / 2 = 16.15 -> 35,
   and 32.175 -> 70. */
.adv-page-hero__wordmark { display: block; padding: 35px 70px; }
.adv-page-hero__wordmark img { display: block; height: 145.4px; width: auto; }
.adv-page-hero--home .adv-page-title {
  max-width: var(--adv-hero-home-title-measure);
  margin-block-start: var(--adv-hero-home-gap-title);
  font-weight: var(--adv-hero-intro-title-weight);
  line-height: var(--adv-hero-intro-title-lh);
  letter-spacing: 0;   /* `Heading/bold_58px` binds 0 (1482:29841) */
}
.adv-page-hero--home .adv-subtitle { margin-block-start: var(--adv-hero-home-gap-subtitle); }
.adv-page-hero--home .adv-hero-search { margin-block-start: var(--adv-hero-home-gap-search); }

/* ---------------------------------------------------------------------
   Master About hero                          node 1482:33810 (AD-138)
   ONE 1024 BAND ON THE SECONDARY SURFACE: a 500 copy column on the left,
   vertically centred (1482:33910 runs 366–659 — centre 512.5 of 1024), and a
   720 x 815 photograph from the bar's foot to the viewport's right edge
   (1482:33811), its LEFT corners at the plate radius. It replaced a page head
   over a 742 full-bleed band (247:8044) — AK's two-line About title rule went
   with that head.

   PULLED UP UNDER THE BAR the way the homepage hero is (`.adv-page-hero--home`
   above — ADR-0024 Amendment 1): the header keeps its 99 + 1 in flow and this
   band starts that much higher, so its surface runs under the bar, which
   About fills with the same colour (`.adv-nav--alt`).

   ITS OWN BLOCK, NOT `.adv-page-hero`: that base is the satellite hero's, and
   its ≤560 rules restack whatever carries the class. Nothing here needs them.

   THE PHOTOGRAPH BLEEDS BY POSITION, NOT BY `100vw`. `inset-inline: 50% 0`
   pins it to the band's own right edge — the viewport's, since the band is
   full-width — so it cannot add the scrollbar's width to the page (TD-10).
   Its top is the bar's foot: the band starts at y=0 and the photograph at 100. */
.adv-about-hero {
  position: relative;
  display: flex;
  align-items: center;
  min-height: var(--adv-about-hero-min-h);
  margin-block-start: calc(-1 * (var(--adv-nav-h) + var(--adv-border-width)));
  /* The copy column starts at the 1320 container's edge at every width. */
  padding-inline: max(var(--adv-section-pad-x), (100% - var(--adv-container)) / 2);
  background: var(--adv-color-surface-alt);
}
.adv-about-hero__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--adv-space-34);
  /* 500 at 1440; never into the photograph's half on a narrower desktop. */
  width: min(var(--adv-about-hero-copy-w), 50% - var(--adv-space-26));
}
/* JOIN TAKES THIS HERO WITH A 600 COLUMN (1485:41428, AD-142) — About's is 500. The
   modifier rebinds the one custom property the column reads; the `min()` still keeps it
   out of the photograph's half, and the ≤860 `width: auto` below still wins. 600 is the
   frame's width, like the 500 it stands beside. */
.adv-about-hero--join { --adv-about-hero-copy-w: 600px; }
/* CAREERS TAKES IT TOO (AD-143, K1 — 553:14183): the h1 on two lines, the lead broken
   after "…team and" and the button, 24 apart (1511:12839 → 12846 → 12847). The frame's
   box is 570, which breaks the lead a word late in Chrome, as Join's 600 does; the
   measure is the one that breaks it where the frame does (measured, AD-143). */
.adv-about-hero--careers {
  --adv-about-hero-copy-w: 550px;
  /* THE COPY BLOCK SITS 10 BELOW THE BAND'S CENTRE in this frame (1511:12839 at 367, the
     button's foot at 677 — centre 522 of 1024; About's is 512.5). 20 of top padding
     moves the centred block down by exactly that. */
  padding-block-start: 20px;
}
.adv-about-hero--careers .adv-about-hero__copy { gap: var(--adv-space-24); }
/* THE SATELLITE HOME TAKES THIS HERO (1484:36470, AD-145 — ADR-0030 §2). The copy is
   NOT centred here: the lead's top is the frame's y=491 and the buttons follow 26 under it
   (589), in a 590 column with an authored break after "businesses". 491 is a page-y
   literal like the listing head's 214 — the band starts at y=0, under the bar. The wordmark
   and the city sit above it, out of flow (`.adv-hero-lockup`). */
.adv-about-hero--home {
  --adv-about-hero-copy-w: 590px;
  align-items: flex-start;
  padding-block-start: 491px;
}
.adv-about-hero--home .adv-about-hero__copy { gap: var(--adv-space-26); }
/* The frame's lead box is 590 with an AUTHORED break after "businesses"; at 590 Chrome
   breaks a word later ("…businesses in"). The tier's 550 measure breaks it where the frame
   does in EN and keeps the NL / FR / DE leads to two lines (measured, AD-145). */
.adv-about-hero--home .adv-page-head__lead { max-width: var(--adv-sat-measure); }
/* THE SATELLITE ABOUT TAKES IT TOO (1511:12628, AD-145): the h1, a 525 lead on three lines
   and the two buttons, 26 apart (367 → 463 → 597), in a block that sits 5 above the band's
   centre (367–647 against 1024). 10 of bottom padding lifts the centred block by exactly
   that — the careers modifier's device, mirrored. */
.adv-about-hero--sat {
  --adv-about-hero-copy-w: 525px;
  padding-block-end: 10px;
}
.adv-about-hero--sat .adv-about-hero__copy { gap: var(--adv-space-26); }
/* THE LOCKUP (1484:36483 + 1484:36477): the master homepage's wordmark box — 539 × 215.4,
   the 145.4 mark inset 35 / 70 (`.adv-page-hero__wordmark`) — at the bar's foot and the
   capped frame's left edge, and the firm's city under it at Inter 42 / 1.153, x=70. THE
   CITY OVERLAPS THE WORDMARK'S BOX: its line box starts 28.7 above the mark's foot
   (1484:36477 centred at y=276 against the mark's 280.5), so it is pulled up by the box's
   bottom inset plus that — two documented literals of the frame. The whole lockup is the
   page's h1; the heading's own type is reset because only its children draw. */
.adv-hero-lockup {
  position: absolute;
  inset-block-start: calc(var(--adv-nav-h) + var(--adv-border-width));
  inset-inline-start: max(0px, (100% - var(--adv-container-outer)) / 2);
  margin: 0;
  font: inherit;
}
.adv-hero-lockup__city {
  display: block;
  /* THE NAME'S BOX IS AT MOST 300 (MD — ADR-0030 Amendment 1 §5): content-box, so
     the 70 inset stays outside it. The photograph starts at 50%, and an unbounded
     name ran under it. */
  box-sizing: content-box;
  max-width: var(--adv-hero-city-max-w);
  margin-block-start: calc(-35px - 28.7px);   /* 1484:36477: the box's 35 inset + the 28.7 overlap */
  padding-inline-start: 70px;                 /* the mark's own x (1484:36483) */
  font-size: var(--adv-hero-city-size);
  line-height: var(--adv-hero-city-lh);
  font-weight: var(--adv-weight-regular);
  color: var(--adv-color-ink);
  white-space: nowrap;
}
/* A compound name (whitespace, a hyphen, a slash — hero.html) wraps inside the
   box; hyphenation stays off. A single word that does not fit drops to the tight
   size, and past that site.js scales it down to a floor of 20 (`--tight` is set
   by the script). Two lines end at ~349, well above the lead at 491. */
.adv-hero-lockup__city--compound { white-space: normal; }
.adv-hero-lockup__city--tight { font-size: var(--adv-hero-city-size-tight); }
/* `Heading/bold_58px` (1482:33911): 58/700, letter-spacing 0, one line. The
   700 is the page-title token's own since 2.9.0 (ADR-0030 §4). The line box
   stays the page title's AUTO (70): with it the lead lands on the frame's 467
   and the buttons on 609. */
.adv-about-hero .adv-page-title {
  font-size: var(--adv-display-size);
  letter-spacing: 0;
}
.adv-about-hero__photo {
  position: absolute;
  inset-block-start: calc(var(--adv-nav-h) + var(--adv-border-width));
  inset-inline: 50% 0;
  height: var(--adv-about-hero-photo-h);
  border-start-start-radius: var(--adv-radius-band);
  border-end-start-radius: var(--adv-radius-band);
  background-size: cover;
  background-position: center;
}

/* THE HEADLINE'S ACCENT (1482:29841: "the right" in corporate/burgundy inside a
   navy display heading, ADR-0024 §5). The phrase is marked in the COPY — the
   i18n string carries `*the right*` and the template runs it through
   `markdownify` — so a translator moves the accent with the words and no
   template knows which words they are. `font-style: normal` is load-bearing:
   Inter ships a real italic and the browser would use it for the `<em>`. */
.adv-accent,
.adv-page-title--accented em {
  font-style: normal;
  color: var(--adv-color-accent-burgundy);
}


/* The compound hero control — node 250:9515. A filter beside the field, and a
   row of popular links beneath. 880 wide on a 1440 frame: the filter, a 22px
   gap, then a 663 field whose button overlaps its tail. */
.adv-hero-search { width: 100%; max-width: 880px; }
/* TWO SELECTS WIDEN THE CONTROL — 623:21940. The measure is the row's own
   arithmetic, not a new taste: 184 + 22 + 219 + 22 + 663 = 1110, against
   184 + 22 + 663 = 869 (drawn 880) for the single-select form the firm sites
   still use. It matters because the field is the part that gives: held at 880
   the second select eats ~230 of the 663 input and the "Popular:" line wraps.
   Centred in the hero float, 1110 lands the block at x=165 of 1440 — the
   frame's own offset, arrived at rather than typed in.
   `:has` keyed on the second wrap rather than a modifier class, so the width
   cannot disagree with what is actually rendered: a firm site, or a master
   screen whose services list is empty, drops back to 880 by itself. */
.adv-hero-search:has(.adv-filter-wrap + .adv-filter-wrap) { max-width: 1110px; }
.adv-hero-search__row { display: flex; gap: 22px; align-items: flex-start; }
/* The field and its popular links are one column, so the links line up under
   the input rather than under the filter that sits beside it. */
.adv-hero-search__field { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.adv-hero-search__field .adv-search { width: 100%; max-width: none; }
/* The filter needs its own positioning context so its panel drops beneath it
   rather than beneath the whole hero. */
.adv-filter-wrap { position: relative; flex-shrink: 0; }
.adv-filter-wrap .adv-filter-panel {
  position: absolute;
  inset-block-start: calc(100% + var(--adv-space-8));
  inset-inline-start: 0;
  z-index: var(--adv-z-dropdown);
  min-width: 260px;
  max-height: 320px;
  overflow-y: auto;
}
/* THE COMPOSITE SCROLLS ITS VALUE COLUMN, NOT ITSELF (AK, 2026-09-01). The rule
   above was written for a panel that is one column, where "the panel scrolls"
   and "the list scrolls" are the same sentence. On `--columns` (529:12362) they
   are not: measured with a full practice-area vocabulary in the right-hand
   column, the panel scrolled 1669px inside its 320 cap and took the AXIS column
   with it — 200px of scroll moved the axis list 200px off the top, so the
   control that says which list you are looking at leaves the screen while you
   look at it. In a master-detail panel the master has to stay put.

   `min-height: 0` is what makes it work: the columns are flex items, whose
   automatic minimum size is their content, so without it the column refuses to
   shrink below its rows and the overflow lands back on the panel. The panel's
   own `overflow: hidden` is then what stops it scrolling at all.

   Placed HERE rather than beside `--columns` further up, and at the same two
   classes as the rule it corrects: it has to win on source order, and lifting
   its specificity would put it above the 402 block that undoes it. */
.adv-filter-wrap .adv-filter-panel--columns { overflow: hidden; }
.adv-filter-panel--columns > .adv-filter-panel__col { min-height: 0; overflow-y: auto; }
/* THE COMPOSITE'S VALUES PANE (AD-139, 529:10832): the one search field over
   whichever value column is showing, 252 wide and 12 above it. The column
   scrolls under a field that stays put — the same reasoning as the rule above,
   one level down. */
.adv-filter-panel__pane {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-12);
  min-width: 252px;
  min-height: 0;
}
.adv-filter-panel__pane > .adv-filter-panel__col { min-height: 0; overflow-y: auto; }
/* THE 306 FLOOR HAS TO BE RESTATED HERE, and this is a specificity bug, not a
   preference. `.adv-filter-panel--search` sets `min-width: 306px` — the frame's
   own panel width (522:9638) — but the dropped rule above is (0,2,0) against
   its (0,1,0), so every searchable panel in a `.adv-filter-wrap` came out 260
   and its field 206 against the drawn 252. Same selector shape, so the variant
   wins on order the way it was always meant to. */
.adv-filter-wrap .adv-filter-panel--search { min-width: 306px; }
/* A STEPPED COMPOSITE OPENS ON ITS AXES ALONE (AD-139, 529:10775): 182 × 96, the
   plain panel's 16/26 inset, no floor — the searchable variant's 306 and 26 are
   for the pane, which is not open yet. Three classes, to beat the floor above. */
.adv-filter-wrap .adv-filter-panel--stepped:not([data-axis-open]) {
  min-width: 182px;
  padding: var(--adv-space-16) var(--adv-space-26);
}
.adv-filter-panel__row { text-decoration: none; }

/* The base row is WHITE, for copy on a photograph. Since AD-137 nothing renders
   it that way: the master's pill and the search entry screen both restate it
   on the page surface below, and the satellite's hero hides the row. */
.adv-hero-search__popular {
  margin: 14px 0 0;
  padding-inline-start: 27px;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-white);
}
.adv-hero-search__popular a { color: inherit; text-decoration: underline; }
.adv-hero-search__popular a:hover { text-decoration-thickness: 2px; }
/* ON THE PAGE SURFACE — the search entry screen (896:9585) keeps this row but
   not the photograph under it, so the white would be white on #FAF9F7. The
   frame binds `text/secondary`, indents 26 rather than the hero's 27, and sets
   it 12 under the field rather than 14.

   WRITTEN HERE, DIRECTLY AFTER THE BASE RULE, and that placement is the whole
   point: the modifier carries the SAME weight as the class it overrides, so
   from anywhere earlier in the file it silently loses. It was authored 70 lines
   up with the rest of the entry screen and rendered white, indent 0, margin 14
   — every one of its three declarations beaten. */
.adv-hero-search__popular--on-page {
  margin-block-start: 12px;
  padding-inline-start: var(--adv-space-26);
  color: var(--adv-color-body);
}

/* THE HERO SEARCH PILL — node 1482:29844 (2026-09-16, ADR-0024 §4 and §6).
   ONE LIGHT PILL where there were three separate controls: Office, a hairline,
   Legal support, a hairline, the field, and a navy submit disc 5px inside the
   right end — 899 x 70 on the page surface, with the search halo. It replaced
   `--on-media`, the dark wash the selects and the field wore over the
   master's photograph (623:21940); with no photograph there is nothing to wash.

   A MODIFIER ON THE SAME CONTROL. The selects, their panels, the hidden fields
   and the script that owns them are untouched — only the dress moves. The pill
   is the ROW (`.adv-hero-search__row`); the wrapper stays a plain column so
   "Popular:" hangs under the pill, outside it.

   THE CELLS: the pill's own 26, then 100 · 26 · | · 26 · 140 · 26 · | · 26 ·
   field. A hairline is the NEXT cell's `border-inline-start`, not an element,
   and it eats the last pixel of the gap before it, so the field's text starts
   where the frame puts it (x=641 of 1440) and not two pixels right. The same
   sum, `--adv-hero-pill-text-inset`, indents "Popular:" — the two cannot
   drift apart. A select label longer than its cell (a chosen value in some
   locales) grows the cell rather than clipping; the indent then no longer
   lines up, which is the right loss.

   Frame slips NOT implemented: the Office caret is drawn 10.75 and the Legal
   support caret 8 — both use the header's `.adv-icon--caret`. */
.adv-hero-search--pill {
  --adv-hero-pill-cell-gap: var(--adv-space-26);
  /* The pill's own lead before the first label — 26 on the master's two-select
     pill, 34 on the satellite's one-select sheet (`--single` below). */
  --adv-hero-pill-lead: var(--adv-space-26);
  --adv-hero-pill-text-inset: calc(var(--adv-border-width) + var(--adv-hero-pill-lead)
    + var(--adv-hero-pill-office-w) + 2 * var(--adv-hero-pill-cell-gap)
    + var(--adv-hero-pill-support-w) + 2 * var(--adv-hero-pill-cell-gap));
}
/* Two selectors because the base widens the control with a (0,3,0) `:has()`:
   the second one matches it weight for weight and wins on order. */
.adv-hero-search.adv-hero-search--pill,
.adv-hero-search--pill:has(.adv-filter-wrap + .adv-filter-wrap) { max-width: var(--adv-hero-pill-w); }
.adv-hero-search--pill .adv-hero-search__row {
  align-items: center;
  gap: 0;
  height: var(--adv-hero-pill-h);
  padding-inline-start: var(--adv-hero-pill-lead);
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-pill);
  background: var(--adv-color-surface);
  box-shadow: var(--adv-shadow-search);
  transition: border-color var(--adv-transition-fast) var(--adv-ease);
}
/* The frame draws no active state for this control. The search component's
   own (`search state=active`, 516:8513) is a burgundy edge on the outline —
   and here the pill IS the outline. */
.adv-hero-search--pill .adv-hero-search__row:focus-within { border-color: var(--adv-hover-accent); }
.adv-hero-search--pill .adv-filter-wrap + .adv-filter-wrap,
.adv-hero-search--pill .adv-hero-search__field {
  margin-inline-start: calc(var(--adv-hero-pill-cell-gap) - var(--adv-border-width));
  padding-inline-start: var(--adv-hero-pill-cell-gap);
  border-inline-start: var(--adv-border-width) solid var(--adv-color-border);
}
/* A select is a 60-tall label + caret in its cell — no plate, no edge. 60 is
   the base control's own height, and the hairline beside it is that tall. */
.adv-hero-search--pill .adv-filter {
  min-width: var(--adv-hero-pill-office-w);
  padding-inline: 0;
  gap: var(--adv-space-12);
  border: 0;
  border-radius: 0;
  background: transparent;
  white-space: nowrap;
}
.adv-hero-search--pill .adv-filter-wrap + .adv-filter-wrap .adv-filter { min-width: var(--adv-hero-pill-support-w); }
/* States keep the base's colours and drop its plate: hover is the burgundy
   label, open or chosen the active navy. */
.adv-hero-search--pill .adv-filter:hover { background: transparent; color: var(--adv-hover-accent); }
.adv-hero-search--pill .adv-filter[aria-expanded="true"],
.adv-hero-search--pill .adv-filter--active { background: transparent; color: var(--adv-active-text); }
/* The panel drops 12 below its cell — clear of the pill's own lower edge —
   and reads left to right inside a centred hero.

   IT OPENS FROM ITS SEGMENT AND IS AS WIDE AS THE SEGMENT OR ITS LONGEST ROW
   (1529:15064, MD — ADR-0030 Amendment 1 §4). The Office panel starts at the
   pill's OUTER edge and is at least the Office cell with its lead and its
   trailing gap (26 + 100 + 26 = 152 at the tokens — the drawn min-width); the
   Legal support panel starts AT ITS DIVIDER and is at least its cell and trailing
   gap (26 + 140 + 26 = 192, inferred — the frame does not draw it open).
   `100%` is the wrap's own box, so a picked label that grew the cell grows the
   minimum with it. `max-content` lets a long city widen the PANEL; the pill
   moves only when that city is picked. Rows wrap only past the viewport's
   gutters.

   THE POPOVER'S DRESS, NOT THE FACET PANEL'S: 26 / 40, rows 26 apart, 500, and
   the menu shadow (`.adv-dropdown__menu--popover`). Scoped to the pill, so the
   listing and search-rail facet panels keep their 16 / 26, 12 and 260 / 306. */
.adv-hero-search--pill .adv-filter-wrap .adv-filter-panel {
  /* 12 under the PILL (1529:15064 at y=725 = 643 + 70 + 12), not under the
     60-tall cell, which sits centred in the 70. */
  inset-block-start: calc(50% + var(--adv-hero-pill-h) / 2 + var(--adv-space-12));
  width: max-content;
  max-width: calc(100vw - 2 * var(--adv-section-pad-x));
  gap: var(--adv-space-26);
  padding: var(--adv-space-26) var(--adv-space-40);
  box-shadow: var(--adv-shadow-menu);
  text-align: start;
}
.adv-hero-search--pill .adv-filter-wrap:first-child .adv-filter-panel {
  inset-inline-start: calc(-1 * (var(--adv-border-width) + var(--adv-hero-pill-lead)));
  min-width: calc(100% + var(--adv-hero-pill-lead) + var(--adv-hero-pill-cell-gap));
}
.adv-hero-search--pill .adv-filter-wrap + .adv-filter-wrap .adv-filter-panel {
  inset-inline-start: calc(-1 * var(--adv-border-width));
  min-width: calc(100% + var(--adv-hero-pill-cell-gap));
}
.adv-hero-search--pill .adv-filter-panel__row {
  font-weight: var(--adv-weight-medium);   /* Navigation/medium_16px, 1529:15065 */
  white-space: normal;
}
.adv-hero-search--pill .adv-hero-search__field {
  flex-direction: row;
  align-items: center;
}
.adv-hero-search--pill .adv-search__field {
  padding-inline: 0 var(--adv-space-12);
  margin-inline-end: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  text-align: start;
}
.adv-hero-search--pill .adv-search__field:focus,
.adv-hero-search--pill .adv-search__field:not(:placeholder-shown) { background: transparent; }
/* THE NAVY DISC (1482:29857): 60 across, 5 in from the pill's outer edge (the
   pill's 1px border is already inside that 5), with the 24px glyph. Its hover
   is the accent button's — burgundy — and the base's paired "active" edge is
   answered at matching weight, or typing would paint the glyph burgundy on
   navy. */
.adv-hero-search--pill .adv-search__button {
  margin-inline-end: calc(var(--adv-hero-pill-submit-inset) - var(--adv-border-width));
  border-color: transparent;
  background: var(--adv-color-primary-dark);
  color: var(--adv-color-on-navy);
  transition: background var(--adv-transition-fast) var(--adv-ease);
}
.adv-hero-search--pill .adv-search__button:hover,
.adv-hero-search--pill .adv-search__button:focus-visible,
.adv-hero-search--pill .adv-search__field:focus ~ .adv-search__button,
.adv-hero-search--pill .adv-search__field:not(:placeholder-shown) ~ .adv-search__button {
  border-color: transparent;
  color: var(--adv-color-on-navy);
}
.adv-hero-search--pill .adv-search__button:hover,
.adv-hero-search--pill .adv-search__button:focus-visible { background: var(--adv-hover-accent); }
/* "Popular:" (1482:29856): 12 under the pill, Text Secondary, starting where
   the field's text does — x=640 of 1440 — not centred. */
.adv-hero-search--pill .adv-hero-search__popular {
  margin-block-start: var(--adv-hero-home-gap-popular);
  padding-inline-start: var(--adv-hero-pill-text-inset);
  color: var(--adv-color-body);
  text-align: start;
}

/* THE ONE-SELECT PILL — the satellite's search sheet (1529:13093, ADR-0030
   Amendment 1 §3). The same control with a single select: a 34 lead (the
   frame's padding-start), the "Practice area" cell sized by its own label and
   caret (the two-select pill's 100 minimum is Office's), then the hairline and
   the field as on the master. No "Popular:" line, so no text inset. */
.adv-hero-search--single { --adv-hero-pill-lead: var(--adv-space-34); }
.adv-hero-search--single .adv-filter { min-width: 0; }

/* THE SATELLITE SEARCH SHEET — 1529:12859 (ADR-0030 Amendment 1 §3).
   The magnifier opens a full-bleed #F5F4F2 sheet under the bar: 1440 × 227 at
   y=100, the pill 57 under its top and 99 above its 1px bottom edge (the
   frame's 157 and 326 — documented literals), and it lies OVER the page, the
   hero lockup included. Anchored to `.site-header`, which is sticky and so
   positioned; the bar stays unpositioned (see `.adv-nav__bar`).

   IT SLIDES DOWN FROM UNDER THE BAR (MD): translated up by its own height, it
   sits behind the nav — whose z-index is the header's — and above the page's
   top, so the closed sheet draws nothing. 240ms on `--adv-ease`, the sheet's
   own (the Home logo beside it slides on `--adv-transition-logo-slide`, 480 —
   ADR-0030 Amendment 2); `visibility` leaves after the travel, so a closed sheet
   takes no focus and no clicks. Reduced motion keeps the two states and drops
   the travel. No scrim: the frame draws none.

   `hidden` in the markup until site.js takes the magnifier over, so a page
   without JavaScript never shows it. */
.adv-search-sheet {
  position: absolute;
  inset-inline: 0;
  inset-block-start: 100%;
  padding: 57px var(--adv-section-pad-x) 99px;
  border-bottom: var(--adv-border-width) solid var(--adv-color-border);
  background: var(--adv-color-surface-alt);
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform 240ms var(--adv-ease), visibility 0s linear 240ms;
}
.adv-search-sheet[data-state="open"] {
  transform: none;
  visibility: visible;
  transition: transform 240ms var(--adv-ease), visibility 0s;
}
.adv-search-sheet .adv-hero-search { margin-inline: auto; }
@media (prefers-reduced-motion: reduce) {
  .adv-search-sheet,
  .adv-search-sheet[data-state="open"] { transition: none; }
}
/* The tile turns into the ✕ while the sheet is open (the `search` component's
   searchOpen variant). Both glyphs ship; the ✕ is hidden until then. */
.adv-chip .adv-icon--sheet-close,
.adv-chip[aria-expanded="true"] .adv-icon--sheet-open { display: none; }
.adv-chip[aria-expanded="true"] .adv-icon--sheet-close { display: inline-block; }
/* BAR AND SHEET READ AS ONE SURFACE while it is open, on every page (the frame
   is Home, whose bar is already #F5F4F2): the bar takes the sheet's fill and
   drops its scroll hairline. `data-search-sheet` is the sheet script's own
   attribute — the observer owns `data-wordmark`, and `[data-search]` is the
   search engine's root. */
.adv-nav[data-search-sheet="open"] {
  background: var(--adv-color-surface-alt);
  border-bottom-color: transparent;
}

/* ---------------------------------------------------------------------
   Carousel
   The track is a flex row of full-width slides; JS translates it. With no
   JS the viewport scrolls instead, so every slide stays reachable — a
   carousel that needs a script to reveal its content is a carousel that
   silently loses articles.

   `adv-reel`, NOT `adv-carousel` (AD-153, 2026-09-22). Ad blockers' generic
   cosmetic filters hide `.adv-carousel` outright — "adv" reads as advertising —
   so every insights carousel on both tiers drew its heading over an empty band
   in Dia (and would in any browser running such a list). Measured: of the 633
   `adv-*` classes this sheet styles, exactly two were hidden there,
   `.adv-carousel` and `.adv-banner` (now `.adv-callout`). Before naming a new
   block, probe the name in a browser with a blocker on.
   --------------------------------------------------------------------- */
.adv-reel { position: relative; }
.adv-reel__viewport { overflow-x: auto; scrollbar-width: none; }
.adv-reel__viewport::-webkit-scrollbar { display: none; }
/* Once JS takes over, the viewport stops being a scroller and the track is
   moved by transform — otherwise the two compete and the slide drifts. */
.adv-reel[data-ready="true"] .adv-reel__viewport { overflow: hidden; touch-action: pan-y pinch-zoom; }
/* `pan-y pinch-zoom` (AD-153): the script drags the track sideways with a mouse or a
   finger, so a horizontal touch belongs to it while a vertical one still scrolls the
   page — and a pinch still zooms it: `pan-y` alone would take zoom away from anyone
   whose fingers land on a carousel. The 402 rail below is a native scroller again and
   restores `auto`. */
.adv-reel__track {
  display: flex;
  transition: transform 420ms var(--adv-ease);
}
.adv-reel__slide {
  flex: 0 0 100%;
  display: flex;
  gap: 20px;
  align-items: stretch;
}
/* A FIXED CARD BASIS, NOT `flex: 1` (TD-17, closed by AD-139). Growing to
   fill the slide drew a slide holding ONE card at 1320 — every detail page
   whose person or area has a single related article, and the last slide of an
   odd count — where 307:6670 and 294:3588 draw the pair's half. Half the track
   less the 20 gap, so one card sits exactly where the pair's first one does
   (650 at 1440; the frame's hug-width groups start at 0 and 659). Every caller
   passes the partial's default two per slide. Shared by both tiers: the
   satellite's lawyer page draws the same pair (343:11894). The 402 rail's
   270 basis below is later and wins there. */
.adv-reel__slide > * { flex: 0 0 calc((100% - 20px) / 2); min-width: 0; }
@media (prefers-reduced-motion: reduce) {
  .adv-reel__track { transition: none; }
}

/* Carousel dots. 34 UNDER THE CARDS, not 60: 430:8832 ends its featured row at
   y=1565 and puts the dots at 1599, the same 34 the listing uses between its
   count and its grid. The 60 was the page rhythm reached for by default. */
.adv-dots { display: flex; gap: 23px; justify-content: center; margin-top: var(--adv-space-34); }
.adv-dots__dot {
  /* Rendered as a <span>, and width/height do nothing on an inline box — the
     same trap as the person card's panel. Flex items are blockified, but these
     sit in a flex row so it is the parent that saves them; stated anyway so the
     rule survives being reused somewhere else. */
  display: block;
  width: 12px;
  height: 12px;
  border: 0;
  padding: 0;
  border-radius: var(--adv-radius-pill);
  background: var(--adv-color-accent-light-blue);
  cursor: pointer;
  transition: background var(--adv-transition-fast) var(--adv-ease);
}
.adv-dots__dot[aria-current="true"] { background: var(--adv-color-primary); }
.adv-dots__dot:focus-visible {
  outline: var(--adv-focus-ring-width) solid var(--adv-focus-ring);
  outline-offset: var(--adv-focus-ring-offset);
}

/* Closing CTA — copy left, image right. */
.adv-cta-split {
  display: flex;
  gap: var(--adv-space-60);
  align-items: center;
}
.adv-cta-split__media {
  flex: 0 0 627px;
  align-self: stretch;
  min-height: 656px;
  border-radius: var(--adv-radius-card);
  background-size: cover;
  background-position: center;
}
.adv-cta-split__body { flex: 1; }
.adv-cta-split .adv-display { color: var(--adv-color-primary-dark); }
/* 498 AND 48 (1484:36573 / 36572, AD-145): the heading's two lines in the frame's own box
   (it was `14ch`, 528, inline) and the button 48 under them, where the stack's 26 stood.
   The pair is centred in the 656 photograph's height, which lands the heading on +209. */
.adv-cta-split .adv-display { max-width: 498px; }
.adv-stack--cta-split { gap: var(--adv-space-48); }
/* THE HOME ABOUT BAND'S COPY (1484:36499, AD-145): 544 of ink under the 659 heading
   column — it was 60ch of `--adv-color-body`, inline. */
.adv-band__copy { max-width: 544px; color: var(--adv-color-ink); }

/* Coming-soon stub (theme/adverit/layouts/_default/coming-soon.html) — a
   placeholder page for routes the navigation needs before Stage 3 builds them. */
.adv-coming-soon { max-width: 52ch; }
.adv-coming-soon__text { color: var(--adv-color-body); }
.adv-coming-soon__actions { display: flex; gap: 14px; flex-wrap: wrap; }

/* =====================================================================
   LISTING & DETAIL SCREENS                                    [design]
   ---------------------------------------------------------------------
   Read with get_design_context off the satellite listing and detail
   frames (343:11443 practice areas, 343:11850 / 343:11878 experts,
   385:3685 / 385:3938 insights). Every listing screen is the same five
   pieces in the same order, which is why they are components here and
   not five nearly-identical page templates:

     page head  →  photo band  →  breadcrumbs  →  controls  →  results

   THE PAGE HEAD SITS ABOVE THE PHOTO BAND, not on it. The h1 is at y=213
   and the band runs 388–838, so the title is on the page surface and the
   band is a separate full-bleed strip beneath it. Reading the two as one
   hero (which is what the homepage does) puts white text on a photo that
   was never designed to carry it.
   ===================================================================== */

/* Page head — h1 left, lead right, split on the container's midpoint.
   The design puts the h1 at x=61 and the lead at x=720 of a 1440 frame.
   Base padding is About's (title at y=105 under a 60px bar); a listing sets
   its own, see `--listing`. */
.adv-page-head {
  display: grid;
  /* 600 + 60 + 660, NOT 1fr 1fr. Every master frame puts the lede column at the
     container's MIDPOINT — x=720 of 1440 (430:8832's "Explore the latest legal
     updates…" at 720, 336:7720's title column, 597:19550's closing band) — and
     an even split on a 60 gap lands it at 750 instead. The same arithmetic as
     `.adv-band__split--cta` and the practice-areas band, arrived at from a
     third frame. */
  grid-template-columns: minmax(0, 600px) minmax(0, 660px);
  gap: var(--adv-space-60);
  /* TOP, NOT CENTRE. 336:10372 runs the h1 at 165..235 and the right column at
     164..312 — the lede (164..236) AND the two CTAs (262..312) — so the h1 sits
     at the column's TOP, not at its middle.

     Centring was invisible for a year because it only differs when the two
     columns differ in height, and on a listing they do not: h1 70 against a
     two-line lede 72. About is the one page whose right column carries more than
     the lede, and there the h1 dropped (148 - 70) / 2 = 39px. */
  align-items: start;
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  /* 105 to the h1's box top, which is what the comment above this rule has said
     all along — "About's (title at y=105 under a 60px bar)" — while the value
     was 47. 336:10814 puts the h1 at y=165 under a 60px bar. The block sat 58px
     high, taking the lede with it, because the two columns are centred on each
     other. `--listing` (153, from 343:11445's y=213) and `--master` override
     this, so the correction lands on About and Contact only. */
  padding: 105px var(--adv-section-pad-x) 76px;
}
/* NAVY MOVED ONTO `.adv-page-title` ITSELF (AK, 2026-09-02) — the rule that
   used to sit here was `.adv-page-head .adv-page-title`, and it is gone.

   The colour was right and its owner was wrong. A page title is navy because it
   is a page title, not because of what happens to wrap it, and making the
   ancestor the carrier meant every title OUTSIDE a page head silently fell back
   to `--adv-color-ink` — the 60/60/60 body grey. Three screens were doing
   exactly that, and 553:12714 (satellite Contact, "Get in touch") is the one AK
   caught: it binds `corporate/navy` like every other page title in the file and
   rendered grey, because `.adv-split-media__head` is not a page head.

   The workarounds this produced are the real evidence. The master's hero and its
   two search titles reach for `.adv-heading--navy` BY HAND to undo the default
   (see sections/hero.html, whose own comment spells out the mismatch), and
   `detail-head.html` wraps its bandless section line in a `.adv-page-head` div
   it does not otherwise need, purely to be coloured — its comment says "falls
   back to the page surface in navy", which is true only because of the wrapper.
   Four places compensating for a default is the default being wrong.

   `--on-media` still wins where the title sits on a photograph: it is a base
   class alongside this one and declared later. Nothing in either theme puts an
   `--on-media` title inside a page head, so the two never meet. */
/* A LISTING'S HEAD, BOTH TIERS (AD-145 — ADR-0030 §5): the h1 at the frame's 214 under
   the one 99 + 1 bar, and the plate 102 under the head, so it lands on 388. The
   satellite's was 153 / 104 on its 60 bar (343:11443 then); the redrawn frames put
   both tiers on the master's geometry, including its 102 (see the note below). */
.adv-page-head--listing {
  padding-block: calc(214px - var(--adv-nav-h) - var(--adv-border-width)) 102px;
}
/* `--master` IS THE TIER, and on its own it is also the master's simple page
   head — About's (247:8044): h1 at y=156 under the 60px bar, so 96 of page, and
   the 742px photograph at y=388, 76 under the button row. The firm sites' 47/60
   is a different frame (336:10372) and stays as it is.

   Combined with `--listing` it takes the listing geometry instead (285:2685 /
   522:8766, both CURRENT since the 2026-09-16 round): title at y=214 and the
   1320 x 450 plate at y=388. Two classes beat one, so this wins over both
   `--master` above and `--listing` further up whatever their order in the file.

   THE TOP IS "FRAME y − BAR", AND IT WAS A 40px DRIFT (AD-138, ADR-0025 §8).
   The value was 153 — 214 − 61, measured when the master bar was 60 + 1. AD-131
   grew the bar to 99 + 1 and nobody re-derived this, so every master listing
   title sat at 253. The frames keep their positions page-absolute (the h1 is
   still at 214 under the 100 bar), so the rule is written the same way and the
   next bar change cannot strand it.

   THE BOTTOM IS 102, NOT THE FRAME'S 104. The head's content is the taller of
   the h1 (70) and the two-line lead (72), and our lead starts level with the
   h1 where the frame's starts at 212 — so 214 + 72 + 102 lands the plate on
   388. The master DETAIL screens use neither class; see
   `.adv-page-band--detail`. */
.adv-page-head--master { padding-block: var(--adv-section-gap) 76px; }
/* …so the compound restates the listing's value to beat `--master` above. */
.adv-page-head--master.adv-page-head--listing {
  padding-block: calc(214px - var(--adv-nav-h) - var(--adv-border-width)) 102px;
}
/* AND ITS TITLE IS THE 58 STEP, NOT 72. The two tiers genuinely differ here and
   the token is not wrong: Figma binds `Heading/black_58px` on the master's page
   title (279:2343) and `--adv-page-title-size` (72) is what the firm sites'
   own frames measure — AD-75 checked that against their handoff templates and
   overruled an earlier 58.

   Bound to the tier modifier rather than added per template. The master's
   homepage hero reaches for `.adv-page-title--sm` by hand because it sits
   outside any page head; every master screen that HAS a head gets 58 from here,
   so the next one cannot forget it. */
.adv-page-head--master .adv-page-title { font-size: var(--adv-display-size); }
/* THE LISTING TITLE BINDS `Heading/bold_58px` — 700 (285:2685, 522:8766). ADR-0025 §2
   rebound it here because the shared token had to stay 900 for the satellite; the
   satellite's redrawn heads bind 700 too, so the TOKEN moved (ADR-0030 §4, AD-145)
   and the rebind is gone. */
/* Detail-page chrome runs one step smaller than a listing's h1: the section
   line above a lawyer or an article measures 70px tall in the Figma detail
   frames (= 58 at line-height 1.21), against 72 on the listings. Both are
   Inter Black in navy; only the size steps down. */
.adv-page-title--sm { font-size: var(--adv-display-size); }
/* "JOIN THE COOPERATION" IS A TWO-LINE TITLE (AK, 2026-08-31). 385:4803 is a
   FIXED-width text node — 365 wide, 140 tall — so the design wraps it on
   purpose; ours ran the full 600 of the head's first column and came out one
   line, 58 tall. Not a property of the page head: the listings' h1 in the same
   component is an AUTO-width node ("Legal insights" measures 408 on 430:8833
   and does not wrap), so the measure belongs to this title, not to the tier.
   The selector is already unique — join is the only `--sm` title inside a
   `--master` head — so it needs no new class.

   THE LINE BOX IS THE TOKEN'S NOW (AK, 2026-09-01). 140 over two lines is 70
   each, which is 58 at AUTO — and `--adv-page-title-lh` finally carries AUTO,
   so this rule keeps only the measure. The scoped 1.21 that used to sit here
   was one of three; all three are gone with the token. */
.adv-page-head--master .adv-page-title--sm {
  max-width: 365px;
}
.adv-page-head__lead {
  margin: 0;
  font-size: var(--adv-lead-size);
  line-height: var(--adv-lead-lh);
  color: var(--adv-color-ink);
}
/* 550 OF LEAD IN THE 660 COLUMN — a measure, not the column, and it belongs to
   the LISTING head only.

   Four listing frames, three of them agreeing exactly: 343:11446 (practice
   areas), 343:12287 (services) and 385:3687 (insights) all put the lead at
   x=720 w=550. 343:11850 (experts) is 557 — one box, 7px off three that agree,
   which reads as a dragged handle rather than a second decision, so the three
   win. Every one of the four is 72 tall, i.e. two lines at 24/1.5.

   NOT ON THE BASE. About's lead is 660 (336:10815, the full column) and its head
   is a different composition — capping the base would pull it in with them.
   Uncapped, the listing lead ran the whole 660 and broke a line later than the
   frame does; measured at 660 on all five satellite heads before this. */
.adv-page-head--listing .adv-page-head__lead { max-width: var(--adv-sat-measure); }
/* …EXCEPT ON TWO SATELLITE LISTINGS (AD-145): the experts' lead is 660 (343:11855 — its
   copy is three lines at 550 and would push the plate down) and the insights' 527
   (385:3687). Same weight as the rule above and after it. */
.adv-page-head--lead-wide .adv-page-head__lead { max-width: 660px; }
.adv-page-head--lead-527 .adv-page-head__lead { max-width: 527px; }

/* Photo strip: 450px on a listing. Every band is an inset plate now (`--inset` below;
   the master's since AD-138, the satellite's since AD-145), and the detail plate is
   200 (`--detail`). The ≤860 block restates both heights (TD-26, TD-31), so change
   them there too. It degrades to nothing when a firm has no image rather than to a
   grey slab. */
.adv-page-band {
  position: relative;
  display: flex;
  align-items: center;
  height: 450px;
  background-size: cover;
  background-position: center;
}
/* `--tall` (742, About's full-bleed photograph) is retired (AD-145): the master About
   (AD-138), Join (AD-142) and now the satellite About (ADR-0030 §5) all open on the
   split hero instead. */
/* `--plain` — the navy fallback for a TITLED band with no photograph — is retired
   (AD-143): its last caller was the master careers pages, which take the detail plate
   now, and the satellite's band always has a picture (`func/firm-image-css.html`). */
/* THE MASTER'S PHOTO BANDS ARE INSET PLATES (AD-138, ADR-0025 §1): 1320 wide in
   the container, radius 24 — the listing band 1485:37739 (x=60, y=388) and the
   detail band 1485:37746. Sized by width + auto margins rather than a wrapper,
   so the plate's left edge meets the breadcrumbs' at every width. */
.adv-page-band--inset {
  width: calc(100% - 2 * var(--adv-section-pad-x));
  max-width: var(--adv-container);
  margin-inline: auto;
  border-radius: var(--adv-radius-band);
}
/* THE MASTER DETAIL BAND (294:3588 → 1485:37746): 1320 x 200 at y=120, with NO
   section line and NO scrim — the frame draws neither. 200 is a documented
   literal (the plate's own height, no token binds it), and the ≤860 block
   restates it (TD-26), so change both together. Its top is "frame y −
   bar", like the listing head's. The breadcrumbs under it sit 60 below, not
   the 26 of their own padding — see the rule after `.adv-breadcrumbs`. */
.adv-page-band--detail {
  height: 200px;
  margin-block-start: calc(120px - var(--adv-nav-h) - var(--adv-border-width));
}

/* `.adv-page-band__inner` and `.adv-page-title--on-media` — the section name carried in
   white on a satellite detail band — retired in AD-145 (ADR-0030 §5): every detail plate
   on both tiers is titleless now. */
/* `.adv-page-band--titled` (54 under the bar, and the neutral scrim under white display type)
   retired in AD-145 with its last consumer, the satellite detail head. */

/* Breadcrumbs — plain text with slash separators, 16px medium in secondary
   ink. The separator is generated, so the trail is never in the copy and a
   screen reader does not read "slash" between every step. */
.adv-breadcrumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding: var(--adv-space-26) var(--adv-section-pad-x) 0;
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
  color: var(--adv-color-body);
}
/* ONE RHYTHM FOR EVERY TRAIL: 26 UNDER ITS PLATE, listing or detail (the client's
   2026-09-17 note, MD — ADR-0030 Amendment 1 §6). The detail pages had their own
   rule here, 60 under the 200 plate (y=380, AD-139 / ADR-0025 Amendment 3, read
   off 307:6050 and 336:7725); it is gone, so the base 26 above acts on both tiers
   and every detail type, and everything under the trail moves up 34 with it —
   the trail-to-content gaps below are unchanged. */
.adv-breadcrumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--adv-space-8);
  margin: 0;
  padding: 0;
  list-style: none;
}
.adv-breadcrumbs li + li::before {
  content: "/";
  margin-inline-end: var(--adv-space-8);
  color: var(--adv-color-body);
}
/* 24 under the bar where there is no band to follow (the contact page): the trail's
   text at y=124 on both tiers (553:12716, 498:4380). It was 64 under the satellite's
   old 60 bar; the bar is 100 on both tiers since ADR-0030 §1 (AD-145). */
.adv-breadcrumbs--bare { padding-block-start: var(--adv-space-24); }
/* The master's contact trail says the same thing twice since AD-145 (it was the 24 while
   the satellite's `--bare` was 64). The expert contact page takes the 24 through its
   wrapper, since its trail is the shared partial. */
.adv-breadcrumbs--master-bare,
.adv-crumbs-bar > .adv-breadcrumbs { padding-block-start: var(--adv-space-24); }
.adv-breadcrumbs a { color: inherit; text-decoration: none; }
.adv-breadcrumbs a:hover { color: var(--adv-hover-accent); }
.adv-breadcrumbs [aria-current="page"] { color: var(--adv-color-ink); }

/* The listing body — bands of content on a 96px rhythm inside the container. */
/* 45 ABOVE, 96 BELOW — and the two really are different.

   The breadcrumbs are a caption for the band above them, not a section, so the
   controls follow at 45 rather than at the page's 96 rhythm. Measured on both
   tiers and they agree: crumbs at y=864 and 25 tall, content column at y=934
   (satellite 343:11448/343:11449, master 522:8770/522:8771). It shipped at 96
   on both, which is why this is a correction and not a master-only tweak.

   The 96 below is the gap to the closing CTA band, which cancels its own top
   margin after a listing — see the adjacency exception further down. */
.adv-listing {
  display: flex;
  flex-direction: column;
  gap: var(--adv-section-gap);
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding: 45px var(--adv-section-pad-x) var(--adv-section-gap);
}

/* THE SEARCH RESULTS PANEL OPENS AT 96, NOT 45 (ADR-0021 §2, AD-126 item 23.2).
   The 45 above is the BREADCRUMB rhythm, measured and right for every listing
   that has crumbs. The search panel has none: it flips in from an entry screen
   that opens at the page's own 96, and after item 23.1 removed the top result
   counter the heading is the whole of `.adv-results`, so the two states of one
   screen opened 51px apart with nothing between them to explain it.

   A MODIFIER CLASS, NOT `[data-search-panel] .adv-listing`, AND THIS IS THE
   FILE'S GENERAL RULE. components.css contains no `min-width` query anywhere —
   every responsive rule here is a `max-width` override winning on source order
   at EQUAL specificity, and a media query adds no weight. A (0,2,0) descendant
   would therefore beat `.adv-listing { padding-block: 54px }` in the 860 block
   below and hand every phone-sized viewport 96 where the tier runs on 54, with
   nothing visible at the design width to show for it. (0,1,0) here, declared
   before every override, keeps that cascade intact. */
.adv-listing--search { padding-block-start: var(--adv-section-gap); }
/* THE CAREERS LISTING RUNS TIGHTER (AD-143, 589:16791): the controls 26 under the trail
   (431 after a trail that ends at 405), the results head 52 under them (543 after 491)
   and the pager 60 under the grid (1556 after 1496) — the experts listing's frame keeps
   45 / 96 / 34. The ≤860 block's `.adv-listing` 54s come later and win there; the
   pager's extra is restated there too. */
.adv-listing--careers { gap: 52px; padding-block-start: var(--adv-space-26); }
.adv-listing--careers .adv-pagination { margin-block-start: calc(60px - var(--adv-space-34)); }
/* THE MASTER'S SEARCH HEAD FOLLOWS ITS FRAME (AD-142 — ADR-0021 Amendment, master only).
   419:2901 / 419:4558: the title 57 under the bar (157), the field 57 under the title
   (284), the kind tags 34 under the field (the cluster's own gap), and the rail and the
   results 58 under the tags (481). So the listing opens at 57, spaces its two children
   57, and closes at 58 — the satellite keeps `--search`'s 96.
   Same weight as `.adv-listing`'s ≤860 rule (54 / 54) and earlier, so the tiers below
   keep their rhythm without a restatement. */
.adv-listing--search-frame { gap: 57px; padding-block: 57px 58px; }
/* THE SATELLITE'S RESULTS HEAD (AD-145 — ADR-0030 §9, an ADR-0021 §2 amendment for this
   tier). 553:13398 is drawn under the 100 bar: the title 57 under it (157), and the rail
   and the results 54 under the kind tags. Between the title and the field it keeps the
   96 `.adv-listing` spaces its children with — the frame's extra 33 was the "N results"
   line, which this tier removed (AD-126 item 23.1). Same weight and place as `--search-frame`,
   so the ≤860 54s still win below. */
.adv-listing--search-sat { padding-block: 57px 54px; }

/* The control ROWS of a listing, as one cluster. `.adv-listing` puts the
   section gap between all of its children, which is right between the controls
   and the results and far too much between the rows of the controls themselves:
   430:8832 stacks the search row (y=933), the scope tags (1027) and the chips
   row 34 apart and then leaves 90 before "Featured insights". The scope tags left
   in AD-196 (ADR-0059 §5); the gaps stay. Used by the insights listing and the
   search screen. */
.adv-listing__controls {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-34);
}

/* Controls row — filters left, search right. The search is 663 of 1320, so
   it takes the right half and the filters take what they need. */
.adv-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 22px;
  flex-wrap: wrap;
}
.adv-controls__filters { display: flex; gap: 22px; align-items: center; flex-wrap: wrap; }
/* Inside the search page's FACET RAIL the same wrapper must stay a
   COLUMN on desktop — the row form above is the listing bar's. Without
   this the rail's pills packed and wrapped inside the ~270px column
   (review find, 2026-08-27). */
.adv-search-results__rail > .adv-controls__filters {
  flex-direction: column;
  align-items: stretch;
  gap: var(--adv-space-16);
}
/* BASIS 663, NOT 420 (AK, 2026-08-31). 430:8838 is a space-between row 1320
   wide holding a 547 filter group, a 110 gap and a 663 field — so the field is
   a FIXED width and the gap is the remainder, not the other way round. At a
   420 basis the field only reached 663 when the pills left it that much room,
   and on the insights listing they did not: it rendered 655 with 22 beside it,
   which is the row's minimum gap and reads as the pills crowding the search.
   Still `1 1` and not `0 0` — below the desktop measure the field has to give
   before the row wraps. */
.adv-controls .adv-search { flex: 1 1 663px; max-width: 663px; }
/* NO FACET → NO HALF-ROW (AD-149, ADR-0030 Amendment 11). The 663 basis is the field's
   share of a row it SHARES with a filter group (430:8838: a 547 group, a 110 gap, a 663
   field), and `justify-content: space-between` is what puts one at each end. A listing
   that passes no facet key renders no `.adv-controls__filters` at all — the satellite's
   Practice areas since AD-149, the first on either tier — and the cap then stranded the
   field in the left half with 657 of nothing beside it. So the cap comes off, which is
   the rule this row already makes for itself below 860.

   `:has()` rather than a modifier the caller passes, because whether the sheet is drawn
   is decided inside listing-controls.html, and handing that decision back out would be
   two places that can disagree about it. BOTH TIERS gate the sheet on there being a
   facet, so this rule is the master's answer too the day a master listing passes none —
   no master screen does today, which is why it has never been seen there. */
.adv-controls:not(:has(.adv-controls__filters)) .adv-search { max-width: none; }

/* One results block: its header, its grid, its empty state and its button.
   34px between them, which is the design's gap inside a results section as
   distinct from the 96px between sections. */
.adv-results { display: flex; flex-direction: column; gap: var(--adv-space-34); }
/* The featured band's label sits 44 above its cards where the results head sits
   34 above its grid — 430:8832: label 1162→1191, cards 1235; "Articles"
   1707→1736, count 1748, grid 1799. Two rhythms in one frame, so the band that
   differs says so rather than both drifting to one value. 42, THE SCALE STEP,
   not the drawn 44: minting a token for a 2px difference is what rule 5 exists
   to prevent, and 42 is already in the scale. */
[data-listing-featured] { gap: var(--adv-space-42); }
/* THE MASTER INSIGHTS LISTING'S FEATURED LABEL IS 29 TALL (430:8832, AD-143): the AUTO
   line on the 24px label, starting 1162 against the scale's 1169. The box grows by 5 and
   the label starts 5 higher, so the carousel stays on the frame's 1235 (the label's own
   top lands 2 below the drawn 1162, the price of keeping 42 on the scale). */
.adv-results--featured-frame > .adv-section-label {
  line-height: var(--adv-small-lh);
  margin-block-start: -5px;
}
/* THE SATELLITE INSIGHTS LISTING (385:3685, AD-145): both labels — "Featured" and "All
   insights" — on their 29 box WITHOUT the master's −5, the cards 73 under the label's top
   (29 + 34 + 10) on both blocks, and "Load more" 26 under the grid (34 − 8). */
.adv-results--sat,
.adv-results--sat[data-listing-featured] { gap: var(--adv-space-34); }
.adv-results--sat > .adv-section-label { margin-block: 0 10px; }
.adv-results--sat > .adv-load-more { margin-block-start: -8px; }

/* Results header — the uppercase maroon label with a count beneath it.
   The count is 14px secondary and deliberately not a badge: it is a status
   line, and a firm with three lawyers should not be given a pill saying so. */
.adv-results-head { display: flex; flex-direction: column; gap: var(--adv-space-16); }
/* WITH A SORT AT ITS RIGHT END (AD-139, the experts listing — 435:10504):
   "Sorted by:" sits level with the label, its right edge on the container's
   (x=1380). A grid rather than a row, so the label and the count keep their
   column and their 16 while the sort takes a second track beside the label.
   Only under this modifier: every other results head stays the plain column. */
.adv-results-head--sorted {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--adv-space-26);
  row-gap: var(--adv-space-16);
  align-items: start;
}
.adv-results-head--sorted > * { grid-column: 1; }
.adv-results-head--sorted > .adv-sort,
.adv-results-head--sorted > .adv-view {
  grid-column: 2;
  grid-row: 1;
  align-self: center;
  margin-inline-start: 0;
}
/* …OR LEVEL WITH THE COUNT (AD-143, the careers listing — 589:16792: "Sorted by: Most
   recent" on the count's line, 584, under a label at 543).
   The control's box is 25 against the count's 17; -4 above and below keeps the row the
   count's height, so the grid stays 34 under the count, with the two centred on one line. */
.adv-results-head--sort-low > .adv-sort { grid-row: 2; margin-block: -4px; }
/* "View as" (AD-148) takes the same second track, level with the label. A flex box, not a
   block: a block wrapper would give the 14 px toggle the body's 25 px line, one taller than
   the label's 24, and push the whole grid down a pixel against today's page. */
.adv-results-head--sorted > .adv-view { display: flex; }
.adv-results-head__count {
  margin: 0;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-body);
}

/* Results grid — three across at 1440 with a 60px gutter. Explicitly a grid
   rather than the homepage's `.adv-card-row` flex: a row of three is a row
   of three, but a listing has an unknown count and the last row must not
   stretch two cards across the full width. */
/* EVERY CARD IN THE GRID IS THE SAME HEIGHT, and that height is the tallest
   card's — `grid-auto-rows: 1fr` sizes every row to the largest, and `stretch`
   makes the cards fill the row they are in. This replaces `align-items: start`,
   which sized each card to its own content.

   A LISTING'S CARDS ARE A SET, NOT SIX INDEPENDENT OBJECTS. Their height is not
   information — nobody reads "this lawyer's card is 42px shorter" as anything
   but a rendering fault, because the thing that varies is which OPTIONAL lines
   the record happens to carry: an expert with no role, a firm with two tags
   instead of three, a name that wraps to a second line. Measured on /experts/
   with those gaps present, the top row came out 722/614/646 — a 108px step
   across three cards standing side by side.

   `1fr` and not `stretch` alone: stretch equalises a ROW, so with three per row
   the second row can still settle at a different height than the first, and the
   grid goes ragged the moment you look down the page instead of across it. As a
   row TRACK size, `1fr` is `minmax(auto, 1fr)` — no row may be shorter than its
   content, and the leftover is shared equally, which in an auto-height grid
   lands every row on the tallest one.

   The cards absorb the extra where they were already built to: the portrait
   keeps its aspect ratio and the panel below it carries `flex: 1`, so a taller
   card is a taller PANEL and the photographs stay on one line. Same for the
   firm card's panel and the vacancy card's `space-between`.

   `--wide` opts out below, and so does the ≤560 stack — see both. */
.adv-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--adv-card-gap);
  align-items: stretch;
  grid-auto-rows: 1fr;
}
/* Two-up, and the columns are 10 apart, not the 60 the three-up grid uses:
   the insight row is a 330 image beside its text and already carries its own
   whitespace, so 649.5 + 10 + 649.5 fills the 1320 container. Rows are 54. */
/* The insight rows OPT OUT of the equal-height rule above. They are not plates
   with a variable panel — each is a fixed 330px image beside its text, so there
   is no region built to absorb slack, and a stretched row would only add empty
   space under the picture. */
.adv-grid--wide {
  grid-template-columns: repeat(2, 1fr);
  column-gap: 10px;
  row-gap: 54px;
  align-items: start;
  grid-auto-rows: auto;
}
/* In the GRID the media runs 335.42, against the 330 square everywhere else —
   authored in the frame (431:9291 vs the featured band), per its own FIX note:
   "keep both". */
.adv-grid--wide .adv-insight__media { width: 335.42px; }
/* THE MASTER'S INSIGHT GRID (AD-140, TD-21): a long compound word breaks
   instead of widening its column. A German title ("UNTERNEHMENSRESTRUKTURIERUNG")
   set the card's min-content to 662, which made the two 1440 columns unequal
   (662 / 648) and the row scroll sideways up to 1280. `anywhere` is this file's
   own answer to the same problem (the hero and search headings above). The
   column count below 1440 is the ≤1439 block's. */
.adv-grid--fluid .adv-insight__body { min-width: 0; }
.adv-grid--fluid :is(.adv-insight__title, .adv-insight__excerpt) { overflow-wrap: anywhere; }
/* THE MASTER'S CARD GRIDS (AD-144, ADR-0025 Amendment 10): the same answer for
   the practice-area and service listings. Their NL and DE names are compound
   words ("ondernemingsrecht" 227 wide at 26px), and in the two-up grid between
   561 and ~630 the title box is 181 — so one word set the card's min-content,
   the `1fr` tracks went unequal and the page scrolled sideways (NL +56). A word
   now breaks only when it cannot fit on a line of its own, so nothing that fits
   moves; the ≤860 block adds hyphenation for the two compounding languages. */
.adv-grid--long-words .adv-area-card { overflow-wrap: anywhere; }
/* A figure in the card's count line ("2 vestigingen") never splits from its
   noun; the ≤860 block lets the line itself wrap at the dot. */
.adv-area-card__stat { white-space: nowrap; }

/* THE LIST VIEW — "View as: list" on the master's Practice areas and Services (AD-148,
   ADR-0025 Amendment 18; the row redrawn in the 2026-09-25 round, 1593:20577, rows
   1593:20814 — AD-162, ADR-0038 §AD-162). The SAME cards the grid draws, under one
   modifier the engine toggles, so facets, search, counts, chips and "Load more" keep
   filtering one set of nodes.

   NO MEDIA QUERY, AND NONE NEEDED (ADR-0021 §3 / §9: this file has no `min-width` layer).
   The modifier is the gate: the engine sets `.adv-grid--list` only above 860 and drops it
   on the way down, so no ≤860 or ≤560 rule ever meets it. Every rule here is (0,2,0) or
   more, so the ≤1100 block's single-class `.adv-grid` / `.adv-area-card__title` cannot
   win between 861 and 1100.

   Geometry, in the frame's 1320 box: the title block at 0, 330 wide (title 28 / 1.2, the
   count 14 under it — 65 tall); the description at 330, 660 wide, the FULL text (16 / 25,
   two or three lines); "Explore … ↗" ending at 1320 and CENTRED ON THE DESCRIPTION (a
   two-line text puts it 12.5 down, a three-line one 25). The row is as tall as the taller
   of the title block (65, kept when a card has no count line) and the description. The
   rule is the frame's V stack of gap 26 with a LINE as its own child — a line of no
   height, stroked 1 px on its centre — so the pitch is row + 52 (75 → 127, 65 → 117,
   read from 1593:20814): 26 above the rule and 25 under it.

   TWO TRACKS, 1fr / 3fr, and the description and the explore line share the second
   through `__tail` (the cards' wrapper, `display: contents` everywhere else): a grid of
   2fr / 1fr whose one row is the description's height, so `align-items: center` centres
   the explore line on the text and not on the row — a two-line text in a 65 row sits at
   the top of it. Proportional tracks put the lines at 330 and 990 at every width, so
   nothing overflows between 861 and 1320: the explore line wraps instead.

   A 26 GUTTER EITHER SIDE OF THE TEXT, and not a `column-gap`: a gap would narrow the
   660 text. The title stops 26 short of its track and the explore line keeps 26 off the
   text (PR #137 review: without it a wrapped German "Rechtsgebiet entdecken" sat 3 px off
   the text at 861). The values no token carries are scoped here, as ADR-0025 §5 did for
   the detail columns. */
.adv-grid.adv-grid--list {
  --adv-list-title-lh: 1.2;
  --adv-list-count-gap: 14px;
  --adv-list-row: 65px;   /* the title block: 28 × 1.2 + 14 + the count's 17 */
  --adv-list-rule-gap: var(--adv-space-26);
  --adv-list-gutter: var(--adv-space-26);
  grid-template-columns: minmax(0, 1fr);
  grid-auto-rows: auto;
  gap: 0;
}
.adv-grid--list .adv-area-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 3fr);
  /* The third row is flexible so a three-line text (75) grows the row BELOW the count,
     not between it and the title: items spanning a flexible track are sized after the
     others. A shorter text leaves the row at the title block's 65. */
  grid-template-rows: auto auto 1fr;
  min-height: 0;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
}
/* The rule sits on every VISIBLE row after the first visible one, so a filter that hides
   the first card still gives the list a clean top. */
.adv-grid--list > .adv-area-card:not([hidden]) ~ .adv-area-card:not([hidden]) {
  margin-block-start: var(--adv-list-rule-gap);
  padding-block-start: calc(var(--adv-list-rule-gap) - var(--adv-border-width));
  border-block-start: var(--adv-border-width) solid var(--adv-color-border);
}
.adv-grid--list .adv-area-card__num { display: none; }
.adv-grid--list .adv-area-card__body { display: contents; }
.adv-grid--list .adv-area-card__title {
  grid-column: 1;
  grid-row: 1;
  max-width: calc(100% - var(--adv-list-gutter));
  min-height: 0;
  font-size: var(--adv-h2-size);
  line-height: var(--adv-list-title-lh);
}
/* The title track is 1fr of the box — 169 after the gutter at 861 — so a Dutch or German
   compound would otherwise break at an arbitrary letter (`--long-words` is
   `overflow-wrap: anywhere`); the ≤860 block's hyphenation never meets the list view. */
.adv-grid--list.adv-grid--long-words .adv-area-card__title:is(:lang(nl), :lang(de)) { hyphens: auto; }
/* In flow under the title; the dot between the figures is body grey, the figures blue. */
.adv-grid--list .adv-area-card__count {
  position: static;
  grid-column: 1;
  grid-row: 2;
  margin-block-start: var(--adv-list-count-gap);
  color: var(--adv-color-body);
}
.adv-grid--list .adv-area-card__stat { color: var(--adv-color-primary); }
.adv-grid--list .adv-area-card__tail {
  display: grid;
  grid-column: 2;
  grid-row: 1 / -1;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  align-items: center;
  align-content: start;
  /* The title block's height, so a card of the twelve with no count line yet (no firm
     covers it) keeps the frame's 65 row. Here and not on the card: from the second row
     on, the card's box also carries the rule's 26 + 1. */
  min-height: var(--adv-list-row);
}
/* THE FULL TEXT: both halves of the base's three-line clamp go (`display` and
   `overflow` — undo both or neither, see `--benefit`). At 660 no shipped description
   runs past three lines. */
.adv-grid--list .adv-area-card__text {
  grid-column: 1;
  grid-row: 1;
  display: block;
  overflow: visible;
  margin: 0;
}
.adv-grid--list .adv-area-card__more {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  grid-column: 2;
  grid-row: 1;
  justify-self: end;
  margin-inline-start: var(--adv-list-gutter);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  font-weight: var(--adv-weight-medium);
  color: var(--adv-color-primary);
}
/* A row is not a card: no lift and no wash (no frame draws a row hover). The whole row
   stays the link, and its explore line underlines, as the site's text links do. */
.adv-grid--list .adv-card--hover:hover { transform: none; background: none; }
@media (hover: hover) {
  .adv-grid--list a.adv-area-card:hover .adv-area-card__more { text-decoration: underline; }
}

/* Load more — a centred text link in corporate blue, 34px under the grid
   (handoff `templates/legal-experts-list/index.html`). Deliberately NOT
   `.adv-link-more`, which carries a "›" the design does not draw here.

   It appears only past the ninth card. The design shows it on the experts and
   insights listings and omits it on practice areas and services — the two that
   never run long. Rather than encode that per screen, the threshold decides:
   a firm with six practice areas never sees it, one with thirty lawyers does. */
/* PAGINATION                                                node 529:10822
   ‹ 1 2 3 4 … 9 › — 26 apart, centred, the current page in corporate blue at
   Medium and the rest 14/400 in secondary ink. The chevrons dim to the border
   colour at the ends of the range rather than disappearing, so the control
   keeps its width and nothing under it moves.

   A SIBLING OF `.adv-load-more`, NOT A REPLACEMENT. The design uses both: the
   practice-areas and services listings unroll one list, the experts and
   insights listings number their pages. Which one a screen gets is a
   `data-paginate` attribute in the markup, not a second engine. */
.adv-pagination {
  display: flex;
  gap: var(--adv-space-26);
  align-items: center;
  justify-content: center;
}
.adv-pagination button {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-regular);
  font-size: var(--adv-small-size);
  line-height: 1;
  color: var(--adv-color-body);
  cursor: pointer;
}
.adv-pagination button:hover { color: var(--adv-hover-accent); }
/* The current page steps up a size AND a weight — 16/500 against 14/400 — which
   is how the frame distinguishes it, not colour alone. */
.adv-pagination button[aria-current="page"] {
  font-size: var(--adv-nav-size);
  font-weight: var(--adv-weight-medium);
  color: var(--adv-color-primary);
  cursor: default;
}
/* The ellipsis is not a control. */
.adv-pagination span { font-size: var(--adv-small-size); color: var(--adv-color-body); }
.adv-pagination button:disabled { color: var(--adv-color-border); cursor: default; }
.adv-pagination button:focus-visible {
  outline: var(--adv-focus-ring-width) solid var(--adv-focus-ring);
  outline-offset: var(--adv-focus-ring-offset);
}

/* "Sorted by: …" — plain 14px text with a caret, hard right on the results
   head (431:9635). Deliberately NOT a pill: the frame draws no box, and a
   second pill on that line would compete with the filters above. The panel is
   the shared one, right-aligned so it opens under its own text. */
/* The sort lives at the right end of the APPLIED-FILTERS row (431:9291 puts it
   at x=1149 on the chips' line, not on the results head — the earlier pass had
   it up there and the canonical frame moved it down). The row is a flex line,
   so "hard right" is an auto margin, and the sort stays put when the chips
   before it hide. */
.adv-controls-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--adv-space-26);
  min-height: 25px;
}
.adv-sort { margin-inline-start: auto; }
/* A LISTING'S OWN SORT IS 402-ONLY. Its desktop position is unread — the frames
   that draw it are the mobile pair (704:28359 / 704:28361), and the one screen
   with a desktop sort puts it beside the chips in `.adv-controls-row`, which is
   a different element and keeps working. Putting this one into the desktop pill
   row on a guess is how a control ends up in two places.

   Scoped to `.adv-controls` so it does not touch that other sort, and written
   without `>` because site.js moves the node between the controls column and the
   row it builds for 402 — the rule has to hold in both homes. */
.adv-controls .adv-sort { display: none; }
/* The experts listing's sort lives in its results head instead (AD-139), where
   it is shown at 1440 and carried into the 402 row by `placeSort()` below 860 —
   at which point this rule's ≤860 twin shows it there. */
/* THE INERT-TAG RULE IS GONE (AK, 2026-08-31). It greyed a scope tag with
   nothing behind it — "News before any News exists" — which meant the row's
   appearance reported today's data rather than the axis the screen can be read
   along, the same mistake the facet floor made. The tags are live buttons now;
   News selects, finds nothing and lands on the designed empty state, which says
   so in a sentence instead of in a shade of grey. */
/* "View as" (AD-148) is the same control in look — its own class only because the
   scripts find the sort by `.adv-sort` (see `listing-view.html`). */
.adv-sort__toggle,
.adv-view__toggle {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--adv-font-body);
  font-size: var(--adv-small-size);
  line-height: 1;
  color: var(--adv-color-ink);
  white-space: nowrap;
  cursor: pointer;
}
.adv-sort__toggle:hover,
.adv-view__toggle:hover { color: var(--adv-hover-accent); }
/* THE SORT PANEL HANGS FROM ITS RIGHT EDGE — it is the rightmost control in its
   row on every screen that has one, so a menu growing rightwards has nowhere to
   go. `inset-inline-end: 0` alone did not achieve that: `.adv-filter-wrap
   .adv-filter-panel` above sets `inset-inline-start: 0`, this rule only ADDED
   the other side, and an absolutely-positioned box with both insets at 0 and a
   `min-width` wider than its containing block grows from the START edge. On 402
   the toggle sits at x=296 in a 402 viewport, so the 180-wide menu ran to 476 —
   74 past the screen, which is what AK saw. `auto` releases the start edge and
   lets the min-width push the box leftwards instead (AK, 2026-09-02). */
.adv-sort .adv-filter-panel,
.adv-view .adv-filter-panel {
  position: absolute;
  inset-inline-start: auto;
  inset-inline-end: 0;
  inset-block-start: 100%;
  margin-block-start: var(--adv-space-8);
  z-index: var(--adv-z-dropdown);
  min-width: 180px;
}

.adv-load-more { display: flex; justify-content: center; }
.adv-load-more button {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: 1;
  color: var(--adv-color-primary);
  cursor: pointer;
}
.adv-load-more button:hover { color: var(--adv-hover-accent); }
.adv-load-more button:focus-visible {
  outline: var(--adv-focus-ring-width) solid var(--adv-focus-ring);
  outline-offset: var(--adv-focus-ring-offset);
}

/* Empty state [authored — ADR-0014 §4 lists it as not designed].
   A firm with no articles yet is the normal case on day one, not an error. */
.adv-empty {
  padding: var(--adv-space-40) 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-body);
}

/* THE DESIGNED EMPTY STATE                                   node 560:15272

   `.adv-empty` above is the other kind: a list that has nothing IN it, where
   the honest answer is one line of grey text. This one is a list whose FILTERS
   matched nothing — the visitor did something, and the screen has to tell them
   what and offer the way back. The design draws it, and §B4 of docs/design-map
   listed empty states as undesigned; for this screen that is no longer true.

   Centred, 588 wide, 16 between the three parts. The applied-filter chips stay
   visible above it — deliberately, so the visitor can see what to remove.

   THE HEADING IS BURGUNDY. It borrows the section-label colour rather than
   taking ink or the error red the rest of a system would reach for, which is
   unusual enough to look like a mistake and is not one: 38/600 in
   `corporate/burgundy` on the frame. It is `nowrap` there; that is not carried
   over, because "No practice areas found" is longer in German and a headline
   that overflows its own 588 is worse than one that wraps. */
.adv-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--adv-space-16);
  max-width: 588px;
  margin-inline: auto;
  text-align: center;
}
/* NAVY AND AUTO, both read off 560:15424 (AK, 2026-08-31).

   THE COLOUR was burgundy. Burgundy is the SECTION-LABEL accent in this system
   — the uppercase 24 above a band — and using it on a 38px sentence made "No
   practice areas found" read as a label for the block underneath rather than as
   the block's own headline. The frame binds `corporate/navy`, which is what
   every other heading of this weight takes.

   THE LINE BOX was `1`, so the title measured 38 against the frame's 46. The
   frame names the style `Heading/semibold_38px` — literally `--adv-h1-*` — and
   reports `leading: normal`, which is AUTO, which is 1.21 for Inter. Same
   transcription trap as everywhere else today, but a component-local literal
   rather than the `--adv-page-title-lh` token, so it is simply the token pair
   now and needs no wider decision.

   ONE RULE FOR SIX SCREENS: practice areas, services, firms, experts, careers
   and the insights listing all render this block. */
.adv-empty-state__title {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h1-size);
  line-height: var(--adv-h1-lh);
  color: var(--adv-color-primary-dark);
}
.adv-empty-state__text {
  margin: 0;
  /* BODY 16/25, NOT THE 24 SUBTITLE. 560:15272 sets this paragraph in
     `Body/regular_16px` — 16px on a 25px line — inside its 588 box, which is
     what makes the sentence read as two lines. At 24 the same words needed
     four, and the block stopped looking like a note under a heading and
     started looking like a second lede. */
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}

/* ---------------------------------------------------------------------
   Closing CTA band — full-bleed warm surface, image left, copy right.
   Repeats at the foot of EVERY listing and detail screen, which is why it
   is one partial and one rule rather than eleven copies.
   --------------------------------------------------------------------- */
/* The 96px below is a MARGIN, and has to be: the band and the footer are both
   full-bleed coloured surfaces, so the gap between them is page background —
   warm grey, then 96 of page, then the footer's dark grey. Padding inside
   either one would be painted and the two plates would still meet.

   Same reasoning as the figures row on About; the design puts every band in one
   column at a 96 rhythm and does not care whether a band has a background, but
   CSS very much does. Measured: CTA ends y=3414 / footer starts y=3510 on
   About, 1342 → 1438 on the listings. */
.adv-cta-band {
  background: var(--adv-color-surface-alt);
  margin-block-end: var(--adv-section-gap);
}
/* 550 + 110 + 659, NOT AN EVEN SPLIT (AK, 2026-08-31). The comment below has
   said "a 550x250 rounded card" since this was written, and the grid never
   honoured it: `1fr 1fr` on the 1320 container made the plate 630 and started
   the copy at 750. FOUR frames agree to the pixel and none of them is an even
   split — 553:13682 (search), 430:8904 (insights listing), 422:6554 (article)
   and 597:18524 (careers) all draw Rectangle 72 at x=61 550 wide and the copy
   frame at x=721, 659 wide. 721 is the container's midpoint, so this is the
   same "the right column starts at half" arithmetic the practice-areas band,
   the articles head and the closing bands all share; the gap is what is left
   over, not a spacing step.

   Expressed as fixed tracks rather than fractions because that is what the
   frames measure, and `minmax(0, …)` so a long headline cannot push the plate
   out of shape. */
.adv-cta-band__inner {
  display: grid;
  grid-template-columns: var(--adv-cta-cols, 550px minmax(0, 659px));
  justify-content: space-between;
  gap: var(--adv-space-60);
  align-items: center;
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding: 54px var(--adv-section-pad-x);
}
/* NO PHOTOGRAPH → NO EMPTY HALF, the same rule as `.adv-offices`. The media is
   a 550x250 rounded card, so an empty one reads as an image that failed to load
   rather than as a band that has none; the copy takes the whole row instead.
   `:has()` because whether there is an image is decided in the template, and
   passing that decision back out to the wrapper means two places that can
   disagree about it. */
.adv-cta-band__inner:not(:has(.adv-cta-band__media)) { grid-template-columns: 1fr; }
/* THE MASTER'S PLATE GIVES TOO (AD-140, TD-21). A fixed 550 plate left the copy
   199 at 861, where "Sie brauchen rechtliche Unterstützung?" and the NL/FR/DE
   buttons ran past the viewport (to 861–915). Both tracks shrink now and share
   the row below 1440 (375 / 375 at 861); at 1440 both reach their frame widths
   and `space-between` keeps the copy on 721. The plate keeps its 250 height. */
.adv-cta-band--fluid { --adv-cta-cols: minmax(0, 550px) minmax(0, 659px); }
/* NO PHOTOGRAPH → THE FIRM'S MONOGRAM, same treatment and the same tokens as
   the firm card's empty plate and the insight row's: the 550x250 card stays
   (the band's rhythm depends on it) and is never filled with a shared stock
   photograph, which would put one firm's premises under another firm's name.
   Only the ARTICLE page's partner band uses this — the network's own CTA bands
   drop the plate entirely when unconfigured, because the network has no
   monogram to fall back to. */
.adv-cta-band__media--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--adv-color-surface);
  box-shadow: inset 0 0 0 var(--adv-border-width) var(--adv-color-border);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-monogram-size);
  line-height: 1;
  color: var(--adv-color-border);
}
.adv-cta-band__media {
  height: 250px;
  border-radius: var(--adv-radius-card);
  background-size: cover;
  background-position: center;
}
.adv-cta-band__body { display: flex; flex-direction: column; gap: var(--adv-stack-gap); align-items: flex-start; }
.adv-cta-band__title {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h1-size);
  line-height: var(--adv-h1-lh);
  color: var(--adv-color-ink);
}
.adv-cta-band__text {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
/* THE ARTICLE'S PARTNER BAND (AD-143, 422:6554 — master only): "Learn more about
   Adverit Antwerp" in a 402 box, so it breaks over two lines as drawn, and the
   sentence under it at the frame's 565. */
.adv-cta-band--partner .adv-cta-band__title { max-width: 402px; }
.adv-cta-band--partner .adv-cta-band__text { max-width: 565px; }

/* `.adv-page-band--short` (the satellite's 240 detail band) retired in AD-145: the detail
   plate is `--inset --detail` on both tiers. */

/* Breadcrumbs at the page margin below the band, the entity's own name under
   them and INDENTED to the prose column.

   THE FIGMA FRAMES WIN HERE, REVERSING THE NOTE THAT STOOD IN THIS PLACE (AK,
   2026-09-01). It read: "An earlier pass indented the name to x=390 after the
   Figma frame; the handoff puts it at the margin, and layout is where the
   handoff is authoritative." The earlier pass was right.

   Two frames say so independently and agree to the pixel — 343:11471 (practice
   area) and 385:3938 (insights):

     band          114 … 354
     breadcrumbs   x=60, y=380   → 26 under the band
     h1            x=390, y=450  → 45 under the crumbs, 56 down to the content
     body copy     x=390         → the h1 starts where the reading starts

   "Layout is what a handoff is for" is a good rule and it is not a licence to
   ignore two frames that agree with each other and disagree with it. The
   handoff's 430/8 put the crumbs 50px too low and left the title at the margin
   while the prose beside it began at 390, so the eye started the page in one
   column and the text in another. Measured before the change on
   /practice-areas/business-law/: crumbs 431, h1 at x=60 against a body at 390. */
.adv-detail-head {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-8);
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  /* 45 BELOW THE TRAIL, not 64. 343:11878 ends the crumbs at 405 and starts the
     portrait at 450; the 64 put the whole expert page 20px low, and every box in
     it with the same offset. It is also the 45 the titled variant uses between
     its crumbs and its h1, so the two heads now agree on one number.
     The article page still takes 0 here and supplies its own — see below. */
  padding: var(--adv-space-26) var(--adv-section-pad-x) 45px;
}
/* THE ARTICLE PAYS THIS GAP TWICE, so the wrapper gives it up on that page only.
   `.adv-article__title` carries `margin-block-start: 42` measured against
   385:3938 — "380→405, title 450→660", i.e. 45 under the crumbs — and the
   wrapper's 64 lands on top of it: the title rendered 106 under the crumbs, 61
   off the frame. Zeroing here leaves the page's own 42, which is the value that
   was measured and the one its comment explains.
   SCOPED WITH `+`, NOT MADE THE BASE. Zeroing the base regressed the expert page
   in the same edit — `.adv-detail` has no top margin of its own, so its content
   ran flush into the crumbs, which is exactly the fault the note on
   `.adv-expert-detail` was written about. Only the pages that supply their own
   gap may take this, and today that is the article. */
.adv-detail-head:has(+ .adv-article-body) { padding-block-end: 0; }
/* The crumbs partial carries its own page padding for the listing screens; in
   here the wrapper already provides it. */
.adv-detail-head .adv-breadcrumbs { max-width: none; margin: 0; padding: 0; }
/* The titled variant's own rhythm: 26 under the band (the base, restated so the
   whole block reads in one place), 45 from the crumbs to the name, 56 from the
   name to the content row. Was 76 / 8 / 64. */
.adv-detail-head:has(h1) {
  padding-block: var(--adv-space-26) 56px;
  gap: 45px;
}
/* THE NAME IS LEVEL WITH THE PROSE, NOT WITH THE PAGE MARGIN — x=390 on both
   frames, which is the body column's own left edge (343:11488 at 389, 385:4256
   at 390). Written against the wrapper's page padding rather than as a bare 330
   so the two move together if the margin ever does.
   On the h1 and not on the wrapper: the crumbs stay at x=60, which is how the
   master reaches the same layout by keeping them outside its own `--indent`
   block. Here they share a wrapper, so only the name moves.

   `:not(--indent)` IS LOAD-BEARING (AK, 2026-09-02). The comment above already
   says the master reaches this layout through `--indent`, and then the selector
   went and did it a second time: on a master service or practice-area detail the
   wrapper's 390 padding and this 330 margin BOTH applied and the title landed at
   x=720 against the frame's 390 (336:8124). Reported by AK on
   /services/consultancy-advice/. Everything else was already safe — the article
   title is `.adv-article__title`, the expert's is `.adv-detail__name`, and the
   firm page's h1 is nested inside the identity column rather than a direct child
   — so the two twinned detail screens were the whole of it.

   THE INDENT ALSO HAS TO FOLLOW THE BODY COLUMN DOWN, and as a bare 330 it did
   not: `.adv-detail--3col` becomes `220px 1fr` at 1100 and one column at 860, so
   the title stayed at 330 while the prose it is meant to be level with moved to
   260 and then to the margin. At 402 the 370 remainder inside a 362 column
   squeezed the h1 to **width 0** — the title was not misplaced there, it was
   invisible, on both tiers. Both steps are restated in the media blocks below;
   this file's other indents are read off the same grid. */
.adv-detail-head:not(.adv-detail-head--indent) > h1,
.adv-detail-head:not(.adv-detail-head--indent) > .adv-detail-head__chips {
  margin-inline-start: calc(390px - var(--adv-section-pad-x));
}
/* A TOPIC'S CHIPS UNDER ITS TITLE (AD-164, ADR-0038 §AD-164 §3; 1734:30825): its areas,
   then its services, each a link to its page. They are the site's `.adv-badge` at the
   frame's outer size (37), though the frame's chips draw no border (a designer question).
   26 under the h1, 8 apart, and 45 down to the columns where a title alone has 56
   (1734:30746: the chips end at 583, the columns start at 628). The chips follow the
   title's indent at every width (the rule above and its ≤1100 / ≤860 restatements). At
   ≤560 the head's own 16 stack places them under the title and above the photo, by
   analogy (no 402 frame): the ≤560 head rule is (0,2,1) and outranks this (0,2,0). */
.adv-detail-head__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--adv-space-8);
}
.adv-detail-head:has(> .adv-detail-head__chips) {
  gap: var(--adv-space-26);
  padding-block-end: 45px;
}
/* A TOPIC'S NAME IS OFTEN ONE LONG COMPOUND (AD-164): "Aandeelhoudersovereenkomsten" at 58/700
   is ~880 wide, and from 861 to about 950 the title's column (the prose column's, from 260)
   holds less — the page scrolled sideways at 861 in Dutch, on both tiers. On a topic page (the
   head's `--topic`, set whether or not any chip survives the firm's marks) the name breaks at
   a syllable in NL and DE at every width, the rule `--long-words` gives every detail title at
   ≤560, and `overflow-wrap` is the floor for the other languages and a browser with no
   dictionary. Area and service titles are untouched. */
.adv-detail-head--topic > h1 { overflow-wrap: break-word; }
.adv-detail-head--topic > h1:is(:lang(nl), :lang(de)) { hyphens: auto; }
/* THE MASTER INDENTS THE ENTITY NAME to x=390 (294:3588 / 295:3839), level with
   the prose column rather than at the page margin, so the eye starts the page
   where the reading starts. Its breadcrumbs stay at the margin and therefore
   sit OUTSIDE this wrapper, which is why the block padding is restated: 45
   under the crumbs, 56 down to the content row. The firm sites put the name at
   the margin — their handoff says so, and layout is what a handoff is for. */
.adv-detail-head--indent {
  padding-block: 45px 56px;
  padding-inline-start: 390px;
}
.adv-detail-head--indent:has(h1) { padding-block-start: 45px; }
/* The office page's identity block (430:8087): name / place / tags in the RIGHT half.

   `--split` is the page's two-column head; since AD-142 (decision 6) nothing occupies its
   left column — the logotype plate (`.adv-firm-logo`, deleted with it) no longer introduces
   the page, which is titled by the office. AK's "BOTH TRACKS ARE ALWAYS OCCUPIED"
   (2026-09-01) is reversed; the empty half is space, not an element. */
.adv-detail-head--split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--adv-space-60);
  align-items: start;
  padding-block: 45px 0;
}
/* THE OFFICE PAGE (AD-142): the identity at (720, 450) — the container's midpoint, and
   70 under the breadcrumbs' top (380), which is the practice-area and service rhythm
   (ADR-0025 Amendment 5; Amendment 3 had left this page at +51). The crumbs' box ends at
   405, so 45 on top; nothing underneath — About opens 96 under the identity's foot with
   its own band padding.
   `:has(h1)` IS LOAD-BEARING both ways: at (0,1,1) it outranks the titled head's base
   rule (`.adv-detail-head:has(h1)`, 26 / 56) by source order, and it still loses to the
   ≤1100 and ≤860 head rules further down, which are the same weight and later. */
.adv-detail-head--office:has(h1) {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: 0;
  padding-block: 45px 0;
}
.adv-detail-head--office > .adv-stack { grid-column: 2; }
/* 16/25 in INK (430:8087 #3C3C3C) — not `.adv-band__text`, whose body grey the old
   identity used. */
.adv-detail-head__place {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
/* Two offices in one city: the firm named after the office title, one step quieter
   (the About row's `.adv-offices__row-firm` rule). */
.adv-detail-head__firm { font-weight: var(--adv-weight-regular); }

/* ABOUT ⟨OFFICE⟩ (430:8150): the firm's paragraphs in the 660 column, 16 apart — the
   frame's paragraph step, not `.adv-prose`'s 8 (ADR-0023). Body ink. */
.adv-office-about {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-16);
  max-width: 660px;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
.adv-office-about > * { margin: 0; }

/* OUR STORY'S HEAD (553:14136): the label, the intro 63 under the label's top (the
   label's box is 24, so 39), the timeline 34 under the intro's foot; the intro runs 675. */
.adv-office-story { display: flex; flex-direction: column; align-items: flex-start; }
.adv-office-story > .adv-section-label { margin-block-end: 39px; }
.adv-office-story__intro {
  margin: 0 0 var(--adv-space-34);
  max-width: 675px;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}

/* Compact expert row — node 343:11491 (270x78). The related-experts rail on
   the practice-area page and the author line on an article. A different
   component from both card families: no panel, no border, just the portrait
   and two lines. */
.adv-person-mini {
  display: flex;
  /* The four `--adv-person-mini-*` hooks below are bound by the master's detail
     columns only (`.adv-detail__rails--frame`, AD-138 / AD-145); every other row reads
     the fallbacks, which are the values this component always had. */
  align-items: var(--adv-person-mini-align, center);
  gap: 18px;
  text-decoration: none;
  color: inherit;
}
.adv-person-mini__photo {
  width: 78px;
  height: 78px;
  flex-shrink: 0;
  object-fit: cover;
  border-radius: var(--adv-radius-card);
  display: block;
}
.adv-person-mini__photo--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--adv-color-accent-light-blue);
  color: var(--adv-color-primary-dark);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h3-size);
}
.adv-person-mini__name {
  display: block;
  margin-block-start: var(--adv-person-mini-name-inset, 0);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-person-mini-name-lh, 1);
  color: var(--adv-person-mini-name-color, var(--adv-color-ink-strong));
}
.adv-person-mini:hover .adv-person-mini__name { color: var(--adv-hover-accent); }
/* The second line's FALLBACK is blue (`blueDeep`) — the satellite's pre-2026-09-16 row.
   Since AD-145 (ADR-0030 §7) no row on either tier reads it: the detail pages' experts
   columns print the name only, and both article bylines bind the hooks
   (`.adv-article__byline--person`), so the role is 14 in ink. */
.adv-person-mini__role {
  display: block;
  margin-block-start: 5px;
  font-size: var(--adv-person-mini-role-size, var(--adv-body-size));
  line-height: var(--adv-person-mini-role-lh, var(--adv-body-lh));
  color: var(--adv-person-mini-role-color, var(--adv-color-blue-deep));
}

/* ---------------------------------------------------------------------
   Detail screens
   The expert detail (343:11878) is the richest of the three and the other
   two are subsets of it, so the pieces are named for their role rather
   than for the entity: every detail page is a 494px media column beside a
   text column, then meta groups, then related content.
   --------------------------------------------------------------------- */
/* The expert page is 610 | 619 of a 1279 row: the left column holds the 494
   portrait AND the two meta columns beneath it (contact at x=0 w208, practice
   at x=330 w280), the right column the name and the prose. An earlier pass read
   the left column as just the portrait and put the meta groups in with the
   biography, which is why the page had a tall empty gutter under the photo. */
/* 610 AND 619 ARE PIXELS, NOT A RATIO. They were written `610fr 619fr`, and an
   `fr` distributes the FREE space in that proportion rather than setting the
   track: on the 1320 container with a 50 gap the two came out 630.3 and 639.7,
   so the right column began at 740 where 343:11918 begins it at 720 — 60 + 610 +
   50, the number the comment above already states. Everything in the right
   column inherited the 20: the name, the role, the prose, the section titles.

   Measured on /lawyers/karel-peeters/ before the change: body column x=740 w=640
   against the frame's x=720 w=619.

   The same arithmetic as `.adv-approach__row`'s `600fr 550fr` — an `fr` pair
   copied from two measured widths reads right and lands wrong every time the
   container is not exactly their sum. */
.adv-detail {
  display: grid;
  grid-template-columns: minmax(0, 610px) minmax(0, 619px);
  gap: 50px;
  align-items: start;
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding-inline: var(--adv-section-pad-x);
}
.adv-detail--wide { grid-template-columns: 1fr; }
/* The practice-area page is three columns, not two: sibling areas on the left,
   the prose in the middle, related experts on the right (node 343:11478). */
/* MEASURED OFF 336:7720, and the middle column is the point of it. The frame
   puts the sibling rail at x=60 w=269, the prose at x=**390** w=618 and the
   right-hand rails at x=1110 w=270, flush to the 1380 margin. The title above
   them starts at 390 too (`--indent`), so the prose and the h1 share one edge.

   `270px 1fr 270px` on the container's 50px gap put the prose at 380 — ten short
   of the title, which is the misalignment AK could see — and ended the rails at
   1325, 55 short of the margin. The tracks below are the frame's own arithmetic:
   270 + 60 = 390 for the prose, 618 wide, and the rest of the row for the rails,
   whose 270 of content is pinned to its far edge (`justify-items: end` below).
   The gap either side of the prose is UNEQUAL in the frame — 61 and 102 — which
   a uniform `column-gap` cannot express; giving the last track the slack and
   right-aligning its content lands both edges without inventing a value. */
.adv-detail--3col {
  grid-template-columns: var(--adv-detail-3col-cols, 270px 618px 1fr);
  column-gap: var(--adv-space-60);
}
/* THE MASTER'S PROSE COLUMN GIVES BETWEEN 1101 AND 1397 (AD-140, TD-21). The
   three tracks above plus the rail's pinned 270 need 1338 of content, so every
   master practice-area and service detail scrolled sideways from 1101 (where
   the ≤1100 two-column layout stops) to 1397. The prose now shrinks — 321 at
   1101, 500 at 1280 — and the rail track keeps a 270 floor. At 1440 the prose
   reaches its 618 before the rail track takes the rest (312), as the frame
   (336:7720) draws it. */
.adv-detail--fluid { --adv-detail-3col-cols: 270px minmax(0, 618px) minmax(270px, 1fr); }
/* Only the rails are pulled to the far edge. NOT `justify-items` on the grid:
   that shrink-wraps every item, and the sibling rail promptly came out 253 wide
   instead of filling its 270 track — the links are short and nothing else was
   holding it open. */
.adv-detail--3col > :last-child { justify-self: end; width: 270px; }
.adv-detail__rail { display: flex; flex-direction: column; gap: var(--adv-space-26); }
/* Two rails stacked in one column — the master's practice-area page carries
   related firms above related experts, 96 apart (407:6990). The firm sites'
   page has a single rail and never needs this. */
.adv-detail__rails { display: flex; flex-direction: column; gap: var(--adv-section-gap); }
/* The eyebrow is 52 above the first card (handoff: label at y=0, cards at 52),
   twice the gap between the cards themselves. */
.adv-detail__rail > .adv-section-label { margin-block-end: var(--adv-space-26); }
/* RELATED TOPICS, THE TOPIC PAGE'S LEFT RAIL (AD-164, ADR-0038 §AD-164 §4; 1734:30746): the
   label (24 Medium caps, its AUTO 29: `--auto`) → 26 → the area rail's rows (`--frame`: 14
   Regular grey, 19 tall, 26 apart, so a pitch of 45). The column's own 26 is the whole gap,
   not 26 + 26. A row is the frame's 19 box, not the list item's 25 body strut: measured, the
   area rail runs at a pitch of 51 for that reason (an older defect, left to its own ticket).
   The 19 is the row instance's own box ("Company law", 14 Regular); no token carries it, and
   the browser's `normal` for the 14 is 17, so it is scoped here (ADR-0025 §5's pattern).

   NO LABEL ABOVE 860, AND THE TOPIC ITSELF FIRST (ADR-0038 §AD-172 Amendment 1 §3): 1734:30746's
   rail (1734:30752) has no label and starts level with the text, its first row the topic in
   `State=Selected` — 16 Medium navy in the same 19 box, so every row stays 45 apart. The label
   stays in the markup and names the `<nav>` (`aria-labelledby` reads a hidden node); the ≤860
   block shows it again once the rail is stacked (over the text at 561–860, under it at ≤560).
   The current row's 19 undoes `--frame`'s 25, the area rails' 16/500/25. */
.adv-detail--topic { --adv-topic-rail-row: 19px; }   /* 1734:30746: a Related-topics row */
.adv-detail--topic > .adv-detail__rail > .adv-section-label { display: none; margin-block-end: 0; }
.adv-detail--topic > .adv-detail__rail .adv-detail__links--frame [aria-current="page"] {
  line-height: var(--adv-topic-rail-row);
}
.adv-detail--topic > .adv-detail__rail .adv-detail__links--frame > li {
  display: flex;
  align-items: center;
  min-height: var(--adv-topic-rail-row);
}
/* AND ON THE MASTER'S RIGHT COLUMN IT IS NOT (AK, 2026-09-01). 407:8199
   (service detail) and 407:6990 (practice-area detail) are identical here and
   both contradict the handoff the rule above was built from: label 0..58, the
   CARD GROUP at 84, "View all" at 278 of a 303-tall rail — so 26 under the
   label, 26 above the link, and the two cards 12 apart INSIDE that group. Ours
   ran 52 and 26: the label's 26 margin stacking on the column's own 26 gap, and
   the cards inheriting the outer rhythm because there is nothing between them
   and the rail.

   NO WRAPPER, though the frame has one (Frame 184). At 402 this rail becomes a
   2-up grid and the cards must stay DIRECT children to be placed in it — a
   group div would drop them out of the grid and take the label's row span with
   them. So the group's 12 becomes the column's gap and the outer 26 is paid
   back as margin on the two things that sit outside the group. `26 - 12`
   written as the arithmetic rather than as 14, because 14 is not a step and
   would read as one.

   `--master` WAS `--dual` UNTIL AD-138. The column carried two rails then —
   firms above experts — and the name described that. The 2026-09-16 frame
   keeps ONE (experts, 407:6990) with exactly this rhythm, so the rules stay
   and the name now says whose column it is (ADR-0025 §7).

   A POSITIVE MODIFIER, AND THE WRAPPER ALONE WOULD HAVE BEEN WRONG. The
   satellite's practice-area detail wraps its single expert rail in the same
   `.adv-detail__rails` purely as a MOBILE hook (760:17871) — its own comment
   calls the desktop "transparent", and scoping to the bare wrapper would have
   stopped that being true. That tier has its own frames and has not been
   measured against them yet (AD-78 satellite half, Ш2). A positive modifier on
   the master's column, rather than `:not(--plain)`: `:not()` carries
   its argument's weight, which lifts these to three classes and puts them ABOVE
   the 402 resets — the same collision measured a paragraph up. Two classes, and
   the tier below still wins on source order.

   TWO CLASSES, NOT A CHILD CHAIN, and it is load-bearing. The 402 block puts
   this label and this link in one head row and clears their margins to do it;
   written `.adv-detail__rails > .adv-detail__rail > .adv-section-label` these
   rules outrank that reset, the margins survive into the grid and the link
   drops off the label's line. Measured, not reasoned: at three classes the 402
   head row came out 14px taller and the link 14 below the label. Kept at two,
   they lose to the media query on source order, which is the order that is
   wanted — this is the desktop case and the tier below restates it. */
/* THE EXPERT ROW (407:6990, AD-138): the name 16/500/25 in text/main at the
   row's top + 7, the place 14/400 in text/secondary 5 under it — top-aligned,
   not centred on the 78 photograph. Bound here through the row's hooks, so the
   402 rules below (which set these properties directly) still win there. */
/* THE ROW HOOKS ARE BOTH TIERS' (`--frame`, ADR-0030 §7): the satellite's 2026-09-16
   detail frames (343:11471, 343:12313) draw the same row, name only. The 12 rhythm
   below stays the master's (`--master`): the satellite's rows are 26 apart (pitch 104)
   under a two-line AUTO label. */
.adv-detail__rails--frame {
  --adv-person-mini-align: flex-start;
  --adv-person-mini-name-inset: 7px;
  --adv-person-mini-name-lh: var(--adv-body-lh);
  --adv-person-mini-name-color: var(--adv-color-ink);
  --adv-person-mini-role-size: var(--adv-small-size);
  --adv-person-mini-role-lh: var(--adv-small-lh);
  --adv-person-mini-role-color: var(--adv-color-body);
}
.adv-detail__rails--master .adv-detail__rail { gap: var(--adv-space-12); }
.adv-detail__rails--master .adv-section-label {
  margin-block-end: calc(var(--adv-space-26) - var(--adv-space-12));
}
.adv-detail__rails--master .adv-link-more {
  margin-block-start: calc(var(--adv-space-26) - var(--adv-space-12));
}
/* `.adv-empty` is a PAGE-level block — 40px of air above and below, sized for a
   grid that has nothing in it. Inside a 270px rail that reads as a paragraph
   that has come loose from its heading, so the padding goes and the column's
   own 26px gap places it. Same text, same component, right rhythm. */
.adv-detail__rail .adv-empty { padding: 0; }
/* Sibling-area rail — node 294:3792. 18/24 in the strongest ink, 26px apart.

   THE SIZE DOES NOT CHANGE BETWEEN STATES. The Figma component draws default at
   18px and both hover and selected at 16, which would shrink an item under the
   pointer and shift every row below it. That is a slip in the component, not an
   intention worth reproducing; the size holds and the states are carried by
   colour and weight, which is the interaction language everywhere else. */
.adv-detail__links { display: flex; flex-direction: column; gap: var(--adv-space-26); margin: 0; padding: 0; list-style: none; }
.adv-detail__links a {
  font-size: 18px;
  line-height: 24px;
  color: var(--adv-color-ink-strong);
  text-decoration: none;
}
.adv-detail__links a:hover { color: var(--adv-hover-accent); }
/* THE CURRENT ROW IS NAVY, not the grey the component transcription carries.
   `CompanyLaw` (294:3792) states `state=selected` as 16/500 in #51595F, and the
   FRAME's selected instance (294:3803) binds `corporate/navy` — so the two
   artefacts disagree and the frame wins, as everywhere else. It is also the
   token every other "selected" in this system already uses: the filter panel's
   chosen row and the category tag both take `--adv-active-text`. Grey made the
   current row the QUIETEST in the rail, which is backwards. */
.adv-detail__links [aria-current="page"] { color: var(--adv-active-text); font-weight: var(--adv-weight-medium); }
/* THE DETAIL RAIL AS DRAWN (294:3784, AD-138; the satellite's 343:11471 since AD-145):
   items 14/400 in text/secondary at the font's own line height (19 tall), the current
   row 16/500/25 navy (294:3803), 26 apart. `--frame` (it was `--master`): both tiers'
   detail templates emit it now; the 18/24 ink above is the unmodified component. */
.adv-detail__links--frame a {
  font-size: var(--adv-small-size);
  font-weight: var(--adv-weight-regular);
  line-height: normal;
  color: var(--adv-color-body);
}
.adv-detail__links--frame [aria-current="page"] {
  font-size: var(--adv-body-size);
  font-weight: var(--adv-weight-medium);
  line-height: var(--adv-body-lh);
  color: var(--adv-active-text);
}
/* THE ROW IS THE LINK (AD-172, ADR-0038 §AD-172 §2): the link's `::after` covers its row,
   the list item, across the column's width. Stretched rather than `display: block` on the
   link: on the area and service rails the row is the item's 25 line box around an inline
   link, and a block link would shrink it to its own 19 — the pitch 51 → 45. Out of the
   flow, the `::after` moves nothing; the 26 between rows stays a gap, and hover and focus
   stay the link's. */
.adv-detail__links--frame > li { position: relative; }
.adv-detail__links--frame a::after {
  content: "";
  position: absolute;
  inset: 0;
}
/* SPACE AROUND A COLOURED BAND IS THE NEIGHBOUR'S MARGIN, NOT ITS PADDING.
   `.adv-related` and `.adv-cta-band` are full-bleed painted surfaces; their own
   padding sits inside the colour, so on a detail page the biography ran
   straight into the grey plate and the two grey plates then met each other.
   The gap has to be page background, which means a margin on the join.

   Stated as adjacency rather than a blanket margin: after `.adv-listing` (which
   already carries a 96 bottom padding of its own) another 96 would be 192. */
/* WARM #F5F4F2 — the handoff sets `--adv-color-surface-alt` on the
   related-insights band (practice-area detail).

   THIRD COPY OF THE SAME RETIRED CLAIM (MD, 2026-09-07). This used to add
   "not the cool #F5F5F5 … the homepage's values band is the cool one; the two
   are one step apart and the design uses both". The values band binds
   `background/secondary` #F5F4F2 like this one (896:9785); the `surfaceCool`
   token was deleted on 2026-09-01, see tokens.css:56-62 and the note on
   `.adv-band--warm` above. */
.adv-related { background: var(--adv-color-surface-alt); padding-block: var(--adv-section-gap); }
.adv-related__inner {
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding-inline: var(--adv-section-pad-x);
}
/* THE GAP IS THE DEFAULT; THE EXCEPTIONS ARE LISTED.

   This was written the other way round — one selector per pair of neighbours —
   and it broke twice for the same reason: rename or add a wrapper and the rule
   silently stops matching, leaving a coloured plate hard against the content
   above it. `.adv-article-body` lost it when the article page was rebuilt, and
   `.adv-search-results` never had it at all.

   So a coloured band now claims its 96 from whatever precedes it, and the
   exception is the case where the gap already exists: after a wrapper whose own
   bottom padding is page background. `.adv-listing` and a PLAIN `.adv-band` are
   those; a `--cool` or `--warm` band is not, because its padding is painted.

   Getting this wrong now leaves 192px of air, which is obvious in review.
   Getting it wrong the old way left 0, which reads as a rendering bug. */
.adv-related,
.adv-cta-band { margin-block-start: var(--adv-section-gap); }

/* `--flow` IS ALSO NOT ONE OF THEM. The exception's premise is that the band
   above already paid the 96 out of its own bottom padding — which is exactly
   what `--flow` does not do (96 above, nothing below; see the rhythm note
   further up). Without this the master's About screen ran "our cooperation"
   straight into the closing band with no gap at all. */
.adv-listing + .adv-related,
.adv-listing + .adv-cta-band,
.adv-band:not(.adv-band--warm):not(.adv-band--flow) + .adv-related,
.adv-band:not(.adv-band--warm):not(.adv-band--flow) + .adv-cta-band { margin-block-start: 0; }

.adv-related__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--adv-space-24);
  margin-block-end: var(--adv-space-40);
}
/* THE TWO CHIP BANDS CLOSE THEIR HEAD AT 34, not 40 (1482:29877 and 1482:29892,
   AD-137): both heads are the 50px "View all" row, and both frames start the
   chips 34 below it — services 389 → 473, practice areas 1114 → 1198. The 40
   is every other head's and stays theirs. Same weight as the base and after
   it; the 560 block's 24 is later still and keeps the mobile head as it was.
   This is the 6px the services band measured over the frame (689 vs 683). */
.adv-related__head--switch { margin-block-end: var(--adv-space-34); }
/* AND THE OFFICES HEAD CLOSES AT 21 (1482:29929): its intro line starts 22 under
   the 50px head (2291 → 2313). 21, not 22 — the value `--top` below settled for
   the same button-to-copy distance from two readings a pixel apart, and one
   intent keeps one number. The 560 block's 24 still wins on phones. */
.adv-related__head--intro { margin-block-end: 21px; }
/* THE ARTICLE PAGE'S TWO LABELS ARE 29 TALL (422:6526, 492:4580 — AD-143): Figma's AUTO
   line (1.21) on the 24px label, where `--adv-label-lh` reads it as 1. The centre of the
   label does not move in the head row; what the extra 5 buys is the chips row under
   "Related practice areas" at the frame's +63 instead of +58. Since AD-145 the satellite's
   detail pages take the same band (and the areas label its `--auto` box) on all four. */
.adv-related--article .adv-section-label { line-height: var(--adv-small-lh); }

/* THE SECTION LINK'S TWO LABELS (partials/view-all.html, both tiers). The full
   string on desktop, a bare "View all" from the 402 step down — 597:19805 draws
   the same 52px text at x=330 in all three of its band heads, and the noun is
   already at x=20 on the same row. Only the visible half changes; the link's
   `aria-label` carries the full string at every width.

   Rendered rather than swapped by CSS content, because the four locales do not
   put the words in the same order and a stem-plus-tail split is not translatable
   — see the partial. The mobile half of this pair is in the 560 block. */
.adv-view-all__short { display: none; }

/* A band head whose button sits ON THE LABEL'S LINE, with the copy below both —
   About's team block (handoff: eyebrow at y=9, button at y=0, copy at y=72).

   A flex row cannot do this. `align-items: center` centres the button against
   the label AND the copy together, pushing it down half the copy's height;
   `flex-start` lines up the two boxes' TOP EDGES, and since the button is 50px
   tall against a 24px label, its text still lands ~13px low — which is the
   "button is below the heading" this replaces.

   So it is a grid: label and button share row 1 and are centred against each
   other, and the copy takes row 2 under the label. */
/* ROW GAP 21, not the stack's 26. Row 1 is the button's height (50) on both
   tiers, so the gap is measured from the button's box, not the label's: 896:9809
   runs the button 1448–1498 and starts the description at 1519. The handoff this
   modifier was first built from says the same thing one pixel apart — button at
   y=0..50, copy at y=72, i.e. 22 — so two independent readings agree that 26 is
   wrong and roughly 21 is right. Kept as ONE value rather than forked per screen:
   a 1px difference between two readings of one intent is not two decisions. */
.adv-related__head--top {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: var(--adv-space-24);
  row-gap: 21px;
}
/* The copy — third child, under the label rather than beside the button. */
.adv-related__head--top > :nth-child(3) { grid-column: 1; }
/* THE SATELLITE TEAM HEAD (1484:36533, AD-145): the lead is 660 (its copy is two lines
   there) and the cards start 34 under it — a documented literal, the frame's column. */
.adv-related__head--team { margin-block-end: var(--adv-space-34); }
/* About's team lead is three lines and its cards start 31 under it (1485:37575: the lead at
   +72, the cards at +178) — Home's two-line lead keeps the 34. */
.adv-band--team .adv-related__head--team { margin-block-end: 31px; }
.adv-related__lead { max-width: 660px; }

/* Below the breakpoint the base rule stacks the head with `flex-direction`,
   which a grid ignores — so the modifier needs its own one-column form or the
   button stays pinned beside the label on a phone. */
@media (max-width: 860px) {
  .adv-related__head--top { grid-template-columns: 1fr; row-gap: var(--adv-space-16); }
  .adv-related__head--top > :nth-child(3) { grid-row: 2; }
  .adv-related__head--top > :nth-child(2) { grid-row: 3; justify-self: start; }
}

/* THE SATELLITE EXPERT PAGE'S OWN PIECES — `__media`, `__aside`, `__meta`, `__headline`,
   `__identity`, `__name`, `__role`, `.adv-detail-section` — retired in AD-145: the page
   is the master's `.adv-expert-detail` since the 2026-09-16 round (ADR-0030 §7). */
/* `align-items: flex-start`, and it is not cosmetic. The body is a flex column,
   so a stretched child fills it — which turned "Discuss your case" into a
   full-width 619px button where the frame draws 193 (407:6974). Anything in
   this column that is not prose wants its own width. */
.adv-detail__body { display: flex; flex-direction: column; gap: var(--adv-space-34); align-items: flex-start; min-width: 0; }
/* Prose and headings still take the column; only self-sized things opt out. */
.adv-detail__body > :is(p, div, h1, h2, h3, ul, ol) { align-self: stretch; }

/* Meta group — a 14px label over its content. Used for contact details,
   languages, practice areas and services on the expert page. */
.adv-meta-group { display: flex; flex-direction: column; gap: var(--adv-space-12); }
.adv-meta-group__label {
  margin: 0;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-body);
}
.adv-meta-group__tags { display: flex; flex-wrap: wrap; gap: var(--adv-space-8); }
.adv-meta-group__value {
  margin: 0;
  font-size: var(--adv-small-size);
  line-height: 1;
  color: var(--adv-color-ink);
}

/* Contact rows — icon then value, 22–28px glyphs on a 40px pitch. */
.adv-contact-list { display: flex; flex-direction: column; gap: var(--adv-space-8); margin: 0; padding: 0; list-style: none; }
.adv-contact-list li { display: flex; align-items: center; gap: var(--adv-space-16); }
.adv-contact-list a,
.adv-contact-list span {
  font-size: var(--adv-small-size);
  line-height: 1;
  color: var(--adv-color-ink);
  text-decoration: none;
}
.adv-contact-list a:hover { color: var(--adv-hover-accent); }
.adv-icon--meta { width: 22px; height: 22px; color: var(--adv-color-ink); }

/* `.adv-timeline` (education as one 14/1 row, "degree, institution, years, 40px apart")
   retired in AD-145: both tiers draw `.adv-expert-education`'s rows. */

/* Article body — the one long-form column in the system. 720 of 1320, so
   the measure stays readable rather than running the container's width. */
/* THE ARTICLE COLUMN IS INDENTED, not centred and not full width: the title
   starts at x=390 and runs 990 wide, the body underneath is 660 — a 74ch
   measure inside a 1320 container (handoff, and Figma 385:3942 agrees).
   Expressed as a grid so the indent is a real column rather than a margin that
   has to be undone on every child. */
.adv-article-body {
  display: grid;
  grid-template-columns: 330px 1fr;
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding-inline: var(--adv-section-pad-x);
}
.adv-article-body > * { grid-column: 2; }
/* THE TITLE'S OWN MARGINS, BOTH READ OFF 422:6516 (AK, 2026-08-31). It was
   `0 0 120px`, which sat the title HARD against the breadcrumbs — measured 0 —
   and then left 120 under it where the frame leaves 26. The frame: crumbs
   380→405, title 450→660, the author card 686. So 45 above and 26 below.
   45 is not on the scale and 42 is the nearest step (the same call the featured
   band's 44→42 took: a token for a 3px difference is what rule 5 exists to
   prevent). 26 is exact. */
.adv-article__title {
  margin: var(--adv-space-42) 0 var(--adv-space-26);
  max-width: 990px;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-display-weight);
  font-size: var(--adv-display-size);
  line-height: var(--adv-display-lh);
  color: var(--adv-color-primary-dark);
}
.adv-article { max-width: 660px; }
/* The column's last paragraph must not spend its bottom margin on the gap to
   the next band: the band already claims a measured 96 and the two add up (112
   was measured before this rule).

   THE `.adv-prose` HALF WENT WITH AD-128, which lifted it to base.css as the
   unscoped `.adv-prose > :last-child` — the article was simply the first column
   to have prose, and now every one of them does. Keeping a second, identical
   declaration here would leave two rules asserting the same thing and an editor
   changing either one with no effect. `.adv-article > :last-child` is NOT
   redundant and stays: it governs the article's own children, which are not
   prose. (ADR-0023) */
.adv-article > :last-child { margin-block-end: 0; }
/* "RELATED LEGAL EXPERTS" BESIDE THE BODY (AD-153; ADR-0025 Amendment 22, ADR-0030
   Amendment 15). Neither article frame draws experts (422:6516, 385:3938): this is the
   practice-area page's column — 407:6990 on the master, 343:11471 on the firm sites —
   carried over with its own classes (`.adv-detail__rails …`), so its rows, label and
   402 tiles are that column's rules, not copies. Only its PLACE is new, and it goes in
   the 330 the 660 body leaves free at 1440: x 1110 → 1380, 270 wide (343:11491's row),
   the 60 to the body being what the 990 column leaves (990 − 660 − 270). Its top is
   level with the byline's because the two share grid row 2.

   THE GRID MODIFIER IS SET ONLY WHEN THE COLUMN RENDERS, so an article with nobody to
   list keeps the grid exactly as it was. The grid is as tall as the taller of body and
   column, so the next band keeps its measured 96 from whichever ends lower — on a
   summary-only article that is the column. Not sticky. One class on the column, so no
   `max-width` block below has a specificity trap to fall into (ADR-0021 §3). */
.adv-article-body--experts > .adv-article { grid-row: 2; }
.adv-article__experts {
  grid-row: 2;
  justify-self: end;
  align-self: start;
  width: 270px;
}
/* THE ARTICLE'S OWN COPY IS INK, not the prose default's `--adv-text-body`
   (AK, 2026-08-31). 422:6522 binds `text/main` #3C3C3C on the body column and
   `Body/regular_16px` — 16/25, which `.adv-prose :is(p, li)` already sets — so the size
   was right through the shared rule and only the colour steps up. Scoped to the
   article: long-form copy elsewhere on the site is `#51595F` and stays there;
   this is the one column that IS the page.

   `:is(p, li)` SINCE AD-128, and the widening is not a new decision. The rule
   above says the article's own COPY is ink; it was scoped to `p` because in
   August 2026 `p` was the only styled text a prose block could emit. AD-128
   gave `.adv-prose` a list mapping at `--adv-text-body`, and 116 firm article
   bodies under sites/ end in a bulleted list — leaving this selector on `p`
   alone would have turned every one of those lists a shade lighter than the
   paragraphs around it. `p` had become a stale proxy for "copy". (ADR-0023) */
.adv-article .adv-prose :is(p, li) { color: var(--adv-color-ink); }
/* Author on the left, date right-aligned on the same line, across the measure. */
.adv-article__byline {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--adv-space-24);
  margin-block-end: var(--adv-space-32);
}
.adv-article__date {
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
  text-align: end;
}
/* THE AUTHOR AS A PERSON (AD-143, 422:6524; the satellite's 385:4262 since AD-145): the
   portrait, the name 16/500/25 at the row's top + 7, and the second line 14/400 in ink 5
   under it — "Adverit ⟨City⟩" on the master, the author's role on the satellite —
   top-aligned on the 78 photograph. Bound through the row's own hooks, the same way
   `.adv-detail__rails--frame` binds them, so the 402 rules that set these properties
   directly still win there. The satellite keeps its 78 × 78 r12 portrait (the frame's
   78 × 80 r4 is a designer question). */
.adv-article__byline--person {
  --adv-person-mini-align: flex-start;
  --adv-person-mini-name-inset: 7px;
  --adv-person-mini-name-lh: var(--adv-body-lh);
  --adv-person-mini-name-color: var(--adv-color-ink);
  --adv-person-mini-role-size: var(--adv-small-size);
  --adv-person-mini-role-lh: var(--adv-small-lh);
  --adv-person-mini-role-color: var(--adv-color-ink);
}

/* THE ARTICLE BODY'S OWN RHYTHM (AD-143, 422:6522; ADR-0029 — both tiers' articles since
   AD-145, 385:3938, which widens ADR-0025 Amendment 8 H).
   The frame sets the firm's text at 16/25 with 16 between blocks and no gap between
   list items, and each section heading at 22/500 in burgundy on a 25 line, with one
   EMPTY 16/25 PARAGRAPH before it and one empty 25 line after it — so the heading
   sits 57 under the text above (16 + 25 + 16, the preceding margin collapsing into
   it) and 25 over the text below. Written as that arithmetic rather than as 57 and
   25, because that is what the frame draws. Every other `.adv-prose` — the practice-area
   and service bodies included — keeps base.css's 24 rhythm (ADR-0023): this is a modifier. */
.adv-prose--article {
  --adv-prose-line: calc(var(--adv-body-size) * var(--adv-body-lh));
}
.adv-prose--article > :is(p, ul, ol, blockquote, pre, table) { margin-block: 0 var(--adv-space-16); }
.adv-prose--article li + li { margin-block-start: 0; }
.adv-prose--article > :is(h2, h3, h4) {
  margin-block: calc(var(--adv-space-16) + var(--adv-prose-line) + var(--adv-space-16)) var(--adv-prose-line);
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-medium);
  line-height: var(--adv-prose-line);
  color: var(--adv-color-accent-burgundy);
}
.adv-prose--article > h2 { font-size: var(--adv-h3-size); }
/* A firm's lower heading levels have no frame: the same colour and weight, a step
   smaller, so the hierarchy survives without inventing a size. */
.adv-prose--article > :is(h3, h4) { font-size: var(--adv-h4-size); }
.adv-prose--article > :first-child { margin-block-start: 0; }
.adv-prose--article a { color: var(--adv-color-primary); }
.adv-prose--article a:hover { color: var(--adv-hover-accent); }
.adv-prose--article img {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: var(--adv-radius-card);
}
/* "Related practice areas" — 492:4580, and it is NOT part of the article column
   (AK, 2026-08-31). The row used to sit inside `.adv-article` between the
   byline and the body, indented to the 660 measure at x=390 and with its label
   hidden above the mobile step. The frame puts it at x=60 across the full 1320,
   labelled, AFTER the body: label 3927 (96 under the body's 3831), chips 3990
   (34 under the label), and 96 from the chips to the closing band. So it is a
   band in the page's own rhythm, not an aside in the reader's column — which is
   also why the mobile tier's `order` tricks are gone: the source order is the
   drawn order on both tiers now. */
.adv-article-areas {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-34);
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  margin-block-start: var(--adv-section-gap);
  padding-inline: var(--adv-section-pad-x);
}
.adv-article__meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--adv-space-12);
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-body);
}
.adv-article__meta a { color: var(--adv-color-primary); text-decoration: none; }
.adv-article__meta a:hover { color: var(--adv-hover-accent); }
/* `.adv-article__hero` WAS HERE and is gone with its one consumer (AK,
   2026-09-01): a 16:9 image across the article column, rendered from the
   article's `image`. 385:3938 draws no image on the insight detail — the byline
   ends at 766 and the body starts at 798, which is the 32 the two blocks are
   apart and no more. The field still feeds the 330px square on the insight card,
   which the listing frames do draw. */

/* ---------------------------------------------------------------------
   About page                                            node 336:10372
   --------------------------------------------------------------------- */

/* Four figures across the container. Each one IS a card — 307x100 on the warm
   surface with the standard hairline and 12px radius, the figure and its label
   centred side by side. An earlier pass set them bare on the page surface, which
   made the row read as loose text rather than as four tiles. */
.adv-stats {
  display: grid;
  grid-template-columns: var(--adv-stats-cols, repeat(4, 1fr));
  gap: 30px;
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding-inline: var(--adv-section-pad-x);
}
/* FOUR IS THE COUNT EVERYWHERE. There used to be an `--auto` variant here
   (`repeat(auto-fit, minmax(280px, 1fr))`) for the partner-firm page, whose row
   was built from whatever the record carried and so came out one to four tiles
   wide. That page now renders all four figures with zeros (AK, 2026-09-01), the
   variant had no other consumer, and a modifier kept for a case that no longer
   exists is how a stylesheet accumulates rules nobody dares delete. Restore it
   from git if a genuinely variable figures row ever turns up. */

/* ---------------------------------------------------------------------
   "Our story" — a dated timeline                        node 553:14136
   The date sits in its own right-aligned 97px column, burgundy 24/500 caps,
   with a hairline between entries. A description list, because that is what
   it is: a date and what happened on it.
   --------------------------------------------------------------------- */
/* RIGHT-ALIGNED IN THE CONTAINER, and that is the whole layout. The label and
   the intro sit at the page margin; the timeline's ENTRY column starts at the
   container's midpoint (x=719.5 of a 1320 container that begins at 60.5) and
   the date column hangs 152 to its left, ending at 664. So the grid is simply
   pushed to the right edge: 97 + 55 + 660 = 812, and 1320 - 812 = 508, which is
   where the frame puts the first date. Built as alignment rather than as a
   fixed offset so it survives a narrower container. */
.adv-story {
  display: grid;
  grid-template-columns: 97px minmax(0, 660px);
  column-gap: 55px;
  margin-inline-start: auto;
  align-self: flex-end;
  row-gap: var(--adv-space-26);
  align-items: start;
  margin: 0;
}
.adv-story__date {
  margin: 0;
  text-align: right;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-label-size);
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--adv-color-accent-burgundy);
  /* 6.5px down, so the date's cap-height lines up with the entry title rather
     than with the top of its line box. */
  padding-block-start: 6px;
}
.adv-story__entry { margin: 0 0 0 0; display: flex; flex-direction: column; gap: var(--adv-space-8); }
.adv-story__title {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-regular);
  font-size: 28px;
  line-height: 1.5;
  color: var(--adv-color-primary-dark);
}
.adv-story__text { margin: 0; font-size: var(--adv-body-size); line-height: var(--adv-body-lh); color: var(--adv-color-ink); }
/* The rule spans the ENTRY column only, not the date column — it separates
   what happened, not when. AFTER EVERY ENTRY, THE LAST INCLUDED (553:14162, AD-142):
   the template emits one per entry; the list used to have rules only between. */
.adv-story__rule { grid-column: 2; height: 1px; border: 0; margin: 0; background: var(--adv-color-border); }
/* THE DOT (553:14168…): a 4px burgundy disc centred under each date but the last, its
   foot on the entry's foot. Decoration, so a pseudo-element: the date cell stretches to
   its row and shrinks to its text, which puts `left: 50%` on the date's own centre. */
.adv-story__date { position: relative; align-self: stretch; justify-self: end; }
.adv-story__date:not(:last-of-type)::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 50%;
  width: 4px;
  height: 4px;
  margin-inline-start: -2px;
  border-radius: 50%;
  background: var(--adv-color-accent-burgundy);
}

/* ---------------------------------------------------------------------
   "What clients say" — a review pair                     node 430:8707
   Two 538-wide columns, each a row of 40px burgundy stars with the score
   beside it, the quote, and the attribution.
   --------------------------------------------------------------------- */
/* Two 538 columns whose left edges land on 0 and 660 of the container (430:9010 /
   430:9011) — i.e. the container's two halves, each column capped at 538. Written as
   halves (AD-142): the first reading, `space-between` on two 538 tracks, put the second
   column at 658 once the band's stack shrank the grid to its content, and at 842 when it
   did not — never at 720. `stretch` because the band's `.adv-stack` aligns to the start. */
.adv-reviews {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 660px));
  gap: var(--adv-space-60) 0;
  align-self: stretch;
}
.adv-review { display: flex; flex-direction: column; gap: var(--adv-space-26); align-items: flex-start; max-width: 538px; }
/* The stars and the score are ONE 4-gap row (430:8759) — the score takes no margin of
   its own; the <p> gives up its user-agent margins, which had put the quote 98 under the
   column top where the frame has 66 (40 + 26). */
.adv-review__rating { display: flex; gap: 4px; align-items: center; margin: 0; }
.adv-review__stars { display: flex; gap: 4px; color: var(--adv-color-accent-burgundy); }
.adv-icon--star,
.adv-review__stars svg { width: 40px; height: 40px; display: block; }
.adv-review__score { margin: 0; font-size: var(--adv-body-size); line-height: var(--adv-body-lh); color: var(--adv-color-ink); }
.adv-review__quote { margin: 0; font-size: var(--adv-body-size); line-height: var(--adv-body-lh); color: var(--adv-color-ink); }
/* 16/25 Medium (430:8770): the attribution sits 26 under the quote on a 25 line box. */
.adv-review__cite {
  margin: 0;
  font-style: normal;
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
/* THE HEAD CLOSES AT 26, NOT 40 (430:8707): the columns open 76 under the head's top —
   the 50 button row plus the band stack's own 26 — so the head adds nothing. A modifier
   (0,1,0), not `:has(~ .adv-reviews)`: the 560 block's `.adv-related__head` 24 must still
   win on phones (ADR-0021 §3). */
.adv-related__head--reviews { margin-block-end: 0; align-self: stretch; }
/* THE GAP BELOW THE FIGURES HAS TO BE A MARGIN, not the next band's padding.
   Figma has the stats row at y=436..536 and the approach band opening at y=632
   — a 96px gap (`Frame 173`, node 336:10372). A band's own `padding-block` sits
   INSIDE its background, so when a coloured band follows this row the 96 is
   there but painted, and the grey plate ends up flush against the tiles.
   Between two plain bands the same padding is transparent and looks right,
   which is why this only shows up here.

   Scoped with `:has()` to the coloured neighbours: after a plain band the
   padding already reads as space, and adding a margin there would double it. */
.adv-stats:has(+ .adv-band--warm) { margin-block-end: var(--adv-section-gap); }
/* THE MASTER'S FOUR TILES GIVE BELOW 1440 (AD-140, TD-21). `repeat(4, 1fr)`
   cannot go under the tiles' one-line content, and at 861 the Dutch, French and
   German pairs ("200+ Behandelde dossiers") summed past the row. The tracks may
   shrink now, and a tile too narrow for its pair puts the value over the label,
   centred (the ≤860 tile's own alignment). At 1440 every pair fits on one line
   and nothing wraps. */
.adv-stats--fluid {
  --adv-stats-cols: repeat(4, minmax(0, 1fr));
  --adv-stat-wrap: wrap;
}
.adv-stats--fluid .adv-stat { text-align: center; }
/* THREE TILES ON THE MASTER'S HOME AND ABOUT (AD-168, ADR-0025 Amendment 23): Offices · Lawyers ·
   Practice areas, "Matters handled" gone (1482:29916, 1482:33824 — 3 × 419.3 on the 1318 row, 30
   apart; ours are 420 on 1320, the four-tile row's same half pixel). A modifier on those two rows
   only: the office page and the satellite's About keep four. Declared after `--fluid` at the same
   weight, so it wins the property that one sets; no ≤1100 rule restates it, and the ≤860 block's
   own two columns still win below 861, where the third tile takes the whole second row. */
.adv-stats--three { --adv-stats-cols: repeat(3, minmax(0, 1fr)); }

/* THE INLINE PADDING IS 24, NOT THE FRAME'S 50 (1482:29916, AD-137). The frame
   pads each 307 tile 30/50, which leaves a 207 content box — and its own
   "200+ Matters handled" pair is 240 wide, centred at x=33.5, i.e. the frame
   overflows its padding. CSS does not: at 50 (or the 40 this used to carry) the
   label wraps to two lines. 24 leaves 259, so every pair the row draws stays on
   one line; narrower pairs are centred either way, so the other screens that
   use the tile (About on both tiers, the firm page) do not move. */
.adv-stat {
  display: flex;
  flex-wrap: var(--adv-stat-wrap, nowrap);
  align-items: center;
  justify-content: center;
  gap: 14px;
  min-height: 100px;
  padding: 30px var(--adv-space-24);
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-card);
  background: var(--adv-color-surface-alt);
}
.adv-stat__value {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h1-size);
  line-height: 1;
  color: var(--adv-color-primary-dark);
}
/* WHILE IT IS COUNTING ONLY. The master homepage's figures count up on first
   scroll into view (site.js, authored — the file has no prototype motion), and
   proportional figures change width as the digits roll, so the number twitches
   left and right on its way up. Tabular figures hold one width. Scoped to the
   attribute the script sets and removes, so the number at rest keeps the
   proportional figures the design draws — the animation borrows the change, it
   does not keep it. */
.adv-stat__value[data-counting] { font-variant-numeric: tabular-nums; }

/* Navy and Medium, matching the figure — not body ink. The label is part of the
   figure, not a caption under it. */
.adv-stat__label {
  margin: 0;
  max-width: 130px;
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: 1;
  color: var(--adv-color-primary-dark);
}

/* ---------------------------------------------------------------------
   "Our approach" rows — About only.
   Close to the homepage's `.adv-value` rows and deliberately NOT the same
   component: this one splits 600 / 550 with a 60px gap (the homepage is
   5:6 with a 330 text column), its number badge takes the neutral hairline
   rather than a burgundy one, its title is navy, and its rule runs the full
   width instead of starting level with the title. Four differences is a
   different component, not a variant.
   --------------------------------------------------------------------- */
.adv-approach { display: flex; flex-direction: column; gap: var(--adv-stack-gap); width: 100%; }
.adv-approach__row {
  display: grid;
  /* 600 + 60 + 660, NOT `600fr 550fr`. The frame's row is 1320 with the name
     column at 0..600 and the copy at 660..1210 (336:10875) — the copy starts at
     the container's MIDPOINT and its 550 is the text's own measure inside a 660
     column, not the column. As `600fr 550fr` the two share 1260 in a 600:550
     ratio, which starts the copy at 777 — 57 right of where it is drawn. */
  grid-template-columns: minmax(0, 600px) minmax(0, 660px);
  gap: var(--adv-space-60);
  align-items: center;
}
.adv-approach__head { position: relative; display: flex; align-items: center; gap: 22px; }
.adv-approach__num {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-pill);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: 1;
  color: var(--adv-color-accent-burgundy);
}
.adv-approach__title {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-semibold);
  font-size: var(--adv-h1-size);
  line-height: 1;
  color: var(--adv-color-primary-dark);
}
/* 550 OF TEXT IN A 660 COLUMN. The column is set by the row's grid above (the
   copy starts at the container midpoint); this is the copy's own measure inside
   it, which the frame states separately — 336:10875 is x=660 w=550 against a
   column that runs to 660, and its three siblings match.
   Without it the copy takes the whole column, each step wraps wherever its own
   sentence happens to run out, and the rows stop being the frame's uniform 50. */
.adv-approach__text {
  margin: 0;
  max-width: var(--adv-sat-measure);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
/* Full width and the standard border colour — the homepage's `.adv-rule` is a
   lighter hairline inset by 60px, which is its own band's rule, not this one. */
.adv-approach__rule { height: 1px; border: 0; margin: 0; background: var(--adv-color-border); }
/* 660 SINCE THE 2026-09-16 ROUND (1485:37549, AD-145): the text runs the whole column now,
   as the master's `.adv-values--wide` records for its own rows. Scoped, because
   `--adv-sat-measure` has other readers. */
.adv-approach--wide .adv-approach__text { max-width: 660px; }

/* Offices — the list on the left, the map on the right, both 660 of 1320. */
/* 600 + 60 + 660 again: 336:10961 puts the map at x=720, the container's
   midpoint, with the office list at x=60 and only 530 wide. `1fr 1fr` on a 60
   gap starts the map at 750. */
.adv-offices { display: grid; grid-template-columns: minmax(0, 600px) minmax(0, 660px); gap: var(--adv-space-60); align-items: start; }
/* 530 OF LIST IN A 600 COLUMN — a measure, not the column, the same distinction
   `.adv-approach__text` records. (`--adv-sat-hero-measure` used to be cited here
   as the second example and no longer can be: AD-132 widened it to 600, which IS
   the h1's column, so the hero is now the counter-example rather than the
   parallel. Its own note says so.) Frame 142 is x=60
   w=530 in both tiers' frames (336:10975, 281:2532) while the grid column beside
   the 660 map runs to 600. Uncapped, "Adverit compliance GmbH & Co. KG" at 38px
   sets on one line where the frame wraps it, and the VAT line runs 70px past
   where it is drawn. The 34 gap is the frame's too: entries at y=0, 292, 395
   against heights 258, 69. */
.adv-offices__list { display: flex; flex-direction: column; gap: var(--adv-space-34); max-width: 530px; }
/* The head row carries the band's 60 to its content. It held two 402-only controls
   ("View as list" and the popup's ×) until AD-149 retired the popup; it is the
   label's row at every width now, and stays an element because it is what carries
   that gap down to the map. */
.adv-offices__head { margin-block-end: var(--adv-space-60); }

/* NO MAP → NO EMPTY HALF. Until a firm has a static-map key or commits its own
   map image the square is not rendered at all, so the two-column grid would
   leave the right half blank and the entries stranded in a narrow strip. The
   list becomes the whole row and flows into columns of its own width instead —
   which is what a list of three or four offices wants anyway.

   `:has()` rather than a modifier class on the wrapper: whether there is a map
   is decided inside partials/offices-map.html, and passing that decision back
   out to the parent template means two places that can disagree about it. */
.adv-offices:not(:has(.adv-offices__map)) { grid-template-columns: 1fr; }
.adv-offices:not(:has(.adv-offices__map)) .adv-offices__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 400px));
  gap: var(--adv-space-60) var(--adv-card-gap);
  /* The 530 measure below is a measure INSIDE the 600 column. With no map there
     is no column — the list owns the full 1320 and lays out as cards — so the cap
     has to come off or it would strand them all in the left 530. */
  max-width: none;
}
.adv-offices__map {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--adv-radius-card);
  display: block;
}

/* ── THE MASTER'S OFFICE ACCORDION (1482:33862, AD-138 — ADR-0025 §5) ──────────
   The live satellites, one row each, beside our own map. A 610 list and the 660
   square, the map on the container's midpoint as before: 610 + 660 leaves 50 of
   the 1320, and `space-between` puts all of it in the gap.

   ITS OWN ELEMENTS, NOT `.adv-office-entry`. That block is one frame on two
   tiers (the satellite About draws it), and its 38px name is set through a
   `:has()` rule a modifier on the entry cannot outrank — so the rows below are
   `.adv-offices__row*`, and the satellite's entry does not move. */
/* The rows start 63 under the label's top (1482:33863 → 1482:33864); the label's
   box is 24 here, so 39 of it is the head row's margin. */
.adv-band--map .adv-offices__head { margin-block-end: 39px; }
.adv-offices--accordion {
  grid-template-columns: minmax(0, 610px) minmax(0, 660px);
  column-gap: var(--adv-space-26);
  justify-content: space-between;
}
/* 26 between rows, a full-width rule in the middle of it (1482:33864: row 0–236,
   rule 262, next row 288). */
.adv-offices--accordion .adv-offices__list { gap: var(--adv-space-26); max-width: 610px; }
/* No map: the list keeps its column and stays a list — the card grid above is
   the satellite's no-map layout, not an accordion's. */
.adv-offices--accordion:not(:has(.adv-offices__map)) .adv-offices__list { display: flex; max-width: 610px; }
.adv-offices__row { display: flex; flex-direction: column; }
/* THE OPEN ROW CARRIES A BLUE BAR AGAIN — AND ONLY THE BAR (MD, 2026-09-20, AD-149 QA;
   ADR-0030 Amendment 12, reversing half of that ADR's Amendment 7 §1). That amendment
   took away both the `--adv-active-surface` plate and this bar on 2026-09-17, leaving
   "open" to be read from the panel showing and the title going navy. It holds while a
   panel has something in it — and a firm that publishes no contact details opens to ONE
   line, so a place of four read as one office answering and three ignoring. The plate
   stays gone: it was the heavier half, and the bar alone says which rows answered.

   A PSEUDO-ELEMENT, SO NOTHING MOVES: it reaches 16 past the row on every side instead
   of padding it, and the row's own box — the frame's 26 rhythm and the rules between
   rows — is unchanged. A row under a rule starts 10 below it (26 − 16), so the bar never
   covers the rule, and the next row's rule sits clear of it.

   `data-active` is written by site.js and never by the markup, so with no script every
   row is open and none is marked. At ≤860 there is no row to mark (AD-149). */
.adv-offices__row[data-active] { position: relative; }
.adv-offices__row[data-active]::before {
  content: "";
  position: absolute;
  inset: calc(var(--adv-space-16) * -1);
  border-inline-start: var(--adv-space-4) solid var(--adv-color-primary);
  pointer-events: none;
}
.adv-offices__row:where(:not([hidden])) ~ .adv-offices__row[data-active]::before {
  inset-block-start: calc(var(--adv-space-26) - var(--adv-space-16));
}
/* BETWEEN VISIBLE ROWS ONLY (AD-142). The Offices listing hides rows with `hidden`, and
   `+` still counts a hidden sibling — the first visible row after a filtered one would
   carry a rule above it. `:where()` keeps the specificity of the old `+` form (0,2,0) and
   About (no hidden rows) computes the same. That parity used to matter twice over: the
   ≤860 rules restyled a row into a card and had to outrank this. Since AD-149 there is
   no row at ≤860 at all, so only the `~`/`+` reason is left. */
.adv-offices__row:where(:not([hidden])) ~ .adv-offices__row:where(:not([hidden])) {
  padding-block-start: var(--adv-space-26);
  border-block-start: var(--adv-border);
}
/* THE HEAD ROW (1482:33868): the name left, "Visit local website ↗" right, 27
   tall. The name is the disclosure's button — 22/500, navy while its row is open
   (1482:33869) and body ink while closed (1482:33881). */
.adv-offices__row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--adv-space-26);
}
/* Flex, so the button's own 27 line box is the title's — an inline button would
   sit on the h3's inherited 25px strut and make the row 28.

   `min-width: 0` because a flex item will not shrink below its content by default,
   and this one holds an office name of any length: without it the name pushes
   "Visit local website ↗" out of the row instead of wrapping (AD-147, the ≤860
   card; on desktop the longest live name is 299 of a 600 column, so nothing moves
   there today — it is the same defect waiting for a longer one). */
.adv-offices__row-title { display: flex; min-width: 0; margin: 0; font: inherit; }
.adv-offices__row-toggle {
  padding: 0;
  border: 0;
  background: none;
  text-align: start;
  cursor: pointer;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-h3-size);
  line-height: var(--adv-h3-lh);
  color: var(--adv-color-ink);
}
.adv-offices__row-toggle[aria-expanded="true"] { color: var(--adv-color-primary-dark); }
.adv-offices__row-toggle:hover { color: var(--adv-hover-accent); }
/* Two offices in one city: the firm's name, a step quieter than the office's. The country
   beside the name ("Adverit Antwerp, Belgium", AD-200, ADR-0025 Amendment 25 §2) takes the
   same step. */
.adv-offices__row-country,
.adv-offices__row-firm { font-weight: var(--adv-weight-regular); color: var(--adv-color-body); }
/* 16/500 corporate blue with the 8px arrow 10 after it (1482:33870). */
.adv-offices__row-link {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  gap: 10px;
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-primary);
  text-decoration: none;
  white-space: nowrap;
}
.adv-offices__row-link:hover { text-decoration: underline; }
/* THE PANEL: kind and place straight under the name, then the lines, then the
   hours, 14 apart (1482:33866: 77 → 91, 197 → 211 — a documented literal, the
   scale has no 14). Lines 2 apart, the e-mail underlined (1482:33876). All 16/25
   body ink. `hidden` is the closed state (base.css), so there is no height to
   animate and reduced motion needs nothing of its own. */
.adv-offices__row-panel { display: flex; flex-direction: column; gap: 14px; }
.adv-offices__row-id,
.adv-offices__row-lines,
.adv-offices__row-hours {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
.adv-offices__row-id p { margin: 0; }
.adv-offices__row-lines { display: flex; flex-direction: column; gap: 2px; }
.adv-offices__row-lines a { color: inherit; text-decoration: none; }
.adv-offices__row-lines .adv-offices__row-mail { text-decoration: underline; }

/* ── THE MAP WITH HTML PINS (1482:33891, ADR-0025 §4–5) ──────────────────────────
   Mode 2 of partials/offices-map.html: a pin-free base, and one button per office
   placed in PERCENT of the square (`--x`/`--y`, computed at build time), so the
   pins scale with it. The surface under the image is what shows while it loads. */
.adv-map {
  position: relative;
  overflow: hidden;
  background: var(--adv-color-surface-alt);
}
/* THE WINDOW, THE SCROLLER AND THE CANVAS (1605:21967, AD-149 — ADR-0025 Amendment 19).
   `.adv-map` is the WINDOW onto the square; `.adv-map__canvas` IS the square, and every
   mark and the name pill are its children, because `--x`/`--y` are percentages of
   whichever positioned box holds them. Above 860 the canvas is exactly the window and
   the desktop composition does not move — these two are inert boxes there.

   THE SCROLLER IS ABSOLUTE, not `width/height: 100%`. `.adv-map`'s height comes from
   `aspect-ratio` on a definite width, and `inset: 0` gives the scroller a definite box
   without asking whether a percentage height resolves against an aspect-ratio'd one. It
   also keeps the card overlay OUT of the scrolled content, which is the point: the card
   is pinned to the window's foot while the map travels under it. */
.adv-map__scroller { position: absolute; inset: 0; }
.adv-map__canvas { position: relative; width: 100%; height: 100%; }
/* The reduced-motion answer for the lift is NOT here. It has to outrank
   `.adv-band--map .adv-map__canvas` (0,2,0), which is where the transition is
   declared, so a bare `.adv-map__canvas` at this weight would lose whatever its
   order — it lives after the 860 block instead, as `(max-width: 860px) and
   (prefers-reduced-motion: reduce)`. */
/* The card and the selector are a ≤860 composition and nothing else — the frame is a
   402 frame and no desktop frame was redrawn (MD, 2026-09-20). Declared off here and
   built in the 860 block, the shape `.adv-offices__toggle` had before it. One rule, not
   two: the card and the selector never appear apart. */
.adv-map__overlay { display: none; }
.adv-map__base { display: block; width: 100%; height: 100%; object-fit: cover; }
/* OUR OWN BASE, INLINED (AD-142 follow-up, ADR-0025 Amendment 6). `img/map-base.svg` is
   Natural Earth drawn at the recorded bounds by scripts/map/build-base-map.mjs, and it
   carries no colour of its own — these three rules are its whole palette, all existing
   tokens: pale-blue water, the warm card surface for land (one step off the page, so the
   square keeps its edge where land meets it), and the default hairline for the land
   borders. No coastline stroke — the file draws only the borders two countries share.
   `non-scaling-stroke`: the drawing is 1320 in a 660 box, and a border is 1px on screen. */
.adv-map__base--vector svg { display: block; width: 100%; height: 100%; }
.adv-map__sea { fill: var(--adv-color-surface-blue); }
.adv-map__land { fill: var(--adv-color-surface-alt); }
.adv-map__borders {
  fill: none;
  stroke: var(--adv-color-border);
  stroke-width: var(--adv-border-width);
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.adv-map__pin,
.adv-map__cluster {
  position: absolute;
  left: var(--x);
  top: var(--y);
  padding: 0;
  border: 0;
  cursor: pointer;
}
/* 26 x 32, TIP ON THE POINT. Idle is text/secondary (1482:33895), the open row's
   pin is corporate blue (1482:33898). */
.adv-map__pin {
  width: 26px;
  height: 32px;
  background: none;
  color: var(--adv-color-body);
  transform: translate(-50%, -100%);
}
.adv-map__pin[data-active] { color: var(--adv-color-primary); }
/* ADVERIT'S OWN HEAD OFFICE (the satellite marked in the console, ADR-0054) — navy while it is
   not the open one, so it reads as neither an idle office nor the selected one; `[data-active]`
   above outranks it. */
.adv-map__pin--head { color: var(--adv-color-primary-dark); }
/* THE OPEN OFFICE'S NAME ON THE MAP (MD, 2026-09-17; ADR-0025 Amendment 7) — the selection
   feedback no frame draws, so it is ours and listed for the designer. A pill in the active
   pin's blue with a tail pointing at the mark. site.js places it: `--x`/`--y` are the
   mark's, `--lift` clears the mark (a pin stands on its point, a bubble is centred on it),
   `--dx` keeps the pill inside the square, and `data-below` flips it under the mark near
   the top edge. Not a control — the pointer passes through to the pins under it. */
.adv-map__label {
  position: absolute;
  left: var(--x);
  top: var(--y);
  z-index: 1;
  padding: var(--adv-space-4) var(--adv-space-16);
  border-radius: var(--adv-radius-pill);
  background: var(--adv-color-primary);
  color: var(--adv-color-on-navy);
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  white-space: nowrap;
  pointer-events: none;
  transform: translate(calc(-50% + var(--dx, 0px)), calc(-100% - var(--lift, 0px)));
}
.adv-map__label::after {
  content: "";
  position: absolute;
  top: 100%;
  left: calc(50% - var(--dx, 0px));
  border: var(--adv-space-8) solid transparent;
  border-block-end: 0;
  border-block-start-color: var(--adv-color-primary);
  transform: translateX(-50%);
}
.adv-map__label[data-below] { transform: translate(calc(-50% + var(--dx, 0px)), var(--lift, 0px)); }
.adv-map__label[data-below]::after {
  top: auto;
  bottom: 100%;
  border-block-start: 0;
  border-block-end: var(--adv-space-8) solid var(--adv-color-primary);
}
.adv-icon--map-pin { display: block; width: 100%; height: 100%; overflow: visible; }
.adv-icon--map-pin .adv-icon__ring { stroke: var(--adv-color-surface); }
.adv-icon--map-pin .adv-icon__dot { fill: var(--adv-color-surface); }
/* The frame's drop shadow (y 2, blur 2.25, 25% black) as an unblurred halo:
   12% stands in for 25% spread by the blur. A documented literal — the pin is an
   icon, and no elevation token applies (ADR-0025 §4). */
.adv-icon--map-pin .adv-icon__halo { fill: var(--adv-color-black); opacity: 0.12; }
/* THE COUNT BUBBLE (1482:33893): a 31-tall pill, 16 inline, on the members'
   centre. It takes the ACTIVE BORDER when one of its offices is the open row —
   the frame's pins cannot show that for an office they no longer draw. */
.adv-map__cluster {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  height: 31px;
  padding-inline: var(--adv-space-16);
  border: var(--adv-border);
  border-radius: var(--adv-radius-pill);
  background: var(--adv-color-surface-alt);
  font-family: var(--adv-font-body);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
  transform: translate(-50%, -50%);
}
.adv-map__cluster[data-active] { border-color: var(--adv-color-primary); }
/* An office entry is three stacked blocks 26px apart: the identity (name, kind,
   place), the contact lines (7px apart), and the opening hours. Everything below
   the name is 16/1.5 body ink.

   BOTH TIERS, ONE FRAME. 336:10959 (satellite About) and 282:2548 (master "our
   cooperation") are the same block down to the copy and every coordinate — same
   530 list, same 660 map at x=720, same three entries. So this is corrected in
   the shared base rather than scoped, and neither tier can drift from it. */
.adv-office-entry { display: flex; flex-direction: column; gap: var(--adv-space-26); align-items: flex-start; }
/* FLUSH BY DEFAULT, 2px ONLY ON THE ADDRESSED ENTRY. The affiliate entries stack
   their three lines with no gap at all — Frame 139 is 69 tall against 27 + 25 +
   17 = 69 — while the office proper takes 2 between each (Frame 138 is 92 against
   46 + 25 + 17 = 88, and the 4 left over is two 2s). */
.adv-office-entry__id { display: flex; flex-direction: column; gap: 0; }
.adv-office-entry:has(.adv-office-entry__lines > *) .adv-office-entry__id { gap: 2px; }
/* THE NAME IS 22 OR 38, AND WHICH ONE IS DECIDED BY THE ENTRY, NOT ITS POSITION.
   The frame sets "Adverit Antwerp" in a 46px line box and both "Adverit
   compliance GmbH & Co. KG" lines in a 27px one — 38 x 1.21 and 22 x 1.21. The
   difference is not emphasis on whichever office comes first: it separates the
   office you can walk into and telephone from an affiliate that is named and
   placed and nothing more.

   Hence `:has(… > *)` and not `:first-child`. A firm with three real addressed
   branches gets three full-size entries, which is right; `:first-child` would
   shrink its second and third for no reason the design ever gave. The `> *`
   matters too — it tests for CONTENT, so an empty lines div (which is what the
   satellite emitted until today) cannot promote an affiliate to 38.

   The comment here used to say an earlier pass had "set the name at 38px
   semibold and the lines at 14px, which made each office read as a section
   heading with fine print under it", and dropped everything to 22. Half of that
   was right: 38 is the frame's size, but only for the one entry that earns it,
   and the lines are 14 (`--adv-body-size` is 16 and they measure 17 = 14 x 1.21
   — left alone here, it is its own reading).

   AND THE LINE HEIGHT IS AUTO. `line-height: 1` was the sixth instance of Figma's
   `leading: normal` transcribed as the number 1. At 1 the boxes are 22 and 38
   against the frame's 27 and 46, which is what made the 2px question above
   unanswerable — a 5px error in the line box swamps it. At 1.21 both land. */
.adv-office-entry__name {
  margin: 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-h3-size);
  line-height: var(--adv-h3-lh);
  color: var(--adv-color-primary-dark);
}
.adv-office-entry:has(.adv-office-entry__lines > *) .adv-office-entry__name {
  font-size: var(--adv-h1-size);   /* 38 — same AUTO 1.21 as --adv-h3-lh */
}
/* `kind` and `hours` are the 16px body — 25px boxes in the frame (336:10979,
   336:10986) and 25 here. These two were always right. */
.adv-office-entry__kind,
.adv-office-entry__hours { margin: 0; font-size: var(--adv-body-size); line-height: var(--adv-body-lh); color: var(--adv-color-ink); }
/* THE PLACE AND THE CONTACT LINES ARE 14, NOT 16 — split out of the rule above.
   Every one of these nodes measures 17 tall: "Belgium, Antwerp" (336:10980),
   "Germany, Hamburg" (336:10990) and all four contact rows (336:10982..85). 17
   is 14 x 1.21, which is the exact case the note beside `--adv-small-size`
   already spells out ("a 14px node 17px"). At 16/1.5625 each was 25, and the
   error compounded: 8px in the identity block, 32 across the four contact rows,
   so the Antwerp entry rendered 298 against the frame's 258.
   This is the other half of the reverted pass the `__name` note above describes
   — it set the lines at 14 and was right about that too.

   `place` and `lines` are one declaration because they are one type style; they
   stay separate SELECTORS from `kind`/`hours` because those are a different one
   and merging them is how they came to share a size in the first place. */
.adv-office-entry__place { margin: 0; font-size: var(--adv-small-size); line-height: var(--adv-small-lh); color: var(--adv-color-ink); }
.adv-office-entry__lines {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: 0;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-ink);
}
.adv-office-entry__lines a { color: inherit; text-decoration: none; }
.adv-office-entry__lines a:hover { color: var(--adv-hover-accent); }
/* The e-mail is underlined at rest, in ink (1485:37536 — the master's office rows do the
   same, `.adv-offices__row-mail`). */
.adv-office-entry__lines a.adv-office-entry__mail { text-decoration: underline; }

/* ONE BLOCK PER OFFICE (1485:37523, AD-145 — ADR-0030 §6). The label sits on its AUTO box
   (29, `.adv-section-label--auto`) and the blocks start 63 under its top. Each block is a
   550 × 403 photograph at x=60 and the office's lines at x=721, 659 wide — 111 between
   the two is the frame's, a documented literal (the details start a pixel past the
   container's midpoint). A second office stacks 60 under the first (ours: the frame
   draws one). The photograph is a plate at the card radius, the office's own or the
   firm's neutral render. */
.adv-band--office .adv-section-label { margin-block-end: var(--adv-space-34); }
.adv-office-blocks { display: flex; flex-direction: column; gap: var(--adv-space-60); }
.adv-office-block {
  display: grid;
  grid-template-columns: minmax(0, 550px) minmax(0, 659px);
  column-gap: 111px;
  align-items: start;
}
.adv-office-block__photo {
  aspect-ratio: 550 / 403;
  border-radius: var(--adv-radius-card);
  background-size: cover;
  background-position: center;
}
/* The name is SEMIBOLD in this frame (1485:37530, 38/600 navy, 530 wide) — the old
   list's 500 was 336:10975's. `.adv-office-entry` has had no other consumer since the
   master moved to its own accordion rows (AD-142). */
.adv-office-block .adv-office-entry__name { max-width: 530px; font-weight: var(--adv-weight-semibold); }

/* ---------------------------------------------------------------------
   Vacancy card                                          node 589:17246
   400x247 on the warm card surface with the light ring, radius 12, 26 of
   padding. Three blocks pinned apart: the title (28/1.5 REGULAR in ink — the
   quietest large heading in the system, and the design's own call) in a
   two-line 84 box, the office in blue over its country, and the
   level/type tags with the posting's age at the right (AD-143).
   --------------------------------------------------------------------- */
.adv-vacancy-card {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  /* 12: 26 + 84 + 12 + 50 + 12 + 37 + 26 is the frame's 247 exactly (589:17206 — the
     office line at 122, the tags at 184). The 402 row restates its own 16. */
  gap: var(--adv-space-12);
  min-height: 247px;
  padding: var(--adv-space-26);
  border-radius: var(--adv-radius-card);
  background: var(--adv-color-surface-alt);
  box-shadow: inset 0 0 0 var(--adv-border-width) var(--adv-color-border);
  color: inherit;
  text-decoration: none;
}
.adv-vacancy-card__title {
  margin: 0;
  max-width: 348px;
  /* Two lines, whatever the title — the frame's 84 box (589:17207), so a one-line
     title leaves the office line where every other card has it. */
  min-height: 3em;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-regular);
  font-size: 28px;
  line-height: 1.5;
  color: var(--adv-color-ink);
}
.adv-vacancy-card__info { display: flex; flex-direction: column; }
.adv-vacancy-card__meta {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
/* "Adverit ⟨City⟩" in `corporate/blue` (589:17208) — on the landing too (K9). */
.adv-vacancy-card__office { color: var(--adv-color-primary); }
/* TWO DATE SLOTS, ONE PER TIER. This note used to say the desktop card carries no
   date; the 2026-09-16 frame draws "2 days ago" at the right of the tags
   (589:17246, 14 in text/secondary — AD-143 K8). The meta line's slot is the 402
   row's (760:12646) and is hidden here; the foot's is hidden there. */
.adv-vacancy-card__posted { display: none; }
.adv-vacancy-card__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--adv-space-8);
}
.adv-vacancy-card__tags { display: flex; flex-wrap: wrap; gap: var(--adv-space-8); }
.adv-vacancy-card__age {
  flex-shrink: 0;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-body);
  white-space: nowrap;
}

/* ---------------------------------------------------------------------
   Careers detail                          nodes 589:17473 / 760:13351
   The desktop composition is `.adv-job-layout` (above); these are its
   parts: the posted/deadline pair (Navigation/regular_14px, label in
   secondary over the value in ink), the bullet lists and the arrow link.
   The hiring office is the kit's compact row (`.adv-job-office`); the
   partner-firm plate that stood here (80px, the 4px radius) left with the
   firm in AD-143. Everything else is the kit.
   --------------------------------------------------------------------- */
.adv-job-meta {
  display: flex;
  justify-content: space-between;
  gap: var(--adv-space-16);
  margin-block-start: var(--adv-space-24);
}
.adv-job-meta__label { margin: 0; font-size: 14px; line-height: normal; color: var(--adv-color-body); }
.adv-job-meta__value { margin: 4px 0 0; font-size: 14px; line-height: normal; color: var(--adv-color-ink); }
.adv-job-tags { margin-block-start: var(--adv-space-24); }
.adv-job-list {
  margin: 0;
  padding-inline-start: var(--adv-space-24);
  display: flex;
  flex-direction: column;
  /* NO GAP between the items (AD-143, 597:19454 — six bullets in seven 25 lines);
     the 402 tier keeps its 8. */
  gap: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-text-body);
}
.adv-arrow-link {
  display: inline-flex;
  align-items: center;
  gap: var(--adv-space-8);
  font-size: 18px;
  line-height: 25px;
  font-weight: var(--adv-weight-medium);
  color: var(--adv-color-primary-dark);
  text-decoration: none;
}
.adv-arrow-link:hover { text-decoration: underline; }
/* "View Adverit ⟨City⟩ ↗" (597:19486, AD-143): 16/500/25 in blue, 10 to the arrow — the
   offices accordion's "Visit local website ↗" in the same role. */
.adv-arrow-link--office {
  gap: 10px;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-primary);
}
.adv-icon--link { width: 9px; height: 9px; }
.adv-icon--corner { width: 14px; height: 14px; }   /* the expanded card's corner arrow (664:25949) */
/* Space above the body blocks; the head pays its own 54 on mobile. */
.adv-job-detail { margin-block-start: 54px; }

/* ---------------------------------------------------------------------
   Contact form                                          node 553:12683
   Pill fields on the page surface, 60px tall like every other control in
   the system; the message box is the one exception at 170px.
   --------------------------------------------------------------------- */
/* 54 between the field stack and the button; 26 between the fields. */
/* The enquiry layout — form left, a 660x851 photograph right (385:5183). Same
   split the contact screen uses one tier down; named here because the join page
   is the master's only form. */
/* TWO 660 COLUMNS THAT MEET. The frame's form frame measures 710 because that
   is its bounding box, but the photograph starts at exactly 660 (385:5183) —
   so the columns are halves of the 1320 container with no gutter between them,
   and the form's own fields (600, from `.adv-field`) provide the breathing room
   inside the left one. Sized as a 710 column with a 60 gap, the two together
   overflowed 1320 and both shrank. */
.adv-form-split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 660px));
  justify-content: space-between;
  gap: 0;
  align-items: start;
}
/* THE FORM TAKES ITS COLUMN. `.adv-stack` is `align-items: flex-start`, which
   is right where it stacks headings and buttons and wrong here: it shrink-wraps
   the <form>, so `.adv-field`'s `width: 100%` resolved against a content-sized
   parent and every input collapsed to its default ~170px. The column is 660 and
   the fields cap themselves at 600; nothing else needs measuring. */
.adv-form-split > .adv-stack { align-items: stretch; }
.adv-form-split__media {
  border-radius: var(--adv-radius-card);
  background-size: cover;
  background-position: center;
  min-height: 600px;
  align-self: stretch;
}
.adv-form { display: flex; flex-direction: column; gap: 54px; align-items: flex-start; }
/* THE FIELDS OPEN 54 UNDER THE LEAD (385:5079 ends 1699, the first group opens 1753 —
   AD-142), the same 54 the form keeps above its button; the column's stack gives 26, so
   the form adds the rest. The ≤860 block takes it back off. */
.adv-form-split .adv-form { margin-block-start: calc(54px - var(--adv-stack-gap)); }
.adv-form__fields { display: flex; flex-direction: column; gap: var(--adv-space-26); align-items: flex-start; width: 100%; }
/* 8 BETWEEN LABEL AND FIELD, not 12 (AK, 2026-09-02). Every group on 553:12683
   is 85 tall — label 17, field 60 — and 85 - 77 leaves 8. At 12 each group ran
   91 and the four of them pushed the consent line, the button and the whole
   photograph 24px down the page. */
.adv-field { display: flex; flex-direction: column; gap: var(--adv-space-8); width: 100%; max-width: 600px; }
/* THE REQUIRED MARK IS RED, and it is a mark rather than punctuation: `abbr`
   with a title, so a screen reader says "required" instead of "asterisk" while
   the input's own `required` carries the semantics. `--adv-status-danger-fg` is
   the system's existing red (ADR-0007), not a new one — this is the only place
   on the public sites that needed it, the rest of the status palette being the
   Operator Console's. */
.adv-field__req {
  color: var(--adv-status-danger-fg);
  text-decoration: none;
  cursor: help;
}
.adv-field__label {
  padding-inline-start: var(--adv-space-26);
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-body);
}
.adv-field input,
.adv-field select,
.adv-field textarea {
  width: 100%;
  min-height: 60px;
  padding: 0 var(--adv-space-26);
  border: var(--adv-border-width) solid var(--adv-color-border);
  /* CARD RADIUS, NOT A PILL. Every other control in the system is a pill —
     buttons, filters, tags, the search field — and the enquiry form is the one
     place the design rounds to 12 instead. A 60px-tall pill next to a 145px
     message box does not read as the same family, which is presumably why. */
  border-radius: var(--adv-radius-card);
  background: var(--adv-color-surface);
  color: var(--adv-color-ink);
  font-family: var(--adv-font-body);
  font-size: var(--adv-small-size);
  /* NOT `line-height: 60px` (AK, 2026-09-02). A 60px line box inside a
     border-box element with a 1px edge on each side makes the control 62 tall,
     against the drawn 60 — the min-height never bound because the content
     already exceeded it. An input centres its own text vertically in whatever
     height it is given, so the line box only has to be smaller than the box. */
  line-height: var(--adv-small-lh);
}
/* A textarea is the one field that is not a pill — a 170px-tall pill reads as
   a mistake, and the design draws it with the card radius. */
.adv-field textarea {
  /* 170, THE DRAWN HEIGHT (AK, 2026-09-02). At 120 the floor never bound —
     `rows="4"` plus 40 of padding already came to 130 — so the message box
     rendered 40 short of Group 164's 170 and every one of the design's
     proportions below it moved up. */
  min-height: 170px;
  padding-block: 20px;
  line-height: var(--adv-body-lh);
  resize: vertical;
}
/* ONE EDGE, AND THE FOCUS FILL (AK, 2026-08-31; the fill redrawn AD-143). This
   drew a detached focus ring OUTSIDE the field's own recoloured border — two
   concentric rings around every focused input, which is what AK saw, and it
   appeared nowhere in the design. The edge is the active blue; the fill WAS the
   active light blue (#D0DEEC) until 560:15756 drew the focused field as a
   near-white #F2F4F5 — its own token, because a focused field is not a selected
   chip (ADR-0028 §8). Every form on both tiers takes it.

   STILL AN ACCESSIBLE FOCUS INDICATOR: the border changes hue AND the fill
   changes, which is a larger visual delta than the ring it replaces — the ring
   was decoration on top of a state the field was already expressing twice. */
.adv-field input:focus,
.adv-field select:focus,
.adv-field textarea:focus {
  outline: none;
  border-color: var(--adv-field-focus-edge);
  background: var(--adv-field-focus-surface);
}
/* THE ERROR STATE (560:15874, AD-143): burgundy edge, warm fill, the message
   under the field. KEYED TO `aria-invalid` ONLY, which the form script sets after
   a field is left or a submit is tried — never to `:invalid` / `:user-invalid`.
   The satellite's form has no script and no `novalidate`, so a native
   pseudo-class would paint its untouched required fields red; the attribute
   never appears there. An invalid field keeps this look while focused: the
   message beside it is still true until the value changes. */
.adv-field [aria-invalid="true"],
.adv-field [aria-invalid="true"]:focus {
  border-color: var(--adv-field-error-edge);
  background: var(--adv-field-error-surface);
}
/* 7 UNDER THE FIELD, at the label's inset: the group grows from 85 to 109
   (17 + 8 + 60 + 7 + 17). The field group's gap is 8, hence the -1. */
.adv-field__error {
  margin: -1px 0 0;
  padding-inline-start: var(--adv-space-26);
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-field-error-text);
}
/* Every required mark turns burgundy while the form shows an error (560:15874
   draws the email's mark burgundy beside the invalid name). The script sets
   the modifier; at rest the mark keeps the danger red. */
.adv-form--invalid .adv-field__req { color: var(--adv-field-error-text); }
.adv-field ::placeholder { color: var(--adv-color-body); }
.adv-consent {
  display: flex;
  align-items: flex-start;
  gap: var(--adv-space-12);
  font-size: var(--adv-small-size);
  line-height: 1;
  color: var(--adv-color-body);
}
/* A 17px square with the card family's small radius, on the warm surface — the
   native control is replaced rather than tinted, because `accent-color` cannot
   give it a border or a 4px radius. 17 and not the tickbox's 19: 385:5165 is
   17x17, and the two controls are drawn at different sizes in their own frames.
   */
.adv-consent input {
  appearance: none;
  width: 17px;
  height: 17px;
  margin: 0;
  flex-shrink: 0;
  border: var(--adv-border-width) solid var(--adv-color-border);
  border-radius: var(--adv-radius-xs);
  background: var(--adv-color-surface-alt);
  cursor: pointer;
}
/* CHECKED IS THE FILTER PANEL'S TICKBOX ON THE FORM'S ACTIVE FILL (AK,
   2026-08-31) — a navy edge and a filled navy square, the 529:12257 treatment,
   but the ring between them is the ACTIVE SURFACE rather than the page's, so
   the box reads as filled light blue like every other active control in this
   form. Nothing in the design contradicts it: 385:5165 draws the box in its
   RESTING state only, so the checked look is a call rather than a transcription,
   and the call is to match the field beside it.

   Same two-shadow construction as `.adv-tick`; 3px in from a 17px box leaves an
   11px core where the 19px box leaves 13. */
.adv-consent input:checked {
  border-color: var(--adv-color-primary-dark);
  background: var(--adv-color-primary-dark);
  box-shadow: inset 0 0 0 3px var(--adv-active-surface);
}
.adv-consent input:focus-visible {
  outline: var(--adv-focus-ring-width) solid var(--adv-focus-ring);
  outline-offset: var(--adv-focus-ring-offset);
}
.adv-consent a { color: var(--adv-color-primary); }
/* The consent line's own mark appears only in the error state (560:15874 prefixes
   the line with a burgundy "* "); at rest the line carries none. The span also
   carries the screen-reader text the script fills. */
.adv-consent__req { display: none; color: var(--adv-field-error-text); }
.adv-consent--error .adv-consent__req { display: inline; }

/* A FORM-LEVEL MESSAGE — a send that failed, or a no-JS submit the server sent
   back (AD-143). Undrawn (listed for the designer), so it is built from the
   status palette the console already uses: the danger trio, the card radius. */
.adv-form-banner {
  width: 100%;
  max-width: 600px;
  padding: var(--adv-space-16) var(--adv-space-26);
  border: var(--adv-border-width) solid var(--adv-status-danger-border);
  border-radius: var(--adv-radius-card);
  background: var(--adv-status-danger-bg);
  color: var(--adv-status-danger-fg);
  font-size: var(--adv-small-size);
  line-height: var(--adv-body-lh);
}

/* ── THE APPLICATION FORM (AD-167, ADR-0037 §11) ─────────────────────────────
   A posting's "Apply" band on both tiers — 1681:27795 (master, filled),
   1643:22321 (satellite), 1734:33300 (submitted) — built from the enquiry
   form's field, consent, banner and button, and ONE new component, the upload
   box (`.adv-upload`). NO NEW TOKEN: every colour below is an existing one;
   the few lengths the scale lacks are the frame's, named where they appear.

   THE UPLOAD BOX (1681:27875): a label 8 above a 600 x 95 box — radius 12, the
   field's surface, a DASHED border 6 on / 6 off in the light border colour.
   The box grows with its chips (157 with two, 12 apart). Its button is the
   outlined `.adv-btn--secondary`, 50 tall ("Choose file" 141, "Add more
   files" 165). Without the script the native file input sits where the
   button goes; with it the input is hidden and the chips appear. Its error
   state is the field's (`--adv-field-error-surface` / `-edge`), its message
   the field's `.adv-field__error` under the box.

   THE DASH IS A MASK, NOT `border-style: dashed` (Trap 13). Browsers draw a
   1px CSS dash at their own length, never the frame's 6/6. An SVG draws it
   exactly, but a data-URI SVG cannot read a custom property — its stroke would
   be a hex written here. So the SVG is only a MASK (its black is alpha, not a
   colour) on a pseudo-element whose fill IS the token, and the error state
   swaps the fill. The rect's `rx` is 12 because `--adv-radius-card` is: the
   one number the URI has to repeat. Stroke 2, centred on the edge, so the
   box's own clip leaves the inner 1px. */
.adv-upload {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-8);
  width: 100%;
  max-width: 600px;
}
.adv-upload__box {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--adv-space-24);
  /* 95 AT REST (1681:27877): 23 above the 50 of a chip or a button and 22 below it,
     the frame's own insets (157 with two chips) — the scale has neither. */
  min-height: 95px;
  padding: 23px var(--adv-space-26) 22px;
  border-radius: var(--adv-radius-card);
  background: var(--adv-color-surface);
}
.adv-upload__box::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--adv-color-border);
  pointer-events: none;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' rx='12' ry='12' fill='none' stroke='black' stroke-width='2' stroke-dasharray='6 6'/%3E%3C/svg%3E") 0 0 / 100% 100% no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' rx='12' ry='12' fill='none' stroke='black' stroke-width='2' stroke-dasharray='6 6'/%3E%3C/svg%3E") 0 0 / 100% 100% no-repeat;
}
.adv-upload__box--error { background: var(--adv-field-error-surface); }
.adv-upload__box--error::before { background: var(--adv-field-error-edge); }
/* Two 14px lines on the body's 25 (1681:27889): what to add, then the rule. */
.adv-upload__empty { min-width: 0; }
.adv-upload__empty p {
  margin: 0;
  font-size: var(--adv-small-size);
  line-height: calc(var(--adv-body-size) * var(--adv-body-lh));
  color: var(--adv-color-body);
}
.adv-upload__empty[hidden],
.adv-upload__chips[hidden],
.adv-upload__choose[hidden] { display: none; }
/* THE CHIPS stack 12 apart (1681:27995); each is 50 tall on the warm surface,
   the name 16 in from the left, the 10 x 10 cross 16 in from the right. */
.adv-upload__chips {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--adv-space-12);
  min-width: 0;
}
.adv-upload__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--adv-space-8);
  max-width: 100%;
  height: 50px;
  padding-inline: var(--adv-space-16) var(--adv-space-8);
  border-radius: var(--adv-radius-card);
  background: var(--adv-color-surface-alt);
  font-size: var(--adv-small-size);
  line-height: calc(var(--adv-body-size) * var(--adv-body-lh));
  color: var(--adv-color-body);
}
.adv-upload__name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The cross is 10 x 10; its button is a 24 target around it, which the chip's
   8 of right padding and the 7 around the glyph put 16 from the chip's edge. */
.adv-upload__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: var(--adv-radius-pill);
  background: transparent;
  color: var(--adv-color-ink);
  cursor: pointer;
}
.adv-upload__remove:hover { color: var(--adv-hover-accent); }
.adv-upload__remove:focus-visible,
.adv-upload__choose:focus-visible {
  outline: var(--adv-focus-ring-width) solid var(--adv-focus-ring);
  outline-offset: var(--adv-focus-ring-offset);
}
.adv-upload__choose { flex-shrink: 0; }
/* WITH THE SCRIPT the native input leaves the layout (it still opens from its
   label and from "Choose file"); WITHOUT it, it is the control, in the box. */
.adv-upload__input {
  max-width: 50%;
  font-family: var(--adv-font-body);
  font-size: var(--adv-small-size);
  color: var(--adv-color-body);
}
.adv-upload--enhanced .adv-upload__input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  opacity: 0;
}

/* THE FORM BAND sits on the vacancy page's own grid (`.adv-job-layout`), so it
   starts on the copy column at x=390 as the frame draws it, and collapses with
   the page below 561. The grid's own head spacing is the page's, not the band's —
   at every width, hence the doubled class over the 560 block's `.adv-job-layout`. */
.adv-job-layout.adv-apply__layout {
  padding-block-start: 0;
  row-gap: 0;
}
/* THE LAST BAND BEFORE THE FOOTER, so it keeps the rhythm below it too: `--flow` gives
   the gap above only, and the footer follows (1734:33300: 93 under the button, read as
   the 96; 34 on the phone tier, where the token itself steps down). */
.adv-apply,
.adv-apply-done { padding-block-end: var(--adv-section-gap); }
/* ANCHOR TARGETS CLEAR THE STICKY HEADER: "Apply now" jumps to `#apply`, a no-JS 303 to
   `#application-submitted` or a refusal's banner — as the switcher panels do. */
.adv-apply,
.adv-apply-done,
.adv-apply .adv-form-banner--target { scroll-margin-top: calc(var(--adv-nav-h) + var(--adv-border-width)); }
.adv-apply__col {
  grid-column: 3 / -1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
}
/* THE HEAD (1681:27845): "Apply for ⟨title⟩" 38/600, the office line 12 under
   it, the intro 26 under that; the fields open 34 below. */
.adv-apply__title { color: var(--adv-color-ink); }
.adv-apply__place {
  margin: var(--adv-space-12) 0 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
.adv-apply__office { color: var(--adv-color-primary); }
.adv-apply__intro {
  margin-block-start: var(--adv-space-26);
  max-width: 617px;
}
.adv-apply__col > .adv-form-banner { margin-block-start: var(--adv-space-26); }
.adv-apply__col > .adv-form-banner[hidden] { display: none; }
.adv-apply__form {
  width: 100%;
  max-width: 600px;
  margin-block-start: var(--adv-space-34);
}
/* Two 290 fields and the frame's 20 gutter (1681:27852) — the scale has no 20. */
.adv-apply__pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
  width: 100%;
  max-width: 600px;
}
.adv-apply__help {
  max-width: 600px;
  color: var(--adv-color-body);
}
/* THE CONSENT'S MARK SHOWS AT REST here (1681:27899 draws "* I consent…" in the
   danger red); the enquiry form shows it only in the error state. */
.adv-apply .adv-consent__req { display: inline; color: var(--adv-status-danger-fg); }
.adv-apply .adv-form--invalid .adv-consent__req,
.adv-apply .adv-consent--error .adv-consent__req { color: var(--adv-field-error-text); }

/* "APPLICATION SUBMITTED" (1734:33300): 58/700 navy, the thanks 54 under it, the
   outlined "View other vacancies" 24 under that. Hidden until a no-JS 303
   targets it (`:target`) or the script shows it; either way the form band after
   it goes. */
.adv-apply-done { display: none; }
.adv-apply-done:target,
.adv-apply-done--shown { display: block; }
.adv-apply-done:target ~ .adv-apply { display: none; }
.adv-apply__col--done > .adv-band__text {
  margin-block-start: 54px;
  max-width: 617px;
}
.adv-apply__col--done > .adv-btn { margin-block-start: var(--adv-space-24); }
.adv-apply__col--done > h2:focus { outline: none; }

/* Split with a tall image on the left and content on the right — the contact
   screen (553:12718, 550x650). Mirror of `.adv-cta-split`, which puts its
   image on the right; both exist in the design. */
/* TWO ROWS, and the heading only occupies the first of them. The photograph
   starts at y=402 and the form at y=377 — they run together and end together,
   while the title sits above the form alone. A single row with `align-items:
   start` lifted the photo up beside the heading instead. */
/* THE MIDPOINT GRID, NOT `fr` (AK, 2026-09-02). This read `550fr 720fr`, and
   `fr` distributes FREE SPACE rather than sizing a track: on the 1320 container
   with a 60 gap it split the remaining 1260 in that ratio and put the right
   column at x=666, where 553:12683 puts everything in it — heading, lede and
   form alike — at x=720. The same mistake as `.adv-approach__row` (600fr 550fr)
   and `.adv-detail` (610fr 619fr); third time in this pass.

   720 is the container's MIDPOINT, so this is the split the rest of the tier
   already uses: 600 + 60 + 660. The frame's own boxes are narrower than their
   tracks — the photograph is 550 of the 600 and the form 600 of the 660 — so
   the widths sit on the elements, where the frame draws them, and the grid
   stays the one shape every other split on the site uses. */
.adv-split-media {
  display: grid;
  grid-template-columns: minmax(0, 600px) minmax(0, 660px);
  grid-template-rows: auto 1fr;
  /* TWO GAPS, NOT ONE. 60 between the columns is the container's own split; 26
     between the lede and the form is the head's own rhythm, the same 26 that
     separates the title from the lede above it and one field group from the
     next below it. One value for both put every row of the form — and the
     photograph beside it — a uniform 35 too low: the lede ends at 351 and
     553:12687 starts at 377. */
  gap: var(--adv-space-26) var(--adv-space-60);
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  /* 34 ABOVE, from the crumbs (AK, 2026-09-02). This opened with the section
     gap, putting the h1 at y=246 where the frame has 183: 553:12716 ends at 149
     and the title starts at 183. Contact is not a section following another
     section — it is a page head following its own breadcrumbs, and the 34 is
     the same one every listing puts between them.
     THE FOOT IS 127 (AD-145, ADR-0030): the section gap plus the 31 the frame
     adds under the button (553:12683) — the master's pattern for its own 141
     (`--master` below). It used to stop at the gap alone. */
  padding: var(--adv-space-34) var(--adv-section-pad-x) calc(var(--adv-section-gap) + 31px);
}
.adv-split-media__head { grid-column: 2; grid-row: 1; display: flex; flex-direction: column; gap: var(--adv-space-26); }
/* THE LEDE IS 581, AS DRAWN (553:12715; AD-145, ADR-0030). It used to take the
   tier's 550 and refuse "a second measure for one text node"; the master's
   Contact shipped 581 (`--master` below) and the round draws it on both tiers. */
.adv-split-media__head .adv-page-head__lead { max-width: 581px; }
.adv-split-media__media {
  grid-column: 1;
  grid-row: 2;
  align-self: stretch;
  /* 550 OF THE 600 TRACK — 553:12718 is drawn 550x650 and the comment above this
     block has said so since it was written; the element simply took the whole
     column. */
  max-width: 550px;
  /* THE PHOTOGRAPH STARTS AT THE FIRST INPUT, NOT AT THE FORM (AK, 2026-09-02).
     The frame numbers were already recorded above — photo 402, form 377 — and
     the code put both at the top of row 2, which is 377 for each. The 25 between
     them is exactly the first field's label and the 8 under it, so it is written
     as that rather than as a magic number: change the label's size and the photo
     follows the field it is aligned to.

     It also makes the height fall out on its own. Row 2 is 675 tall (571 of
     fields + 54 + a 50 button), and 675 - 25 = 650, the drawn height, with
     `stretch` doing the work. `min-height` stays as a floor for a firm whose
     form is somehow shorter. */
  margin-block-start: calc(var(--adv-small-size) * var(--adv-small-lh) + var(--adv-space-8));
  min-height: 650px;
  border-radius: var(--adv-radius-card);
  background-size: cover;
  background-position: center;
}
/* 600 of the 660 track — Frame 182 is 600 wide at x=720 and its fields are the
   same 600, which `.adv-field` already caps at. Stated here too so the prose
   above a form (`.adv-prose`) shares the form's measure instead of running the
   full column. */
.adv-split-media__body { grid-column: 2; grid-row: 2; display: flex; flex-direction: column; gap: var(--adv-space-32); max-width: 600px; }

/* ---------------------------------------------------------------------
   MASTER CONTACT (AD-143, ADR-0028) — 498:4380 generic, 435:10926 expert,
   581:16126 / 578:16014 their thank-yous. The satellite's split, re-measured:
   the title at 700 (the token's own since ADR-0030 §4), a 16/25 lead at 581 (600 beside a person), 34 from the lead
   to the form (the satellite's 26), and 141 from the form to the footer.
   --------------------------------------------------------------------- */
.adv-split-media--master {
  row-gap: var(--adv-space-34);
  padding-block-end: calc(var(--adv-section-gap) + 45px);
}
.adv-split-media--master .adv-page-head__lead {
  max-width: 581px;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
}
.adv-split-media--expert .adv-page-head__lead { max-width: 600px; }
/* The person in the left column, level with the title (435:10926: the 330 portrait
   at 183, the name 15 under it at 28/400/1.5, then the two 25 lines 8 and 4 apart —
   `.adv-expert-identity` already spaces those). */
.adv-contact__person { grid-column: 1; grid-row: 1 / span 2; align-self: start; }
.adv-expert-photo--contact { width: 330px; }
.adv-contact__person-name {
  margin: 15px 0 0;
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-regular);
  font-size: var(--adv-h2-size);
  line-height: var(--adv-h2-lh);
  color: var(--adv-color-ink);
}
.adv-contact__person-name a { color: inherit; text-decoration: none; }
/* The name is a `p` too, so the identity block's `:first-of-type` 8 lands on it rather
   than on the first role line; restated for the line under the name. */
.adv-contact__person-name + .adv-expert-role { margin-block-start: var(--adv-space-8); }
.adv-contact__person-name a:hover { color: var(--adv-hover-accent); }

/* A no-JS submit the API refused lands on `#enquiry-error`: the page is static, so
   the fragment is the only state it can read. */
.adv-form-banner--target { display: none; }
.adv-form-banner--target:target { display: block; }
/* The honeypot: in the form, never on the screen or in the tab order. */
.adv-enquiry__trap {
  position: absolute;
  inset-inline-start: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* THE THANK-YOU, IN PLACE (C7). The trail stays; the head and the form go. On the
   generic page the photograph shortens to 309 at y=245 (96 under the trail) and the
   text starts 35 into it at the right column (581:16126); beside a person the text
   starts 92 under the title's old top (578:16014). The 550x309 is its own crop, so
   the default 550x650 plate is simply hidden rather than squashed. */
.adv-contact__photo--sent,
.adv-contact__success[hidden] { display: none; }
.adv-contact__success {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-26);
  max-width: 660px;
}
.adv-contact__success-title { margin: 0; max-width: 553px; }
.adv-contact__success-text {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-ink);
}
.adv-contact--sent { padding-block: var(--adv-section-gap) calc(var(--adv-section-gap) + 61px); }
.adv-contact--sent .adv-split-media__head,
.adv-contact--sent .adv-split-media__body,
.adv-contact--sent .adv-contact__photo:not(.adv-contact__photo--sent) { display: none; }
.adv-contact--sent .adv-contact__photo--sent {
  display: block;
  grid-row: 1;
  align-self: start;
  margin-block-start: 0;
  min-height: 309px;
}
.adv-contact--sent .adv-contact__success { margin-block-start: 35px; }
/* One row once the form has gone: the second track would still spend the 34 row gap. */
.adv-contact--sent:not(.adv-contact--expert) { grid-template-rows: auto; }
.adv-contact--expert.adv-contact--sent { padding-block: var(--adv-space-34) 79px; }
.adv-contact--expert.adv-contact--sent .adv-contact__success { margin-block-start: 92px; }

/* =====================================================================
   SEARCH RESULTS                                        node 553:13398
   ---------------------------------------------------------------------
   A different screen from the search entry page, and a different shape
   from every listing: a filter rail on the left, and results GROUPED BY
   KIND on the right — experts, practice areas, services, insights — each
   with its own count and its own "view all". Cards are the compact 475
   family the design system has carried unused since AD-73: `.adv-media-card`
   for a person or an article, `.adv-topic-card` for an area or a service.
   ===================================================================== */

.adv-search-results {
  display: grid;
  grid-template-columns: 258px 1fr;
  gap: 72px;
  align-items: start;
  max-width: var(--adv-container-outer);
  margin-inline: auto;
  padding-inline: var(--adv-section-pad-x);
}
.adv-search-results__rail { display: flex; flex-direction: column; gap: var(--adv-space-16); }
.adv-search-results__rail .adv-section-label { margin-block-end: var(--adv-rail-label-mb, var(--adv-space-26)); }
/* The results column, and the groups inside it — two names, because they were
   one and the same class nested in itself, which reads as a typo and behaves
   as one the moment either needs its own rule. */
.adv-search-results__col { display: flex; flex-direction: column; gap: var(--adv-space-40); min-width: 0; }
.adv-search-results__main { display: flex; flex-direction: column; gap: var(--adv-section-gap); min-width: 0; }

/* The rail's controls are 258x60 boxes with the CARD radius, not the pill the
   listing filters use — the one place a filter is square-ish in this system. */
/* THE SEARCH RAIL'S PILL CENTRES ITS LABEL (AK, 2026-09-01). It was
   `space-between`, which is what a full-width control usually wants — and it is
   wrong here: the pill stretches to the rail's 258 while its label stays as
   short as "City", so the word sat hard left and the caret hard right with 150px
   of nothing between them, five times down the column.

   419:4948 centres the label and the caret AS A PAIR — measured across all five
   rows of the frame, the pair's midpoint lands on the box's, and the caret keeps
   the base pill's own 6px gap after the word rather than being pinned to an
   edge. So the fix is to stop overriding `.adv-filter`'s `center`, not to add an
   alignment: the base was already right and this modifier took it away.

   Worth knowing for the next reader: the pill's COMPUTED `text-align` already
   said `center`, which is why this looked fixed from the inspector. It is
   inherited, and it could not have helped — the label is a flex item sized to
   its content, so there is no spare line box for it to centre within. The
   alignment that governs here is the flex container's. */
.adv-filter--box {
  width: 100%;
  border-radius: var(--adv-radius-card);
}

/* Group head: label, count beneath it, and an optional "view all" on the right. */
/* THE GROUP HEAD'S THREE OFFSETS READ CUSTOM PROPERTIES (AD-142), whose fallbacks are
   the values these rules always had — so the satellite computes exactly as before, and
   the master's `.adv-search-results--frame` sets the frame's: 419:2901 puts the count 41
   under the label's top, "View all" 5 down, and the cards 92 under the label. */
.adv-result-group { display: flex; flex-direction: column; gap: var(--adv-result-group-gap, var(--adv-space-26)); }
.adv-result-group__head {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: start;
  gap: var(--adv-space-16);
}
.adv-result-group__count {
  margin: var(--adv-result-count-mt, var(--adv-space-16)) 0 0;
  grid-column: 1;
  font-size: var(--adv-small-size);
  line-height: 1;
  color: var(--adv-color-body);
}
.adv-result-group__all {
  grid-row: 1;
  grid-column: 2;
  margin-block-start: var(--adv-result-all-mt, 0);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-nav-size);
  line-height: var(--adv-nav-lh);
  color: var(--adv-color-primary);
  text-decoration: none;
}
.adv-result-group__all:hover { color: var(--adv-hover-accent); }
/* THE MASTER'S VALUES (419:2901, AD-142). Our label box is 24 where the frame's is 29,
   so: the count's 14 box at 42 (24 + the head's 16 + 2), "View all" 3 down (its centre 3
   under the label's, as drawn), and the cards 36 under the count's foot (42 + 14 + 36 =
   92). The ≤860 block restores the fallbacks. */
.adv-search-results--frame {
  --adv-result-count-mt: 2px;
  --adv-result-all-mt: 3px;
  --adv-result-group-gap: 36px;
  /* The facets 63 under the rail label's top (419:4947 → 419:4948): 24 + 23 + the rail's 16. */
  --adv-rail-label-mb: 23px;
  /* THE CARD TRACKS GIVE (TD-23). A fixed 475 track is wider than the results column from
     861 to 924 (the column is the viewport less 450), so the cards ran past it and, at
     861–864, past the page. `minmax(0, 475px)` keeps the count `auto-fill` computes from
     the 475 maximum — two at 990, one below 1030 — and lets a lone track shrink to the
     column; the card's own `max-width: 100%` follows. The ≤860 block's one-column rule is a
     plain declaration and still wins. */
  --adv-result-cards-cols: repeat(auto-fill, minmax(0, 475px));
}
/* THE ROW AND ONE KIND'S HEAD CLOSE AT 34 (419:2901: chips 477–514, groups 548; 419:4558:
   count, then the chips 34 under it, the cards 34 under those) where the column's 40 is
   the pager's. The chips row also sits 4 above the rail's label, centred on it (the
   frame's label box is 29). Restated in the ≤860 block. */
.adv-controls-row--frame { margin-block-end: -6px; }
.adv-search-kind-head[hidden] + .adv-controls-row--frame { margin-block-start: -4px; }
/* The satellite draws no single-kind head (AD-145), so its row has no such sibling: the
   chip icon's hidden holder is what precedes it. Same 4 above FILTERS. */
.adv-search-results--sat [data-chip-icon] + .adv-controls-row--frame { margin-block-start: -4px; }
/* THE SATELLITE'S EXPERT CARD IS 168 (553:13398), the drawn rail — ours was 170: the
   card's two border pixels around a 168 rail and a 168 body. Both give the border back:
   the rail 166 inside it, and the text 33 inside it, which is the frame's 34 from the
   card's edge. The ≤560 row card restates its own rail height. */
.adv-search-results--sat {
  --adv-media-card-pad-y: 33px;
  --adv-media-card-rail-h: 166px;
}
.adv-search-kind-head { margin-block-end: -6px; }
/* The expert card's office line in the primary blue (419:4113) — the class exists only
   where the master's template opts in (`data-search-office-line`). */
.adv-media-card--office .adv-media-card__meta { color: var(--adv-color-primary); }

/* Cards wrap at their own 475 width with a 40 gutter — two to a 990 column. */
/* A GRID, NOT A WRAPPING FLEX ROW (AK, 2026-09-02) — because the cards in a row
   must be as tall as the tallest, and this was the one card container in the
   system that was not.

   Measured on /search/?q=law: the two service results came out 212 and 187, a
   25px step that is exactly one line of snippet — one card's summary wraps to
   two lines and the other's does not. The row is what the reader sees, so the
   shorter card read as a rendering fault rather than as a shorter summary.

   AND THE FLEX ROW WOULD NOT EQUALISE THEM. `align-items: stretch` on the
   container, `align-self: stretch` on the items and `height: 100%` on the cards
   all left it at 212/187; only changing the container's formatting context did.
   So this is the structure being wrong rather than a declaration missing, and
   the structure it should have had all along is the one every other card row in
   this system uses — `.adv-grid` is `grid` with `grid-auto-rows: 1fr`, and the
   listing grids got exactly this treatment for exactly this reason.

   `repeat(auto-fill, 475px)` keeps the drawn column: 475 + 40 + 475 = 990, the
   results column exactly (553:13439 draws the pair at 0 and 515 of 990). The
   `> *` width stays, so the mobile override at the ≤402 step — which restates
   `display: flex` for the sideways rails and the stacked rows — still governs
   there untouched. */
.adv-result-cards {
  display: grid;
  grid-template-columns: var(--adv-result-cards-cols, repeat(auto-fill, 475px));
  grid-auto-rows: 1fr;
  align-items: stretch;
  gap: var(--adv-space-40);
}
.adv-result-cards > * { width: 475px; max-width: 100%; }
/* TOPIC ROWS EVEN THEIR OWN ROW, NOT THE GRID (AD-166). `1fr` makes every row as tall as the
   tallest in the whole grid, which the area and service cards never showed — their snippets run
   to much the same length. A topic card carries one to three rows of chips, so on the one-kind
   view and in the single column (≤860) every card took the tallest one's height, 125 of it empty
   under a one-row card at 561. `auto` rows still stretch both cards of a row to the taller
   (`align-items: stretch`), which is what the rule above is for. (0,2,0), so the ≤860 column's
   plain `grid-template-columns` still applies. */
.adv-result-group--topics .adv-result-cards { grid-auto-rows: auto; }

/* The kind tags above the rail switch which group is shown. */
.adv-result-kinds { display: flex; flex-wrap: wrap; gap: var(--adv-space-8); }
/* ONE LINE, EACH TAG ITS OWN HEIGHT (AD-143, 430:9032 — drawn for the master's insights
   listing, whose row left in AD-196; the satellite's search page uses it). The active tag
   is 16/500 on a 25 line (45 tall) and the others 14/400 (37); the frame centres them on
   one row. The base row stretches its items, which drew all four at 45. */
.adv-result-kinds--frame { align-items: center; }
/* THE COUNT IS ITS OWN STYLE (AD-145, ADR-0030 §9 — both tiers): 14/400 in the body grey
   on every tag, the active one included (553:13401, 419:3418). It inherited the tag's
   type, so the active tag's count came out 16/500 navy. Only the two search screens'
   tags carry a count. */
.adv-result-kinds [data-kind-count] {
  font-size: var(--adv-small-size);
  font-weight: var(--adv-weight-regular);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-body);
}

/* ---------------------------------------------------------------------
   Search entry                                          node 553:13398
   --------------------------------------------------------------------- */
.adv-result {
  display: flex;
  flex-direction: column;
  gap: var(--adv-space-8);
  padding-block: var(--adv-space-24);
  border-block-end: var(--adv-border-width) solid var(--adv-color-border);
  text-decoration: none;
}
.adv-result__kind {
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-accent-burgundy);
  text-transform: uppercase;
}
.adv-result__title {
  font-family: var(--adv-font-heading);
  font-weight: var(--adv-weight-medium);
  font-size: var(--adv-h3-size);
  line-height: var(--adv-h3-lh);
  color: var(--adv-color-primary-dark);
}
.adv-result:hover .adv-result__title { color: var(--adv-hover-accent); }
.adv-result__snippet {
  margin: 0;
  font-size: var(--adv-body-size);
  line-height: var(--adv-body-lh);
  color: var(--adv-color-body);
}

/* The person card gains the tag row the listing screens carry (300:5534) —
   26px below the credentials, chips wrapping at 8px. On the homepage the
   same card renders without it, so the row is optional by construction.

   THE ROW SITS ON THE PANEL'S FLOOR, not 26px under whatever came last. Since
   the grid gives every card the tallest card's height, the slack has to land
   somewhere, and under the credentials is the wrong place: it leaves each
   card's chips floating at a different distance from its own bottom edge, so a
   row of cards that are now exactly the same height still reads as misaligned.
   Pinned, the chips form one line across the row — which is the thing equal
   heights were for.

   `margin-block-start: auto` is what pins it: an auto margin in a flex column
   eats the free space before it. The 26 moves to PADDING so it survives that —
   a margin that has been handed the slack is no longer a gap, so with the two
   split the distance is `max(26, slack)` rather than one or the other. A card
   with nothing spare still draws the frame's 26. */
.adv-person-card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--adv-space-8);
  margin-block-start: auto;
  padding-block-start: var(--adv-space-26);
}

/* Practice-area card count — "7 experts", level with the number badge at the
   card's top right.

   CORPORATE BLUE. Node 288:3230 binds `corporate/blue`, and so does the hover
   variant (516:6801) — it is a variable, not a stray fill. The Claude Design
   handoff writes rgb(0,0,0) here; that is drift in the export, and a pass that
   followed it turned the one accent on this card into black-on-grey.

   WHICH SETTLES THE PRECEDENCE RULE, since the two sources disagree often
   enough to need one: a BOUND Figma variable beats an unbound literal in the
   handoff. The handoff wins on layout and composition — geometry the variables
   never described — but it does not get to overrule a value design actually
   bound to a name.

   Right-anchored rather than the handoff's left:253, so a longer count
   ("12 experts") grows away from the card edge instead of over it. */
/* "7 experts", top-right of the card (343:11456 → Frame 146 at x=311 y=32, 17
   tall; the card is 400 wide with a 26 margin, so 311 + 63 = 374 is that right
   edge). Only the LISTING card carries it — the homepage's has no such node —
   which is decided by the template, not here.
   AUTO, not 1: 17 is 14 x 1.21. `line-height: 1` gave a 14px box. */
.adv-area-card__count {
  position: absolute;
  inset-block-start: 32px;
  inset-inline-end: var(--adv-space-26);
  margin: 0;
  font-size: var(--adv-small-size);
  line-height: var(--adv-small-lh);
  color: var(--adv-color-primary);
}

/* =====================================================================
   RESPONSIVE — authored, not designed
   ---------------------------------------------------------------------
   Every frame in the design file is 1440 wide. There are no mobile or
   tablet comps, and responsive behaviour is the client's headline
   complaint, so waiting was not tenable: ADR-0014 §7 grants bounded
   developer discretion and this block is that boundary. It is kept in one
   place, rather than scattered through the components, so that when design
   does supply 375/768 frames there is a single thing to replace.

   The rules, in the order they were decided:
     - the page margin relaxes 60 → 26 before anything else moves;
     - card grids degrade 3 → 2 → 1, never to a horizontal scroller;
     - the centred menu collapses into a toggle rather than wrapping,
       because a wrapped nav changes the header height and breaks sticky;
     - the media rail on cards drops away before the text does;
     - the footer's two columns stack under the brand block;
     - the display headings' line budget is given back below the frame.
   ===================================================================== */

/* THE LINE BUDGET IS THE 1440 FRAME'S, AND BELOW THE FRAME IT WOULD DELETE
   SHIPPED WORDS (AD-132). 1439 is one under `--adv-bp-frame`, which is
   `--adv-container` 1320 + 2 × `--adv-section-pad-x` 60 — the width at which the
   600/60/660 split the budget is measured against actually exists. From 861 to
   1439 both hero tracks and both band tracks are an equal (100vw − 180) / 2:
   measured 2026-09-08, 1320 gives 570/570, 1200 gives 510/510 and 1101 gives
   460.5/460.5, so the 600 measure is inert through that band and the cap would be
   measuring nothing. At and below 860 `.adv-band__split` collapses to ONE
   full-width column — see the 860 block — which is the one band where the 600
   still binds; that case is taken at the foot of this note.

   1101 IS NOT THE FLOOR, AND IT IS THE ONE THING TO GET RIGHT HERE. It is the
   tempting number — it lines up with the fluid step below — and it truncates
   TODAY'S copy on both tiers. Measured at 58px fixed: the satellite's "Discuss
   your questions or challenges with us." is FOUR lines at 1101 and at 1200, and
   the master's "Independent expertise. Stronger through collaboration." (as it
   then read — AD-132 shortened it) is four at 1200 AND at 1320. Every mobile rule
   in this file so far re-flows words; `-webkit-line-clamp` removes them.

   BOTH `display` AND `overflow` COME BACK, not just `display`. The base's
   `overflow: hidden` is half of the clamp, and on a flex item — which both about
   headings are, inside `.adv-stack` and `.adv-switch-panel` — it also suppresses
   the automatic minimum size (Flexbox §4.5). Undo both or neither; the same pair
   is what `.adv-area-card--benefit` restores, with the same reasoning.

   AN UNDO AND NOT `@media (min-width: 1440px)`. This file has no `min-width`
   layer, by ADR-0021 §3 and §9 — base rule = the design state, media block = the
   degradation, every one of them widest-first. One `min-width` block here would
   be a second, contradictory mental model, and worse: §3's rule against
   descendant selectors is written as holding "until the file gains a `min-width`
   layer", so adding one would read as licence to start writing them. That is a
   far larger change than a three-line cap.

   THE HERO'S MEASURE IS UNDONE TOO, and that is a QA finding rather than a plan.
   Shipped with 600 at every width it read one line instead of two at 430, 480,
   560 and 860, and broke in a different place at 1200 — because 399 was not a
   leftover down there, it was the number every tier from 402 up was drawn and
   tested against, AD-119's overflow cases included. ADR-0021 §4 had already
   examined removing it below 561 and refused: "143px of new breakage for 241px
   fixed". So the widening is the FRAME's and nothing else's.

   `.adv-display--budget`'s measure is NOT undone, and BOTH tiers move where it
   binds — corrected here after a review checked the master rather than assuming
   it. From 861 up it is inert (the tracks are smaller); at 561–860, where the
   band is one full-width column, it binds on each tier and each changes:
   measured at 860 and 38px, the satellite's About heading goes three lines to two
   (its inline `16ch` was 395 wide, this is 600) and the master's goes ONE line to
   two (it had no cap at all, so its column gave it 733).

   KEPT ANYWAY, because the alternatives are worse and were measured too. `none`
   is not a restoration — at 860 it hands the heading 740 on the satellite and 733
   on the master, wider than the frame ever draws it — and `16ch` is the
   font-relative cap this ticket exists to remove, which the note on the (since
   retired) satellite `.adv-hero-title` argued against on its own terms. 600 is the narrowest of the
   three and the only one that is the same number the frame uses. Nothing is
   truncated (the clamp is off down here) and the two tiers agree, which is the
   point. Recorded in ADR-0021 §12 rather than undone. */
@media (max-width: 1439px) {
  /* THE INSIGHT GRID GOES ONE TO A LINE WHERE TWO ROW CARDS DO NOT FIT (AD-140,
     TD-21). Two `1fr` columns of 335 image + text needed 537 each in English and
     ~620 in German, so /articles/ scrolled sideways at 861–1101 (DE to 1280).
     600 is a documented literal: the 335.42 image, its 18 gap and a 247 text
     column — the narrowest that still reads as the frame's row card (431:9291
     draws 296). Two columns from 1366, one below. (0,2,0), so it beats the ≤1100
     `.adv-grid` two-up; the ≤860 block restores that below 861. */
  .adv-grid--wide.adv-grid--fluid { grid-template-columns: repeat(auto-fill, minmax(600px, 1fr)); }
  /* The 693 is the 1440 frame's: a narrower card has a shorter photograph and
     a taller panel, so below the tier the card takes its content's height and
     every chip shows (the grid still evens a row out). */
  .adv-person-card--listing { height: auto; }
  .adv-person-card--listing .adv-person-card__tags { overflow: visible; }
  .adv-display--budget {
    display: block;
    overflow: visible;
  }
  /* THE EXPERTS COLUMN GOES UNDER THE BODY (AD-153). Below 1440 the 330 right of the 660
     body is narrower than 60 + 270 (170 at 1280), so the column leaves row 2 for the row
     under the article — the body's column, its left edge — one section gap under the
     body and still 270 wide (MD, 2026-09-22: no frame draws either). The same rule holds
     through the ≤1100 one-column grid; ≤560 lays it out as the rail's own tiles. */
  .adv-article__experts {
    grid-row: auto;
    justify-self: start;
    margin-block-start: var(--adv-section-gap);
  }
}

@media (max-width: 1100px) {
  .adv-footer__top,
  .adv-footer__bottom { padding-inline: var(--adv-space-26); }
  /* The master's value rows put the description under the name here (AD-140,
     TD-21) — the ≤560 layout, whose own rules set these properties directly and
     so still win below 561. */
  .adv-values--fluid {
    --adv-value-cols: 38px minmax(0, 1fr);
    --adv-value-text-col: 2;
    --adv-value-row-gap: var(--adv-space-8);
  }
  /* `--top` too (AD-168): the long text goes under the name here, as About's rows always did —
     the two 578/660 tracks would otherwise halve, and a Dutch or German value name
     ("Verantwoordelijkheid") would get a cell narrower than the word and run into the text. */
  .adv-values--top .adv-value { grid-template-columns: 38px minmax(0, 1fr); row-gap: var(--adv-space-8); }
  .adv-values--top .adv-value__body { grid-column: 2; }
  .adv-values--top .adv-value__num { margin-block-start: 0; }
  /* THE SATELLITE EXPERT PAGE'S TWO COLUMNS NARROW HERE (TD-29, ADR-0030 Amendment 5, MD's
     call). Each is ~375 at 861, so the facts' 330 first column left the practice-area and
     service chips a ~45 column, and they ran over the biography up to 953. A name word wider
     than what the CTA left (~186) ran under it up to 873. The facts go to one column
     under the portrait, on the column's own 34, and the CTA goes under the name. The main
     column keeps 34 between its three rows, as the ≤860 stack does. From 1101 the frame's
     row is unchanged. `:where()` keeps the CTA and facts rules at one class, so the ≤560
     block (later, same weight) still owns 402. The master's page is TD-25's. */
  .adv-expert-detail--sat .adv-expert-detail__main {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--adv-m-band-gap);
  }
  .adv-expert-detail--sat :where(.adv-expert-cta) {
    grid-column: 1;
    justify-self: start;
    margin-block-start: 0;
  }
  .adv-expert-detail--sat :where(.adv-expert-facts) {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--adv-space-34);
  }
  /* The bar itself stays unpadded. THE GLYPH FOLLOWS THE PAGE'S GUTTER HERE, 26
     (ADR-0030 Amendment 1 §2): the client's note was the glyph not matching the
     page's margin, which is 60 above 1100 and 26 in this band. The tile starts
     at the edge and pads 26; the ≤1439 sheet's rows read the same sum. */
  .adv-nav--row { --adv-nav-tile-x: 0px; --adv-nav-tile-pad: var(--adv-space-26); }
  .adv-nav__links > a,
  .adv-nav__links > span,
  .adv-nav__item,
  .adv-dropdown__toggle { padding-inline: var(--adv-space-24); }
  /* The rule that dropped the homepage menu's +64 in this band is gone
     (AD-140): the +64 no longer exists — the master grid draws the bar state —
     and below 1440 the master menu is the sheet, whose transform the ≤1439
     block below retires. This padding step is the satellite's, and the
     master's `.adv-nav--compact` at 1440. */
  /* THREE RULES REMOVED HERE (2026-09-01), all of them the full-bleed panel's:
     a `:not(--popover)` padding-inline that gave the panel page margin back as
     the viewport narrowed, and `__cols` / `__group` stacking its two halves into
     one column. Both tiers draw the popover now — one column at a fixed 236,
     with nothing to re-margin and nothing to collapse. The elements themselves
     are gone from the templates and from the base rules above. */
  /* Display sizes are set for a 1440 frame; below it they must come down or a
     72px hero eats the viewport. Fluid rather than stepped, so there is no
     width at which the headline is awkward.

     THE FLOORS ARE 38, NOT 34/40/32. On the 402 frames the display end lands
     on ONE number — 38 carries the hero (800) and every band headline (700)
     (ADR-0017; --adv-m-hero/title). The old floors were authored under B2
     ("nothing below 1440 exists"); the measured value supersedes them. */
  .adv-display    { font-size: clamp(var(--adv-m-title-size), 4.2vw, var(--adv-display-size)); }
  .adv-page-title { font-size: clamp(var(--adv-m-title-size), 3.8vw, var(--adv-page-title-size)); }
  .adv-area-card__title { font-size: clamp(26px, 3vw, var(--adv-card-title-size)); }
  /* The person card's name is 28, not the 38 card title — it must not be swept
     into the same clamp or it grows past its own designed size. */
  .adv-person-card__name { font-size: clamp(22px, 2.2vw, var(--adv-h2-size)); }
  .adv-value__name { font-size: clamp(24px, 2.8vw, var(--adv-h1-size)); }
  .adv-cta-split__media { flex-basis: 45%; min-height: 420px; }
  /* The detail page's media column is a fixed 494px; below ~1100 that is more
     than half the text column, so it becomes a proportion instead. */
  .adv-detail { grid-template-columns: 45% 1fr; gap: var(--adv-space-40); }
  /* Three columns will not fit; the rails move under the prose. */
  .adv-detail--3col { grid-template-columns: 220px 1fr; }
  .adv-detail--3col > :last-child {
    grid-column: 1 / -1;
    /* AND THE DESKTOP COLUMN'S SIZING IS UNDONE (AK, 2026-08-31 — "the block
       got squeezed on mobile"). The desktop rule pins this child to
       `width: 270px; justify-self: end` because there it IS the third column,
       270 wide at the container's right edge. Taking the full row without
       undoing either left the rails 270 wide and hard right — a narrow strip
       floating at the end of a 1320 row, and at 402 a 270 strip inside a 362
       column. Once it spans the row it is a ROW, so it takes the row's width. */
    width: auto;
    justify-self: stretch;
  }
  .adv-detail-head { padding: var(--adv-space-40) var(--adv-space-26); }
  .adv-detail-head:has(h1) { padding-block-start: var(--adv-space-40); }
  /* THE TITLE FOLLOWS THE PROSE COLUMN, and the column moved: `.adv-detail--3col`
     is `220px 1fr` on a 40 gap from here down, so the body starts 260 into the
     content box and the desktop's 330 would leave the title 70 to its right —
     the alignment this indent exists for, broken at every width but 1440.
     Both selectors spelled out because the desktop rule is (0,2,1) and a bare
     `.adv-detail-head > h1` here would be (0,1,1) and lose; a media query adds
     no specificity. `--indent` needs it too — its own 390 padding is already
     gone by this width, replaced by the 26 above. */
  .adv-detail-head:not(.adv-detail-head--indent) > h1,
  .adv-detail-head.adv-detail-head--indent > h1,
  .adv-detail-head:not(.adv-detail-head--indent) > .adv-detail-head__chips,
  .adv-detail-head.adv-detail-head--indent > .adv-detail-head__chips {
    margin-inline-start: calc(220px + var(--adv-space-40));
  }
  .adv-article-body { grid-template-columns: 1fr; padding-inline: var(--adv-space-26); }
  .adv-article-body > * { grid-column: 1; }
  .adv-article__title { margin-block-end: var(--adv-space-40); font-size: clamp(var(--adv-m-title-size), 4vw, var(--adv-display-size)); }
  .adv-article__byline { flex-direction: column; }
  .adv-article__date { text-align: start; }
  /* The master listing head carries a (0,2,0) desktop rule
     (--master--listing: 153/104) that outguns a single class — matched
     compound-for-compound so 54 wins on mobile. */
  .adv-page-head--listing,
  .adv-page-head--master.adv-page-head--listing { padding-block: 54px; }
  /* Applied-filter chips sit ABOVE the "All practice areas" head (the
     handoff's filtered state; AK) — flex order, no markup change.

     AND THEY BELONG TO THE CONTROLS, NOT TO THE RESULTS (AK, 2026-09-02).
     Reordering alone left them 54 below the "Filters" row, because that 54 is
     `.adv-listing`'s stack gap between the controls block and `.adv-results`,
     and the chips are now the first thing on the far side of it. 681:26795
     measures the whole column: the Filters row ends at 496 and the chips start
     at 512 — SIXTEEN — while the head below them starts at 603, i.e. 54 under
     a 37-tall chip row.

     So the two gaps differ and one `gap` cannot serve both. The margins say the
     difference out loud rather than hiding it in a new wrapper: pull up by the
     54 this element did not ask for and put back the 16 it wants; push down by
     the 54 the head wants, less the 34 the results stack already gives it. */
  .adv-results { display: flex; flex-direction: column; }
  .adv-results > .adv-applied-filters {
    order: -1;
    margin-block-start: calc(var(--adv-space-16) - 54px);
    margin-block-end: calc(54px - var(--adv-space-34));
  }
  /* CLEAR ALL LEADS THE ROW (681:26940: "Clear all" at x=0, the first chip at
     x=62). It was last, which on a row that scrolls sideways means the control
     that undoes everything is the one you cannot see. The search screen already
     had this correction; the listings are the same row and the same frame
     family, so the rule moves up here and stops being search-only. */
  .adv-applied-filters__clear { order: -1; }
  .adv-grid { grid-template-columns: repeat(2, 1fr); gap: var(--adv-space-40); }
  /* How we can help: the panel keeps its two columns to 861 on a page-gap gutter. */
  .adv-help { --adv-help-col-gap: var(--adv-space-60); }
  .adv-page-head { padding-inline: var(--adv-space-26); }
  /* The plate keeps the page margin the breadcrumbs take here. Its detail twin
     keeps its 20 under the bar — `--titled` above drops to 0, but a rounded
     plate pressed against the bar reads as clipped. */
  .adv-page-band--inset { width: calc(100% - 2 * var(--adv-space-26)); }
  .adv-about-hero { padding-inline: var(--adv-space-26); }
  .adv-breadcrumbs,
  .adv-listing,
  .adv-cta-band__inner,
  .adv-article-areas,
  .adv-detail { padding-inline: var(--adv-space-26); }
}

/* ===== THE HEADER COLLAPSES BELOW 1440 — BOTH TIERS (AD-140, ADR-0022 Amendment 2, ADR-0030 §1) ====
   The master row is a fixed sum — the 248 tile, five items at label + 2 × 40,
   the two 60 tiles — and nothing in it gives between 861 and 1440. Measured
   2026-09-16: EN needs 1288 (1128 at the ≤1100 padding), NL 1495, DE 1512,
   FR 1551, so every master page scrolled sideways somewhere in that band (EN
   at 861–1287, TD-10; the translated menus at every width up to 1440 and
   beyond). MD's call: the master shows its full row at 1440 and the burger
   sheet below it, in every language. The satellite's redrawn row does the same
   since AD-145 (ADR-0030 §1): its NL menu overflowed 861–≈1155 at the old 60
   row already, and the 99 row with a city is wider still.

   THE SHEET IS THE ≤860 ONE, THE BAR IS NOT. The bar stays the desktop's 99
   with the tile at the left — so everything measured from
   `--adv-nav-h`, the transparent homepage hero and the wordmark slide
   keep working — and the search tile stays. Only the menu becomes the navy
   sheet under the bar, with the ≤860 block's row styles. No frame draws this
   band (a designer question in Open Questions).

   WHY THIS BLOCK BREAKS THE WIDEST-FIRST ORDER (ADR-0021). It sits after the
   ≤1100 block, whose item padding it must beat at the same weight, and before
   the ≤860 block, whose bare classes must still win below 861 — every rule
   here is `:where()`-scoped to zero weight, and every value that would
   otherwise leak below 861 is the ≤860 block's own. The (0,2,0)+ rules are the
   ones that have to out-weigh a base master rule, and they repeat values the
   ≤860 block also sets.

   `.adv-nav--row` is emitted by both headers; `:has(.adv-nav__toggle)` keeps
   the styleguide's toggle-less demos (design-system/index.html) a row at every
   width. */
@media (max-width: 1439px) {
  /* Back to the satellite's grid: with the links out of flow, the tile keeps
     the left track and the tiles the right — and the ≤860 centred logo still
     centres on the screen. `auto` also stops the fixed sheet shrink-centring. */
  .adv-nav--row:has(.adv-nav__toggle) { --adv-nav-cols: 1fr auto 1fr; --adv-nav-menu-justify: auto; }
  /* The tile no longer stretches across the whole left track (a 630-wide home
     link), and the tiles keep column 3: with the links gone from the grid they
     would otherwise auto-place into the middle track (site.js's note on
     `closeOnLink` describes that renumbering). */
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__logo-link { justify-self: start; }
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__actions { grid-column: 3; }
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__toggle { display: inline-flex; }

  /* THE SHEET — the ≤860 one (623:23130 / 623:22166), opening under the 99 bar.
     Its rows start at the wordmark's own x rather than the 402 margin. */
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__links {
    position: fixed;
    inset: var(--adv-nav-h) 0 0;
    z-index: var(--adv-z-dropdown);
    flex-direction: column;
    align-items: flex-start;
    gap: 7px;
    padding: 18.5px calc(var(--adv-nav-tile-x, 0px) + var(--adv-nav-tile-pad)) var(--adv-space-40);
    background: var(--adv-color-hero-navy);
    overflow-y: auto;
  }
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__links > a,
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__links > span {
    justify-content: flex-start;
    height: auto;
    min-height: var(--adv-m-touch-min);
    padding: 9.5px 0;
    font-size: var(--adv-m-row-size);
    font-weight: var(--adv-weight-regular);
    line-height: var(--adv-m-body-lh);
    color: var(--adv-color-on-navy);
  }
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__links > a:hover {
    background: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  /* Current is weight only in the sheet, and the row stays inverse: the base
     current rule's navy would vanish on it. */
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__links > a[aria-current="page"] {
    font-weight: var(--adv-m-row-active-weight);
    color: var(--adv-color-on-navy);
  }
  /* The rows are left-set text, not boxed labels: no 500 reservation. */
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__label { display: inline; }
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__label::before { content: none; }
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__label-text { display: inline; width: auto; }
  /* The dropdown gives way to the flat rows, as below 861 — at the weight of
     the popover anchoring that sets its `display: flex`. */
  .adv-nav--row:has(.adv-nav__toggle) .adv-dropdown { display: none; }
  :where(.adv-nav--row:has(.adv-nav__toggle)) .adv-nav__links > .adv-nav__mobile-link { display: inline-flex; }
  /* Closed in the first frame, before any script — the ≤860 rule's reasoning.
     With JavaScript off the sheet cannot be opened in this band either; the
     footer carries every destination. */
  .adv-nav--row:has(.adv-nav__toggle[aria-expanded="false"]) .adv-nav__links { display: none; }
  /* The homepage menu's −64 belongs to the row; the sheet does not move. */
  .adv-nav--home .adv-nav__links,
  .adv-nav--home[data-wordmark] .adv-nav__links { transform: none; }

  /* With the sheet up the bar is navy too (623:22166) — and on the homepage it
     shows its own wordmark, inverted, even while the hero's is on screen: the
     sheet covers that one. */
  .adv-nav--row:has(.adv-nav__toggle[aria-expanded="true"]) { background: var(--adv-color-hero-navy); }
  .adv-nav--row:has(.adv-nav__toggle[aria-expanded="true"]) .adv-nav__logo { filter: brightness(0) invert(1); }
  .adv-nav--row:has(.adv-nav__toggle[aria-expanded="true"]) :is(.adv-nav__toggle, .adv-chip) { color: var(--adv-color-on-navy); }
  .adv-nav--row:has(.adv-nav__toggle[aria-expanded="true"]) :is(.adv-nav__toggle:hover, .adv-chip:hover) {
    background: transparent;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .adv-nav--home:has(.adv-nav__toggle[aria-expanded="true"]) .adv-nav__logo-link { transform: none; }
}

@media (max-width: 860px) {
  /* AD-142's Join corrections are DESKTOP measurements (385:4800); the tiers below keep
     the values they had. Same weight as the desktop rules and later, so these win. */
  .adv-stack--labelled { gap: var(--adv-stack-gap); }
  .adv-stack--rows { gap: 54px; }
  .adv-search-results--frame {
    --adv-result-count-mt: var(--adv-space-16);
    --adv-result-all-mt: 0;
    --adv-result-group-gap: var(--adv-space-26);
    --adv-rail-label-mb: var(--adv-space-26);
  }
  .adv-controls-row--frame,
  .adv-search-kind-head[hidden] + .adv-controls-row--frame,
  .adv-search-results--sat [data-chip-icon] + .adv-controls-row--frame { margin-block: 0; }
  .adv-search-kind-head { margin-block-end: 0; }
  .adv-values--wide .adv-value__name,
  .adv-values--careers .adv-value__name { line-height: 1; }
  .adv-form-split .adv-form { margin-block-start: 0; }
  /* THE TYPE STEP (ADR-0017 §3, conflict 2). Below the nav breakpoint the
     body step drops to 14/25 — body copy, card meta and button labels all
     take it, which is why the remap happens on the tokens rather than per
     component. 16 survives only as the uppercase section label (m-label);
     the lede pair contracts to 18/1.35. --adv-nav-size is deliberately NOT
     remapped: the cover menu styles its own rows below, and the footer's
     16px column headings keep the desktop value by design (623:21898). */
  :root {
    --adv-body-size:     var(--adv-m-body-size);
    --adv-body-lh:       var(--adv-m-body-lh);
    --adv-lead-size:     var(--adv-m-lede-size);
    --adv-lead-lh:       var(--adv-m-lede-lh);
    --adv-subtitle-size: var(--adv-m-lede-size);
    --adv-label-size:    var(--adv-m-label-size);
    --adv-label-lh:      1.5625;  /* the 16px label keeps the 25px box (foundations sheet) */
  }
  /* The article page's 29px desktop label (AD-143) is a desktop reading: here the
     label keeps the tier's 25 box like every other. */
  .adv-related--article .adv-section-label,
  .adv-results--featured-frame > .adv-section-label { line-height: var(--adv-label-lh); }
  .adv-results--featured-frame > .adv-section-label { margin-block-start: 0; }
  .adv-results--sat > .adv-section-label { margin-block-end: 0; }
  .adv-results--sat > .adv-load-more { margin-block-start: 0; }
  /* The careers pages' 29 label box (AD-143) is the same desktop reading. */
  .adv-section-label--auto,
  .adv-job-layout .adv-section-label,
  .adv-band__split--job-office .adv-section-label { line-height: var(--adv-label-lh); }

  /* Nav collapses. The toggle appears, sized to the authored touch floor
     around its 20px glyph — the target grows, the glyph does not
     (ADR-0017 §5). The search chip takes the same box. */
  .adv-nav__toggle {
    display: inline-flex;
    width: var(--adv-m-touch-min);
    height: var(--adv-m-touch-min);
  }
  .adv-chip { width: var(--adv-m-touch-min); height: var(--adv-m-touch-min); }
  /* No search tile in the mobile bar (597:19805 draws logo + burger only;
     AK 2026-08-26). The direct-child selector is load-bearing: the
     language toggle is also an .adv-chip but sits inside .adv-nav__lang,
     and it must stay — four locales have no other way in (B9). */
  .adv-nav__actions > a.adv-chip { display: none; }

  /* MOBILE BAR (1537:19420 — every page of both tiers, MD; ADR-0030 Amendment 1
     §7): 88 tall, the logo tile CENTRED — 220 × 88 at x=91 on the 402 frame, the
     wordmark 162.9 × 59.3 in its middle. It was 72 with a 150 × 60 tile and a
     40-high wordmark (597:19805), and every mobile page top moves down 16 with
     it. The links leave the grid entirely (position: fixed below), so only the
     logo and the actions remain in it and each is placed explicitly.

     THE CONTROLS HANG FROM THE BURGER'S LINE, not the bar's centre: the frame
     draws the 20 × 16 glyph at (362, 26) — centre 34 against the logo's 44, a
     designer question — with its right edge on the 20 margin; the 44 touch box
     is centred on it. The language chip stays beside it (no 1537 frame draws
     one, but a phone still needs the switch). */
  .adv-nav { position: relative; }
  .adv-nav__bar { height: var(--adv-m-header-h); }
  .adv-nav__logo-link {
    grid-column: 2;
    justify-self: center;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--adv-m-logo-tile-w);
    height: var(--adv-m-logo-tile-h);
  }
  .adv-nav__logo { height: var(--adv-m-logo-h); }
  .adv-nav__actions {
    grid-column: 3;
    align-self: start;
    margin-block-start: calc(34px - var(--adv-m-touch-min) / 2);   /* 1537:19420: the glyph's centre, 26 + 16 / 2 */
  }

  /* AD-131 UNDOES ITSELF HERE. The two rules above win on their own — they set
     `height` directly, so the row's `--adv-nav-h` and rebound `--adv-nav-mark-h`
     never reach the bar at this tier — but the tile's inset and the homepage's
     slide are not heights and need saying.

     The weights are the point, and they are the trap this ticket was most
     likely to ship: `.adv-nav--home[data-wordmark]` is (0,3,0) against a bare
     class at (0,1,0), and SPECIFICITY BEATS ORDER, so without these the 402
     frame gets a centred tile drawn 229px off the left of the screen and a menu
     sheet shoved 64 sideways. `.adv-nav__links` IS that sheet below this
     breakpoint (position: fixed, further down), which is what makes the second
     line load-bearing rather than cosmetic. `[data-wordmark]` is unqualified on
     purpose: it matches both values, so one line retires the slide in either
     state. Restated at matching weight rather than by weakening the tier scope
     — the same answer as the dropdown rules below. */
  .adv-nav--row .adv-nav__logo-link { padding-inline: 0; }
  /* The row's tile x is desktop geometry: the mobile tile is centred. The tiles'
     inset puts the burger glyph's right edge on the 20 margin — the touch box
     reaches (44 − 20) / 2 past it. */
  .adv-nav--row {
    --adv-nav-tile-x: 0px;
    --adv-nav-tiles-inset: calc(var(--adv-m-margin) - (var(--adv-m-touch-min) - var(--adv-m-toggle)) / 2);
  }
  /* The outer tracks may not grow past half of what the tile leaves: the two
     44 controls and their inset (96) are wider than that (91 at 402), and an
     `auto` minimum pushed the "centred" tile 5 left. They overflow toward the
     tile instead, clear of the glyph. At the ≤1439 rule's weight, later. */
  .adv-nav--row:has(.adv-nav__toggle) { --adv-nav-cols: minmax(0, 1fr) auto minmax(0, 1fr); }
  /* THE SATELLITE'S CITY SITS UNDER THE WORDMARK (1537:19432): Inter 16 regular,
     its left edge on the glyph's (x=120 of 402), its glyphs centred on y=71 —
     the frame's 65 on a 0.77 line box is 63 on a 16 one. It is as wide as the
     glyph at most (the tile less the glyph's two insets; 183.65 / 66.9 is the
     wordmark's own ratio), and site.js shrinks a longer name to fit, floor 10. It
     was hidden below 861 until the 1537 frames drew it. */
  .adv-nav__city {
    position: absolute;
    inset-inline: calc((var(--adv-m-logo-tile-w) - var(--adv-m-logo-h) * 183.65 / 66.9) / 2);
    inset-block-start: 63px;
    max-width: none;
    font-size: var(--adv-m-nav-city-size);
    line-height: 1;
    font-weight: var(--adv-weight-regular);
  }
  .adv-nav--home .adv-nav__logo-link,
  .adv-nav--home .adv-nav__links,
  .adv-nav--home[data-wordmark] .adv-nav__logo-link,
  .adv-nav--home[data-wordmark] .adv-nav__links { transform: none; }
  /* THE HOME TOPS ARE DRAWN AT 402 NOW (1537:17668 master, 1537:18643
     satellite — ADR-0030 Amendment 1 §7, reversing ADR-0024 §7's "no
     transparent state" and this block's old opaque bar). The bar opens with NO
     LOGO over the hero's own lockup — transparent on the master, filled #F5F4F2
     on the satellite, the desktop's two top states — and the logo (and the
     satellite's city) arrive once the hero's lockup has gone under the bar
     (1537:19039, 1537:19350), with the fill and the hairline, as above 860.

     THE TILE SLIDES IN FROM THE LEFT HERE TOO (MD, ADR-0030 Amendment 7 §2 —
     it used to fade, "a centred tile has no side to come from"). In the hero
     state it waits just off the left edge: a centred box's left is
     (100vw − its width) / 2, so −50vw − 50% of its own width puts its right
     edge at x = 0 (100vw counts a scrollbar, which errs further off-screen, as
     above 860). It travels on the base rule's `transform` transition
     (`--adv-transition-logo-slide`, 480), both ways, and the base
     reduced-motion rule drops the travel; off-canvas it takes no taps, so
     `visibility` stays. The satellite's city sits inside the tile and travels
     with it. With the menu sheet up the tile is in place, inverted, as above
     860 — the `:has()` line outweighs the hero state.

     THE FILL STILL ARRIVES AT ONCE, as above 860. The brief asked for it to fade
     in with the logo (ADR-0030 Amendment 2 §2 records the deviation): a
     transition on the bar state's fill also runs when the menu sheet CLOSES —
     the same state is entered — and drew the sheet's navy fading out for 480ms
     under a logo that had already turned dark again. */
  /* The hero's fade measures against the 88 bar, and the satellite lockup's
     glyph starts (tile − glyph) / 2 below its top: the 295 tile is 99.2 / 248
     of its width, the glyph 66.9 / 248 (19.2 at the tokens). */
  [data-hero-fade] { --adv-hero-fade-inset: var(--adv-m-header-h); }
  .adv-hero-lockup[data-hero-fade] { --adv-hero-fade-lead: calc(var(--adv-m-hero-logo-w) * (99.2 - 66.9) / 496); }
  .adv-nav--home[data-wordmark="hero"] .adv-nav__logo-link { transform: translateX(calc(-50vw - 50%)); }
  .adv-nav--home[data-wordmark="hero"]:has(.adv-nav__toggle[aria-expanded="true"]) .adv-nav__logo-link { transform: none; }
  /* The satellite Home's bar keeps its #F5F4F2 once the logo is in (1537:19350
     draws the scrolled bar on the hero's own surface). */
  .adv-nav--satellite.adv-nav--home[data-wordmark="bar"] { background: var(--adv-color-surface-alt); }

  /* THE MENU COVERS THE PAGE (623:23130) — the opposite of the in-flow
     panel this block used to build. A fixed sheet on the page surface,
     opening under the bar (`--adv-m-header-h`, 88 since the 1537 frames) so
     the bar's own logo and toggle stay where the frame puts them: the logo
     tile centred, the close glyph at x=362 y=26 — which is the toggle,
     drawing its X.

     Rows are 25-tall text on a 51 pitch — 14/25 regular, ink is Text
     Secondary (--adv-m-row-ink), no tile, no fill; a text list, not tap
     rows. The authored 44px hit area comes from 9.5px block padding
     (9.5 + 25 + 9.5 = 44) and the gap shrinks to 7 so the VISUAL pitch
     stays the frame's 25 + 26 = 51. Rows start 28 under the bar (18.5 pad +
     9.5 hit — y=100 under 623:23130's 72 bar, 116 under the 88 one; the
     sheet itself is not redrawn). */
  .adv-nav__links {
    position: fixed;
    inset: var(--adv-m-header-h) 0 0;
    z-index: var(--adv-z-dropdown);
    flex-direction: column;
    align-items: flex-start;
    gap: 7px;
    padding: 18.5px var(--adv-m-margin) var(--adv-space-40);
    /* NAVY, not the page surface: the kit component (623:23130) draws a
       light plate, but the screen-level frame of the menu OPENED over the
       homepage (623:22166) is hero-navy with inverse rows — and the screen
       frame wins, the same rule that settled the console topbar. */
    background: var(--adv-color-hero-navy);
    overflow-y: auto;
  }
  .adv-nav__links > a,
  .adv-nav__links > span,
  .adv-nav__item {
    justify-content: flex-start;
    height: auto;
    min-height: var(--adv-m-touch-min);
    padding: 9.5px 0;
    font-size: var(--adv-m-row-size);
    font-weight: var(--adv-weight-regular);
    line-height: var(--adv-m-body-lh);
    color: var(--adv-color-on-navy);   /* rows are inverse on the navy sheet (623:22166) */
  }
  /* In the sheet, state is WEIGHT, not surface: no hover tile, and the
     active row goes 500 (authored — the file's 13px active variant is an
     authoring slip, see ADR-0017 §6). */
  .adv-nav__links > a:hover,
  .adv-nav__item:hover {
    background: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .adv-nav__links > a[aria-current="page"],
  .adv-nav__item[aria-current="page"] {
    font-weight: var(--adv-m-row-active-weight);
    color: var(--adv-color-on-navy);
  }
  .adv-nav__label { display: inline; }
  .adv-nav__label::before { content: none; }
  .adv-nav__label-text { display: inline; width: auto; }

  /* The dropdown does not survive to mobile: the sheet lists its content
     as flat rows instead (623:23130 — About · Practice areas · Legal
     experts · Partner firms · …), which is what the __mobile-link items
     in both headers are for. Hiding the whole component also retires the
     in-flow panel and the master-panel-on-a-phone layout that used to
     live here.

     ALL THREE SELECTORS, and the tier-scoped two are not redundant (AK,
     2026-08-31; satellite added 2026-09-01). The popover anchoring sets
     `display: flex` on `.adv-nav--master .adv-dropdown` — (0,2,0) against
     this rule's (0,1,0) — and SPECIFICITY BEATS ORDER, so a rule 3800 lines
     earlier silently un-hid "Find legal support" in the 402 sheet, where it
     appeared beside the flat rows that exist to replace it. Restated at
     matching weight rather than by weakening the anchoring, so the mobile
     intent is explicit instead of depending on nobody ever out-specifying it.

     The satellite arm is the same trap, armed the day its menu became a
     popover: it now carries the identical (0,2,0) anchoring, so without this
     line "Expertise" would reappear in the 402 sheet directly above the
     `__mobile-link` row that exists to replace it. */
  .adv-dropdown,
  .adv-nav--master .adv-dropdown,
  .adv-nav--satellite .adv-dropdown { display: none; }
  .adv-nav__links > .adv-nav__mobile-link { display: inline-flex; }

  /* ── THE SHEET IS CLOSED BEFORE ANY SCRIPT RUNS (AK, 2026-09-02) ──────────
     Reported as "the menu flickers on every navigation and refresh", on both
     tiers, and it was not a flicker: it was the FIRST PAINTED FRAME of every
     mobile page. Reproduced by disabling script execution, which is exactly
     what the browser has to work with until the deferred bundle runs —
     `#navLinks` came back `display: flex`, `position: fixed`, 402 × 828, navy,
     and `elementFromPoint` at the middle of the viewport returned the menu.

     Three reasonable things combined into it. The markup ships `#navLinks`
     with no `hidden`, correctly — above this breakpoint the nav must be
     visible. The rule above turns it into a full-screen navy cover. And the
     ONLY thing that closed it was `syncNav()` in site.js setting
     `navLinks.hidden`, which is `defer`red and therefore runs after first
     paint. So the closed state existed only as a side effect of JavaScript
     having run, and every navigation is a fresh document. site.js's own
     comment reads "the panel is display:none below the breakpoint via
     [hidden]" — a true description of what the script does, easily misread as
     a description of the stylesheet, where nothing of the kind existed.

     A CLOSED MENU IS A PROPERTY OF THE MARKUP, and the markup already says so:
     the burger ships `aria-expanded="false"`. Keying off it makes the sheet
     closed in the first frame, with no script involved. `:has()` is already
     what the three rules below use, so this introduces no new dependency.

     It cannot disagree with `[hidden]`: `disclosure()`'s `set()` writes
     `aria-expanded` and `panel.hidden` in the same statement, so the attribute
     this reads and the attribute base.css's `[hidden]` reads always move
     together. This rule is the guarantee for the window BEFORE that code runs.

     THE TRADE, NAMED: with JavaScript off the mobile menu can no longer be
     opened. It could not be USED before either — it was pinned open across the
     page — so this replaces one broken no-JS state with a quieter one, and the
     footer carries the whole navigation (8 live links on both tiers, verified
     with script execution disabled), so no destination becomes unreachable.
     On the master the same holds from 1439 down (AD-140, the block above). */
  .adv-nav:has(.adv-nav__toggle[aria-expanded="false"]) .adv-nav__links { display: none; }

  /* With the sheet up, the BAR is part of the navy surface too — inverted
     logo, white close glyph and controls (623:22166). */
  .adv-nav:has(.adv-nav__toggle[aria-expanded="true"]) { background: var(--adv-color-hero-navy); }
  .adv-nav:has(.adv-nav__toggle[aria-expanded="true"]) .adv-nav__logo { filter: brightness(0) invert(1); }
  .adv-nav:has(.adv-nav__toggle[aria-expanded="true"]) :is(.adv-nav__toggle, .adv-chip) { color: var(--adv-color-on-navy); }
  .adv-nav:has(.adv-nav__toggle[aria-expanded="true"]) :is(.adv-nav__toggle:hover, .adv-chip:hover) {
    background: transparent;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  /* BUTTONS ON THE BODY STEP (ADR-0017 §3, conflict 3). The 402 kit's
     button label is 14/25 medium — the same step every other label takes
     here — while the geometry holds (50 tall, pill, 26 inline pad, all
     already the base rule). Note the INVERSION the conflict names was
     already the build's state: --secondary IS the outlined main and
     --primary the filled accent since the v2 transcription; what was
     missing is this label step and the authored pressed states below. */
  .adv-btn { font-size: var(--adv-m-body-size); line-height: var(--adv-m-body-lh); }

  /* AUTHORED pressed states (ADR-0017 §6): main presses to desktop main
     AT REST — navy fill, light label — because mobile main is already the
     outlined form; accent presses to its desktop hover, burgundy (ADR-0024
     §2 — it pressed one step down to blue-deep while it was blue). Disabled is
     already the base rule (the desktop inactive recipe, verbatim). */
  .adv-btn--secondary:active {
    background: var(--adv-m-btn-main-pressed-bg);
    border-color: var(--adv-m-btn-main-pressed-bg);
    color: var(--adv-m-btn-main-pressed-ink);
  }
  .adv-btn--primary:active { background: var(--adv-m-btn-accent-pressed-bg); }

  /* The enquiry FORM-SPLIT has no mobile idea of its own: two 660 columns
     squeezed side by side at 402. It stacks — and its desktop photo hides,
     because the mobile slot (Rectangle 71's position, after the heading)
     already renders the same image; two copies of one photograph is not a
     layout. */
  .adv-form-split { grid-template-columns: 1fr; gap: var(--adv-space-34); }
  .adv-form-split > .adv-stack { min-width: 0; }
  .adv-form-split__media { display: none; }

  /* Cards lose the media rail before they lose the text. */
  .adv-card__media,
  .adv-media-card__media { display: none; }

  .adv-footer__cols { max-width: none; margin-inline-start: 0; flex-basis: 100%; }
  .adv-footer__bottom { flex-direction: column; align-items: flex-start; }
  /* Both footers' desktop measurements stop here (AD-137, AD-145 — the 402 tier was
     measured against the old base values, and no mobile frame came with either
     round). The column rules above already override the widths directly. On the
     BASE, later than both tier modifiers at their weight, so it resets them all;
     the satellite keeps its city (8 under a 40 mark) and its light-blue line. */
  .adv-footer {
    --adv-footer-mark-h: 40px;
    --adv-footer-mark-offset: 0px;
    --adv-footer-tagline-gap: var(--adv-space-24);
    --adv-footer-network-gap: var(--adv-space-24);
    --adv-footer-brand-w: 320px;
    --adv-footer-brand-max: 380px;
    --adv-footer-top-pad-end: var(--adv-space-40);
    --adv-footer-bottom-pad: var(--adv-space-16);
    --adv-footer-bottom-gap: var(--adv-space-16);
    --adv-footer-city-gap: var(--adv-space-8);
  }
  /* .adv-band__split is a grid now — flex-direction would be silently ignored. */
  .adv-band__split,
  .adv-band__split--chips,
  .adv-band__split--cta,
  .adv-band__split--values { grid-template-columns: 1fr; gap: var(--adv-space-32); }
  /* A photo plate that keeps a 491/660 desktop height on a phone is a screen of
     photograph before any words; it becomes a band. */
  .adv-band__media,
  .adv-band__media--tall { min-height: 280px; }
  /* The chip column becomes a wrapping row above its panel, the way the services
     band already is at every width — one behaviour on a narrow screen, not two. */
  .adv-switch-chips { flex-direction: row; flex-wrap: wrap; gap: var(--adv-space-8); }
  /* And the services band gives back its 102. That number centres the panel on
     the photograph beside it; here the split has collapsed and the photograph is
     no longer beside anything, so it would just be 102px of air between the
     chips and their copy. Back to the stack rhythm the column already keeps. */
  .adv-switch-column:has(> .adv-switch-chips--row) { gap: var(--adv-stack-gap); }
  /* THE HOME LOCKUPS SHOW AT 402 NOW (1537:18130, 1537:19268 — ADR-0030
     Amendment 1 §7). Until the 1537 frames the hero wordmark and the city were
     hidden below 861 and the bar kept its own; now each Home opens on its large
     wordmark — a 295 × 118 tile, the 248 tile at 295 / 248, the 2.7452 mark
     inside it — and the observer, which only sees a DISPLAYED element, slides
     the bar's in on scroll here as well. */
  .adv-page-hero__wordmark {
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--adv-m-hero-logo-w);
    aspect-ratio: 248 / 99.2;
    padding: 0;
  }
  .adv-page-hero__wordmark img {
    width: calc(var(--adv-m-hero-logo-w) * 183.65 / 248);
    height: auto;
  }

  /* THE MASTER HOMEPAGE HERO AT 402 (1537:18130 — ADR-0030 Amendment 1 §7;
     it was ours, AD-137):

       - PULLED UNDER THE BAR AGAIN: the band starts at y=0 behind the
         transparent top bar and its surface runs 750 (a documented literal);
       - the wordmark tile centred, 71 from the top;
       - the headline centred at 38 / 600 on a 0.99 line box — Home only; every
         other 402 head keeps `--adv-m-hero-weight` — its first line ending on
         the accent phrase ("Find the right / legal expertise.");
       - the lede centred; then the two pills (the pill block below).

     The gaps are the frame's: 30 above the headline and the lede (both 30.4),
     63 above the pills. Weighted (0,2,0) so the ≤560 `.adv-page-hero` padding
     does not undo the 71. */
  .adv-page-hero.adv-page-hero--home {
    min-height: 750px;
    margin-block-start: calc(-1 * (var(--adv-m-header-h) + var(--adv-border-width)));
    padding: 71px var(--adv-m-margin) var(--adv-space-48);
  }
  /* ABOUT'S HERO STACKS (AD-138 — ours, no frame; ADR-0025 §9): the copy, then
     the photograph at the container's width with the plate radius on all four
     corners, in the band ratio this tier already gives a page photograph
     (402/388). Not pulled under the bar — the bar is opaque here, as on the
     homepage — and as tall as what it holds. */
  .adv-about-hero {
    flex-direction: column;
    align-items: stretch;
    gap: var(--adv-space-34);
    min-height: 0;
    margin-block-start: 0;
    padding-block: 54px 0;
  }
  .adv-about-hero__copy { width: auto; }
  .adv-about-hero__photo {
    position: static;
    height: auto;
    aspect-ratio: 402 / 388;
    border-radius: var(--adv-radius-band);
  }
  /* THE SATELLITE ABOUT KEEPS ITS 402 ORDER (760:16587): the title, the lede, the
     photograph in the 362 × 185 slot, then the buttons — so the copy column dissolves
     and the buttons step behind the photograph. 26 is the copy's own step (ours). */
  .adv-about-hero--sat { gap: var(--adv-space-26); padding-block-end: 0; }
  .adv-about-hero--sat .adv-about-hero__copy { display: contents; }
  .adv-about-hero--sat .adv-cta-row { order: 1; }
  .adv-about-hero--sat .adv-about-hero__photo { aspect-ratio: 362 / 185; }
  /* THE SATELLITE HOME AT 402 (1537:19268 top, 1537:19353 scrolled — ADR-0030
     Amendment 1 §7). One #F5F4F2 surface from y=0, the bar included (its filled
     top state): the lockup in flow — the 295 tile with the glyph on the 20
     margin, 72 from the top, the city (26 / 1.153) overlapping its foot at 160
     as on desktop — then the lede at 248, the two buttons side by side, and the
     photograph at 362 × 340 with the card radius (12, as drawn, not the band's
     24). The gaps are the frame's: 58, 20, 44.

     THE BUTTONS SIT SIDE BY SIDE WHILE THEY FIT and stack when a language's pair
     does not: each is at least its nowrap label, grows from the drawn 171, and
     the row wraps — never a clipped label or a sideways scroll (trap 11). The
     primary reads "Contact us" at ≤560, as drawn (`.adv-btn__label--narrow`). */
  .adv-about-hero--home {
    gap: 0;
    margin-block-start: calc(-1 * (var(--adv-m-header-h) + var(--adv-border-width)));
    padding-block: 72px 0;
  }
  .adv-about-hero--home .adv-hero-lockup { position: static; }
  .adv-about-hero--home .adv-page-hero__wordmark {
    margin-inline-start: calc(var(--adv-m-hero-logo-w) * (183.65 / 248 - 1) / 2);
  }
  .adv-hero-lockup__city {
    max-width: none;
    margin-block-start: -30px;   /* 1537:19312 at y=160, the tile's foot at 190 */
    padding-inline-start: 0;
    font-size: var(--adv-m-hero-city-size);
  }
  .adv-about-hero--home .adv-about-hero__copy {
    gap: var(--adv-m-stack-gap);
    margin-block-start: 58px;
  }
  .adv-about-hero--home .adv-cta-row {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: stretch;
    align-self: stretch;   /* the copy column is start-aligned; the halves need its width */
    gap: var(--adv-space-16) var(--adv-m-stack-gap);
  }
  /* Half the row each (171 at 402), with the label centred in it: the frame's
     27 of padding is what is left around its label in a fixed 171 box, so the
     button's own minimum keeps only 12 a side — "Find a legal expert" is 123 in
     the build's Inter. A label that does not fit its half wraps the pair. */
  .adv-about-hero--home .adv-cta-row .adv-btn {
    flex: 1 1 calc((100% - var(--adv-m-stack-gap)) / 2);
    width: auto;
    padding-inline: var(--adv-space-12);
  }
  .adv-about-hero--home .adv-about-hero__photo {
    margin-block-start: 44px;
    aspect-ratio: 362 / 340;
    border-radius: var(--adv-radius-card);
  }
  /* THE OFFICE BLOCK STACKS PHOTO FIRST (ours, ADR-0030 §10): the plate at the
     container's width, the office's lines 26 under it. */
  .adv-office-block { grid-template-columns: minmax(0, 1fr); row-gap: var(--adv-space-26); }
  .adv-page-hero--home .adv-page-title {
    max-width: none;
    margin-block-start: 30px;   /* 1537:18162 — the tile's foot to the headline */
    font-size: var(--adv-m-hero-size);
    font-weight: var(--adv-m-home-title-weight);
    line-height: var(--adv-m-home-title-lh);
  }
  .adv-page-hero--home .adv-page-title--accented em::after { content: "\A"; white-space: pre; }
  .adv-page-hero--home .adv-subtitle {
    margin-block-start: 30px;   /* 1537:18357 */
    font-size: var(--adv-m-lede-size);
  }
  .adv-page-hero--home .adv-hero-search { margin-block-start: 63px; }   /* 1537:18407 at y=437 */
  .adv-subtitle { line-height: var(--adv-m-lede-lh); }

  /* THE PILL STACKS (AD-137 — ours, no frame). 899 does not fold into 362, and
     dropping the two selects the way the satellite's 402 hero does would take
     the network's front door with them. So two rows on the same surface, edge
     and halo:

       - row 1: Office | Legal support, half each, joined into one pill by the
         second cell's hairline;
       - row 2: the field as its own pill, the navy disc 5 inside its end, at
         the tier's 56 search height.

     A grid rather than a wrap, so the halves are exact and the field spans
     both. The row stops being the painted pill; its three children take the
     paint instead. "Popular:" comes back (the base 860 rule hides it for the
     satellite) and wraps left-aligned under the field's text. */
  .adv-hero-search--pill .adv-hero-search__row {
    display: grid;
    /* `minmax(0, …)`: a picked long city must not widen its half. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    row-gap: 14px;   /* 1537:18407 — the filter pill to the field pill */
    height: auto;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
  }
  .adv-hero-search--pill .adv-filter-wrap,
  .adv-hero-search--pill .adv-hero-search__field {
    margin: 0;
    border: var(--adv-border-width) solid var(--adv-color-border);
    background: var(--adv-color-surface);
    box-shadow: var(--adv-shadow-search);
  }
  .adv-hero-search--pill .adv-filter-wrap:first-child {
    border-inline-end: 0;
    border-radius: var(--adv-radius-pill) 0 0 var(--adv-radius-pill);
  }
  /* Restated at the base's (0,3,0), which set this cell's gap and inset.
     THE TWO HALVES ARE ONE PILL (1537:18384): the divider between them is 48
     tall inside the 56, not a full-height edge — drawn by the right half, whose
     own left edge goes. */
  .adv-hero-search--pill .adv-filter-wrap + .adv-filter-wrap {
    margin: 0;
    padding-inline-start: 0;
    border-inline-start: 0;
    border-radius: 0 var(--adv-radius-pill) var(--adv-radius-pill) 0;
  }
  .adv-hero-search--pill .adv-filter-wrap + .adv-filter-wrap::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    inset-block-start: 50%;
    width: var(--adv-border-width);
    height: var(--adv-space-48);
    background: var(--adv-color-border);
    transform: translateY(-50%);
  }
  /* Labels 14 / 500, centred in their half with the caret 8 after them
     (1537:18393). A picked label longer than its half WRAPS inside it rather
     than widening the half: the hero script writes the toggle's first text node,
     so the label cannot be an ellipsizing box of its own without editing both
     MIRRORED blocks. */
  /* The pills are 56 OUTSIDE (1537:18384, 1537:18389): the controls inside
     their 1px edges are 54. They were 56 inside, which drew 58-tall pills. */
  .adv-hero-search--pill .adv-filter,
  .adv-hero-search--pill .adv-filter-wrap + .adv-filter-wrap .adv-filter {
    width: 100%;
    min-width: 0;
    height: calc(var(--adv-m-search-h) - 2 * var(--adv-border-width));
    gap: var(--adv-space-8);
    padding-inline: var(--adv-space-8);
    font-size: var(--adv-nav-small-size);
    line-height: var(--adv-nav-small-lh);
    white-space: normal;
    text-align: center;
  }
  /* Each half is its panel's minimum: the left one opens from its outer edge,
     the right one from its own right edge — anchored left it would run past a
     402 screen. The `:first-child` rule is restated at the desktop one's weight. */
  .adv-hero-search--pill .adv-filter-wrap .adv-filter-panel {
    inset-block-start: calc(100% + var(--adv-border-width) + var(--adv-space-12));
  }
  .adv-hero-search--pill .adv-filter-wrap:first-child .adv-filter-panel {
    inset-inline-start: calc(-1 * var(--adv-border-width));
    min-width: calc(100% + var(--adv-border-width));
  }
  .adv-hero-search--pill .adv-filter-wrap + .adv-filter-wrap .adv-filter-panel {
    inset-inline: auto calc(-1 * var(--adv-border-width));
    min-width: calc(100% + var(--adv-border-width));
  }
  .adv-hero-search--pill .adv-hero-search__field {
    grid-column: 1 / -1;
    padding-inline-start: var(--adv-space-26);
    border-radius: var(--adv-radius-pill);
    transition: border-color var(--adv-transition-fast) var(--adv-ease);
  }
  .adv-hero-search--pill .adv-hero-search__field:focus-within { border-color: var(--adv-hover-accent); }
  .adv-hero-search--pill .adv-search__field { height: calc(var(--adv-m-search-h) - 2 * var(--adv-border-width)); }
  .adv-hero-search--pill .adv-search__button {
    width: calc(var(--adv-m-search-h) - 2 * var(--adv-hero-pill-submit-inset));
    height: calc(var(--adv-m-search-h) - 2 * var(--adv-hero-pill-submit-inset));
  }
  /* "Popular:" is not drawn at 402 (1537:18130) — hidden at the pill's weight. */
  .adv-hero-search--pill .adv-hero-search__popular { display: none; }

  /* Buttons in a stack take the full measure — by now every 402 frame
     draws it (help 597:19882, About 623:23874, Join's intro anchor and
     submit): the scoping to one band was over-caution. */
  .adv-stack > .adv-btn { width: 100%; }
  /* …except the office page's "Visit local website ↗" under its identity, which keeps
     its own width on the left at every size (AD-200, ADR-0025 Amendment 25 §3, MD:
     "not full width"). */
  .adv-detail-head--office > .adv-stack > .adv-btn { width: auto; }
  /* .adv-stack aligns flex-start and shrink-wraps block children — grids
     and value lists inside it must claim the measure themselves. */
  .adv-stack > .adv-grid,
  .adv-stack > .adv-values { align-self: stretch; width: 100%; }
  /* Neither the "Popular:" line nor the practice-area filter chip exists in
     the satellite's mobile hero — Group 186 is one pill and one round button.
     (The master's pill drops it too since 1537:18130; see `.adv-hero-search--pill`
     in this block.) */
  .adv-hero-search__popular { display: none; }

  /* The services plate holds the frame's 362 × 271 slot (Rectangle 71 on
     597:19805) at every mobile width, photo or authored empty state —
     without a height the background-image plate collapses to nothing. */
  /* On mobile the service photograph moves INSIDE the panel — title,
     photo, copy (597:19862) — so the desktop plates column hides and the
     inline plate shows. Ratio, not fixed height: pinned at 271 the crop
     hardened as the measure grew. Radius is the mobile card 8. */
  .adv-band__plates { display: none; }
  .adv-band__media--inline {
    display: block;
    width: 100%;
    max-width: 100%;
    height: auto;
    min-height: 0;
    aspect-ratio: 362 / 271;
    border-radius: var(--adv-m-radius-card);
  }
  /* The handoff's band copy metrics: description 14/20 with the meta line
     in the primary blue ("7 experts · 3 offices"). */
  .adv-switch-panel__meta { color: var(--adv-color-primary); }
  .adv-switch-panel__text { line-height: 20px; }
  /* How we can help: the topics stack under the service's text (no frame between 561 and
     1439 — ADR-0038 §AD-162 §4). */
  .adv-help__panel { grid-template-columns: minmax(0, 1fr); row-gap: var(--adv-space-34); }
  /* Topics by practice area stacks too: its split is (0,2,0) above, so it needs its own —
     and its lead drops the 48 it keeps from the topics beside it (AD-164). */
  .adv-help--menu .adv-help__panel { grid-template-columns: minmax(0, 1fr); }
  .adv-help--menu .adv-help__lead { padding-inline-end: 0; }
  /* Help callout (Group 188): the title is 32/500 on the page surface —
     not the display 38. The band is on the page surface at every width
     (623:21979 and 1482:29871 both fill `background/main`), so there is no
     plate to undo here. */
  .adv-band--help .adv-h1 { font-size: 32px; font-weight: var(--adv-weight-medium); line-height: 1.1; }
  /* Stat tile (handoff Frame 42): 171 × 130 on the BRAND 12px radius —
     surface-alt fill, 1px border, 38/600 value over a 14/500 label, both navy.

     CENTRED, and the note here used to end "left-aligned" (AK, 2026-09-02).
     750:36026 settles it eight times over — every figure and every label in the
     2 × 2 is centred in its 171 tile to the half-pixel, and the arithmetic is
     the giveaway: "10+" is 70 wide at x=50.5 and (171 − 70) / 2 = 50.5;
     "Countries" 75 at 48; "7" 23 at 74; "Partner firms" 100 at 35.5; "85" 49 at
     61; "Legal experts" 104 at 33.5; "Practice areas" 110 at 30.5. Eight texts
     of eight different widths, every one exactly half the remainder from the
     edge. Ours had them all flush at x=21.

     `text-align` as well as `align-items`: the flex property centres the text
     BOX, and a label that wraps to two lines inside that box would still set
     ragged-right without it. */
  .adv-stat {
    border-radius: var(--adv-radius-card);
    background: var(--adv-color-surface-alt);
    border: var(--adv-border-width) solid var(--adv-color-border);
    /* 130 TALL, and it takes all three of these to get there. Both line heights
       below were `1` — the AUTO-read-as-1 slip, now corrected in five places —
       which alone cost 16px and left the tile at 114. With them right the column
       measures 46 + 8 + 25 = 79.

       The padding is 24.5 and not the frame's own 25.5 because `box-sizing` is
       border-box here (base.css) and the tile carries a 1px border: 24.5 × 2 +
       79 + 2 = 130. Written as 25.5 first and measured at 132, which is the
       border being paid for twice. `min-height` rather than `height` so a label
       that wraps — the German "Partnerkanzleien" is the near case — grows the
       tile instead of spilling out of it. */
    min-height: 130px;
    padding: 24.5px 20px;
    display: flex;
    flex-direction: column;
    gap: var(--adv-space-8);
    justify-content: center;
    align-items: center;
    text-align: center;
  }
  /* 46 TALL FOR A 38px FIGURE — 46/38 is 1.21, Inter's AUTO, which is what the
     frame's text box records (750:36030: "10+" at y=25.5, height 46). `1` was
     the literal reading of Figma's `leading: normal` and it clipped the tile by
     8px on this element alone. */
  .adv-stat__value {
    font-size: 38px;
    font-weight: var(--adv-weight-semibold);
    line-height: var(--adv-h1-lh);
    color: var(--adv-color-primary-dark);
  }
  /* 25 for a 14px label — the tier's own body step (--adv-m-body-lh), and the
     height every label box on 750:36026 carries. */
  .adv-stat__label {
    font-size: var(--adv-m-body-size);
    font-weight: var(--adv-weight-medium);
    line-height: var(--adv-m-body-lh);
    color: var(--adv-color-primary-dark);
  }

  /* THE SEARCH SCREEN'S FIELD IS THE SAME COMPONENT AT 402 (Group 186 —
     681:27546, the instance AK measured against; the satellite hero float,
     664:24579 of the same thing, retired in AD-145). Two things it was missing, both because the
     entry screen is new (896:9585) and picked up no mobile rule at all:

       - 56 tall, not the desktop 60. Every other search on the 402 tier is
         `--adv-m-search-h`; this one was the only 60 on the site.
       - THE DARK BORDER — `borders/dark` #3C3C3C, which is what AK reported
         missing. It is a genuine TIER difference and not an oversight in the
         desktop pass: 896:9585 binds `borders/light` on this same field at
         1440, and the 402 component binds dark.

     WHAT IT DOES NOT TAKE is the component's 70% ink wash. That fill is what
     makes the field readable ON A PHOTOGRAPH, and the entry screen no longer
     has one — on a plain surface it reads as a solid black pill rather than as
     a control. Dark border on the
     light surface is a sanctioned pairing; the token is named "Borders Dark"
     for exactly this. */
  .adv-search-entry .adv-search__field {
    height: var(--adv-m-search-h);
    border-color: var(--adv-color-border-strong);
  }
  .adv-search-entry .adv-search__button {
    width: var(--adv-m-search-btn);
    height: var(--adv-m-search-btn);
    border-color: var(--adv-color-border-strong);
  }

  .adv-cta-split { flex-direction: column; }
  .adv-rule { margin-inline-start: 0; }
  .adv-cta-split__media { flex-basis: auto; width: 100%; min-height: 320px; }
  .adv-card-row { flex-wrap: wrap; }
  .adv-card-row > * { flex-basis: calc(50% - var(--adv-card-gap) / 2); }
  .adv-insight { flex-direction: column; }
  .adv-insight__media { width: 100%; height: auto; aspect-ratio: 1; }

  /* The head's two columns stack: the lead belongs under its own title, not
     beside a title that has shrunk to fit half a phone. */
  .adv-page-head,
  .adv-cta-band__inner { grid-template-columns: 1fr; gap: var(--adv-space-24); }
  /* PHOTO FIRST in the CTA band (597:19945: Rectangle 71, 362 × 238, then
     the copy at y=262, then the full-measure button) — the image-last
     order that used to live here was authored under B2 and the frame
     refutes it. Sized as a ratio so it scales with the measure. */
  .adv-cta-band__media { order: -1; height: auto; aspect-ratio: 362 / 238; }
  .adv-cta-band .adv-btn { width: 100%; }
  /* NO BAND FILL ON A PHONE (681:26825, both tiers — ADR-0030 Amendment 1 §7).
     The block sits on the page in its rhythm: the photograph 54 under the block
     before it (the inner padding, unchanged), the button 72 above the footer
     (the frame's; the band's own margin is the page's section gap, so the
     padding is what is left of 72 — none at 561–860, where that gap is 96).
     The desktop band keeps its fill. */
  .adv-cta-band { background: none; }
  .adv-cta-band__inner { padding-block-end: max(0px, 72px - var(--adv-section-gap)); }
  /* THE PLATES KEEP THEIR DESKTOP HEIGHTS (TD-26, TD-31; ADR-0025 Amendments 11
     and 14, ADR-0030 Amendments 3 and 6). The ratio is the retired About band's
     (full-bleed 402 × 388, Rectangle 3 on 623:23434). It has the same weight as
     the plates' heights and comes later, so it turned the 1320 × 450 listing
     plate and the 1320 × 200 detail plate into squares here (808 × 780 at 860,
     against 809 × 450 and 809 × 200 at 861). No frame draws 561–860; MD chose the
     desktop heights, so only the width follows the page and 860 matches 861.
     Every band that renders is an inset plate, so the ratio reaches none of them
     now. At ≤560 both plates are hidden. */
  .adv-page-band { height: auto; aspect-ratio: 402 / 388; }
  /* 450 is the base `.adv-page-band` height — the listing plate's. */
  .adv-page-band--inset { height: 450px; aspect-ratio: auto; }
  /* The detail plate is inset too, so its own 200 comes after. */
  .adv-page-band--detail { height: 200px; aspect-ratio: auto; }
  .adv-detail,
  .adv-detail--3col { grid-template-columns: 1fr; }
  /* One column means the prose starts at the page margin, so the title that is
     level with it does too. Without this the h1 kept a 260 indent inside a 362
     content box and rendered at width 0 — present in the DOM, readable to a
     screen reader, invisible on the screen. */
  .adv-detail-head:not(.adv-detail-head--indent) > h1,
  .adv-detail-head.adv-detail-head--indent > h1,
  .adv-detail-head:not(.adv-detail-head--indent) > .adv-detail-head__chips,
  .adv-detail-head.adv-detail-head--indent > .adv-detail-head__chips { margin-inline-start: 0; }
  .adv-detail--3col > :last-child { grid-column: 1; }
  /* THE TOPIC RAIL'S LABEL IS BACK once the columns stack (ADR-0038 §AD-172 Amendment 1 §3,
     MD: "с заголовком"): above 860 the rail stands beside the text and has none (1734:30746).
     Stacked, the rail sits over the text at 561–860 and under it at ≤560 (AD-164), and a
     list of links in the page's flow needs its name. */
  .adv-detail--topic > .adv-detail__rail > .adv-section-label { display: block; }
  .adv-related { padding-block: var(--adv-space-60); }
  .adv-related__head { flex-direction: column; align-items: flex-start; }
  /* Stats take the full measure (750:36026: 171 × 130 tiles on a 20 gap
     across the 362): the base rule's 60px section padding is the desktop
     figure and left the grid lopsided against the 20px mobile margin. */
  .adv-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--adv-m-stack-gap);
    padding-inline: var(--adv-m-margin);
  }
  /* THE MASTER'S MID-WIDTH MODIFIERS STOP HERE (AD-140, TD-21): below 861 each
     of these is restated to exactly what it computed before them, so the 402
     and 860 pages do not move. */
  .adv-stats--fluid { --adv-stat-wrap: nowrap; }
  /* THREE TILES (AD-168): two columns here, so the third takes the second row's whole width
     rather than leaving half a row empty (ours: no 402 frame draws three). */
  .adv-stats--three > .adv-stat:last-child { grid-column: 1 / -1; }
  /* The split above goes to one column here, so the row has the whole measure
     again — and the ≤560 rules take over below 561. */
  .adv-values--fluid {
    --adv-value-cols: 38px 1fr 330px;
    --adv-value-text-col: auto;
    --adv-value-row-gap: 22px;
  }
  .adv-grid--wide.adv-grid--fluid { grid-template-columns: repeat(2, 1fr); }
  .adv-grid--fluid .adv-insight__body { min-width: auto; }
  .adv-grid--fluid :is(.adv-insight__title, .adv-insight__excerpt) { overflow-wrap: normal; }
  /* THE SATELLITE GIVES BETWEEN 561 AND 860 (TD-29, ADR-0030 Amendment 5). No frame draws
     this band (ADR-0017: developer discretion). The insight grid keeps its two columns. `.adv-grid--wide` pins the photograph at 335.42
     with two classes, so the one-class `width: 100%` above lost. Two photographs need 733,
     so /articles/ scrolled sideways below that (+176 at 561). The photograph now follows its
     column up to the same 335.42: `min()`, not `max-width`, so a column that holds 335.42
     computes exactly as before. The ≤560 block's photograph rule is later, at the same weight. */
  .adv-grid--fluid-mid .adv-insight__media { width: min(100%, 335.42px); }
  /* THE SATELLITE EXPERT PAGE IS ONE COLUMN (MD's call). Two tracks were 190 each at 561
     and 340 at 860. The name ran under the CTA, and the chips ran over the biography at
     every width of the band. This is the 402 order (704:30027): name, portrait, CTA, facts,
     biography. It keeps this tier's own measures: the 494 portrait, the desktop CTA and
     type, and the ≤1100 facts. The main column's grid values are restated to what they
     computed before, because it is `display: contents` from here down. */
  .adv-expert-detail--sat {
    display: flex;
    flex-direction: column;
    gap: var(--adv-m-band-gap);
  }
  .adv-expert-detail--sat .adv-expert-detail__main {
    grid-template-columns: minmax(0, 1fr) auto;
    row-gap: 58px;
  }
  .adv-expert-detail--sat :where(.adv-expert-detail__aside, .adv-expert-detail__main) { display: contents; }
  .adv-expert-detail--sat :where(.adv-expert-identity) { order: 1; }
  .adv-expert-detail--sat :where(.adv-expert-photo) { order: 2; }
  .adv-expert-detail--sat :where(.adv-expert-cta) { order: 3; align-self: flex-start; }
  .adv-expert-detail--sat :where(.adv-expert-facts) { order: 4; margin-block-start: 0; }
  .adv-expert-detail--sat :where(.adv-expert-bio) { order: 5; }
  /* …while the card grids keep theirs (AD-144): the two-up rows below are where
     a compound word breaks, so a Dutch or German name breaks at a syllable with a
     hyphen rather than at whichever letter hits the edge. Scoped by language
     because `hyphens: auto` also splits words that would have fit whole on the
     next line — harmless in the compounding languages, a visible change in EN
     and FR, which never needed a break here. The ≤560 block switches it off. */
  .adv-grid--long-words .adv-area-card__title:is(:lang(nl), :lang(de)) { hyphens: auto; }
  /* The count line starts where the number circle ends (26 inset + the 38
     circle + 8), so a long one ("11 experts · 2 vestigingen" is ~150 in a 183
     box beside a 38 circle) wraps under itself instead of running over the
     number. Right-aligned, so a count that fits on one line sits exactly where
     it did. */
  .adv-grid--long-words .adv-area-card__count {
    inset-inline-start: calc(var(--adv-space-26) + 38px + var(--adv-space-8));
    text-align: end;
  }
  .adv-approach__row { grid-template-columns: 1fr; gap: var(--adv-space-16); }
  .adv-approach__title { font-size: clamp(26px, 3.2vw, var(--adv-h1-size)); }
  .adv-page-title--sm { font-size: clamp(var(--adv-m-title-size), 4vw, var(--adv-display-size)); }
  /* The join title's 365 measure and 1.21 line box are a DESKTOP composition
     (385:4803). Below this step the head is one column at the page margin, so a
     365 cap would be a cap on nothing, and the 1.21 would make one screen's h1
     lead differently from every other. Both released back to the tier. */
  .adv-page-head--master .adv-page-title--sm {
    max-width: none;
    /* The token, NOT `inherit` — inherit would take the page head's 25px body
       leading and set a 38px title in it. */
    line-height: var(--adv-page-title-lh);
  }
  .adv-offices { grid-template-columns: 1fr; }
  /* ── THE MAP IS A 603 WINDOW ONTO A SQUARE THAT PANS (1605:21967/21968, AD-149 —
     ADR-0025 Amendment 19) ──────────────────────────────────────────────────────
     This band was "the map first and full-bleed at 402 × 400, the offices behind a
     'View as list' link as a popup over it" (812:8426, AK 2026-09-02; MD kept the popup
     on 2026-09-16). MD redrew it on 2026-09-20: the map is 603 tall and PANS sideways,
     the answer to a tapped mark is one card ON its foot, and there is no list here.

     The square is drawn at the WINDOW'S HEIGHT while the window is the page's width, so
     at 402 about a third of it is off screen and the reader travels across it. ADR-0025
     §5 is untouched: a native scroller over our own inlined SVG makes no third-party
     request, which is the test a tile map fails.

     THE TWO RULES ON ONE ELEMENT ARE NOW ONE. `.adv-offices__map` and `.adv-map` are the
     same node here, and the pair used to contradict itself — `height: 400px;
     aspect-ratio: auto` and then `height: auto; aspect-ratio: 1` twelve lines later, the
     second winning on source order, so the map was never the 400 the first one stated.

     ORDER and FULL BLEED are kept from that block: `order: -1` puts the map above the
     list (a grid item, so order drives auto-placement as it does in flex), and the
     negative inline margin cancels the band's 20 page margin — there are no corners left
     to round on a bleeding element. `width` is still STATED rather than left to `auto`:
     with a raster base this is an `<img>`, whose `auto` inline size resolves against the
     file's own ratio and lands 2px short of the bleed.

     603 is 1605:21968's height — a frame dimension written once as a literal with its
     node id, the convention this file follows for 660, 530 and 400. The width is
     definite, so `aspect-ratio` gives the square from 603 up to 860 and `min-height`
     holds the frame's 603 below it. */
  .adv-band--map .adv-offices__map {
    order: -1;
    margin-inline: calc(var(--adv-m-margin) * -1);
    width: calc(100% + var(--adv-m-margin) * 2);
    height: auto;
    aspect-ratio: 1;
    min-height: 603px;              /* 1605:21968 */
    border-radius: 0;
    /* What the lift reveals under the canvas: the map's own water, so the strip reads as
       sea rather than as the page showing through. `.adv-map__sea` is its only other
       consumer, which is the point — it is the same colour by construction. */
    background: var(--adv-color-surface-blue);
  }
  /* HORIZONTAL ONLY, AND NO `touch-action`. A native scroller already gives the
     horizontal axis to the map and leaves the vertical one to the page, which is exactly
     what was asked for — declaring `touch-action` would take the page's swipe away. The
     bar is hidden because it would sit across the south of Europe, and
     `overscroll-behavior-x` stops a pan at the east edge turning into the browser's back
     gesture. `grab` is for a mouse, which gets no native pan; site.js drags it.

     AND NOTHING IN HERE IS SELECTABLE. The only mouse gesture on this box is that pan,
     and without this a drag across a count bubble selects its digit and leaves the
     highlight behind on the map. Scoped to the SCROLLER, so the card and its selector —
     which live in the overlay, outside it — keep their text. */
  .adv-band--map .adv-map__scroller {
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    overscroll-behavior-x: contain;
    cursor: grab;
    user-select: none;
    -webkit-user-select: none;
  }
  .adv-band--map .adv-map__scroller::-webkit-scrollbar { display: none; }
  .adv-band--map .adv-map__scroller[data-dragging] { cursor: grabbing; }
  /* `min-width`, NOT `width: auto` + `aspect-ratio`. A block-level box's `auto` inline
     size is a STRETCH fit and an aspect ratio does not override it — the canvas would
     come out 402 wide with nothing to pan. The side is `max(window, 603)`, which is the
     window's own height, so the canvas stays square at every width in this block and the
     build-time projection holds without a line of script. */
  .adv-band--map .adv-map__canvas {
    width: 100%;
    min-width: 603px;               /* 1605:21968 */
    height: 100%;
    /* THE LIFT (site.js). Roma and Barcelona project to y ≈ 77–79%, which is under the
       card, so on a choice the canvas — marks and name pill with it — moves up until the
       chosen mark clears the overlay. A TRANSFORM rather than a scroll: the canvas is
       exactly as tall as the window, so there is no vertical overflow for `scrollTop` to
       use, and a transform cannot be fought by a focus-scroll onto a southern pin. No
       frame draws this; listed for the designer. */
    transform: translateY(calc(var(--adv-map-lift, 0px) * -1));
    /* The fast step, not a new duration: the lift is a correction to what the reader
       just tapped, not a reveal. Motion is the one group with no Figma value to read
       (ADR-0014 §6), so a third token here would be invention. */
    transition: transform var(--adv-transition-fast) var(--adv-ease);
  }
  /* ── THE CARD ON THE MAP'S FOOT AND ITS SELECTOR (1605:21976 / 1605:21989) ─────
     ONE ABSOLUTELY-POSITIONED COLUMN. The card's height is content-driven — a wrapped
     German name, a missing areas line — so the selector's 8 above it is a GAP and not an
     offset anything could compute. `pointer-events` is released on the box and taken
     back by its two children, so the gap between them is still map. */
  .adv-band--map .adv-map__overlay {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--adv-space-8);
    position: absolute;
    inset-inline: var(--adv-m-margin);
    inset-block-end: var(--adv-space-16);
    z-index: 1;
    pointer-events: none;
  }
  .adv-band--map .adv-map__overlay > * { pointer-events: auto; }
  /* 362 × ~164 at x=20. The frame leaves 15 above the map's bottom edge; taken as 16,
     the token, which is what the card this replaces (812:8513) was documented at —
     listed for the designer. THE SHADOW IS THE TOKEN: `--adv-shadow-menu` is
     `0 0 3px rgba(0,0,0,.08)`, exactly 1605:21976's, and the `0 0 5px` at 12% that used
     to sit on the row died with the rule that carried it.

     The radius is the literal 8 the frame draws, with the same reasoning the old rule
     carried: `--adv-radius-card` is 12, and a fill is what a reader sees. */
  .adv-band--map .adv-map__card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--adv-space-8);
    align-self: stretch;
    padding: var(--adv-space-24);
    border: var(--adv-border-width) solid var(--adv-color-border);
    border-radius: 8px;
    background: var(--adv-color-surface-alt);
    box-shadow: var(--adv-shadow-menu);
  }
  /* 22 REGULAR, capped at 276 so a long name does not run under the × (1605:21982).
     NOT the h3 token's Medium: the frame sets it Regular, which is one of the two text
     corrections in the client's 2026-09-20 note. */
  .adv-band--map .adv-map__card-name {
    margin: 0;
    max-width: 276px;
    font-family: var(--adv-font-heading);
    font-weight: var(--adv-weight-regular);
    font-size: var(--adv-h3-size);
    line-height: 1.21;
    color: var(--adv-color-ink);
  }
  /* 10 REGULAR in text/secondary (1605:21983/21984) — Medium until the same note.
     `--adv-color-body` IS #51595F, the token the frame names; not `--adv-color-ink-muted`
     (#797979), which is a different grey and would not hold up at this size. */
  .adv-band--map .adv-map__card-line {
    margin: 0;
    font-weight: var(--adv-weight-regular);
    font-size: var(--adv-caption-size);
    line-height: var(--adv-caption-lh);
    color: var(--adv-color-body);
  }
  /* THE WHOLE `areas` LIST ON ONE CLIPPED LINE. The frame shows two; cutting at two is a
     number we would be inventing (listed for the designer). */
  .adv-band--map .adv-map__card-areas {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* 14/25 Medium corporate blue with the 8px arrow 10 after it — the row link's look
     (1605:21986), 24 under the text group. The `::after` STRETCHES IT OVER THE WHOLE
     CARD: the client asked for a click anywhere on the card, and the × is a <button>,
     which cannot live inside an <a>. */
  .adv-band--map .adv-map__card-link {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-block-start: var(--adv-space-16);
    font-weight: var(--adv-weight-medium);
    font-size: var(--adv-m-body-size);
    line-height: var(--adv-m-body-lh);
    color: var(--adv-color-primary);
    text-decoration: none;
  }
  .adv-band--map .adv-map__card-link::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
  }
  /* 14 square at the card's own 24 inset (1605:21988), ABOVE the stretched link —
     otherwise closing the card navigates instead. */
  .adv-band--map .adv-map__card-close {
    position: absolute;
    inset-block-start: var(--adv-space-24);
    inset-inline-end: var(--adv-space-24);
    z-index: 1;
    padding: 0;
    border: 0;
    background: none;
    color: var(--adv-color-primary-dark);
    cursor: pointer;
  }
  .adv-band--map .adv-map__card-close .adv-icon { display: block; width: 14px; height: 14px; }
  /* 99 × 36 for "1 of 3", on the card's axis, in the card's own fill, ring and shadow
     (1605:21989). Centring is the column's `align-items`, so nothing here computes it. */
  .adv-band--map .adv-map__selector {
    display: flex;
    align-items: center;
    gap: var(--adv-space-16);
    padding: var(--adv-space-12) var(--adv-space-16);
    border: var(--adv-border-width) solid var(--adv-color-border);
    border-radius: var(--adv-radius-pill);
    background: var(--adv-color-surface-alt);
    box-shadow: var(--adv-shadow-menu);
  }
  .adv-band--map .adv-map__count {
    font-weight: var(--adv-weight-regular);
    font-size: var(--adv-caption-size);
    line-height: var(--adv-caption-lh);
    color: var(--adv-color-ink);
  }
  /* THE DRAWN CHEVRON IS 4 × 8; THE HIT AREA IS NOT. A 4-wide target fails the touch
     minimum, so the button is 24 square with the glyph centred — and NEGATIVE MARGINS ON
     BOTH AXES give the pill back every pixel of the difference, so the drawn geometry is
     the frame's and only the reachable geometry is ours. Without the inline pair the pill
     measured 140 where 1605:21989 draws 99: 16 + 4 + 16 + "1 of 3" + 16 + 4 + 16 = 99,
     and a 24-wide button spends 20 more on each side. The touch target still overlaps the
     pill's padding and the gap, which is exactly what that space is for. */
  .adv-band--map .adv-map__step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    margin-block: -6px;
    margin-inline: -10px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--adv-color-ink);
    cursor: pointer;
  }
  .adv-band--map .adv-map__step .adv-icon--chevron { display: block; width: 4px; height: 8px; }
  .adv-band--map .adv-map__step--next .adv-icon--chevron { transform: rotate(180deg); }
  /* NO LIST AT THIS WIDTH, WHEREVER THE CARD REPLACES IT (MD, 2026-09-20). The answer is
     the card on the map, and on the Offices listing the search and the Country facet act
     on the MARKS. Gated on nothing the SCRIPT writes, so it holds in the FIRST painted
     frame — the bundle link is render-blocking and site.js is deferred, so a rule that
     waited for the script would paint six rows of address, phone and VAT and then blank
     them. Undone for a reader with no script by head.html's <noscript><style>, who has no
     mark to tap. An office with no pin cannot be reached here (MD's call; the build
     warning in offices-map.html is the signal).

     BUT ONLY WHERE THERE IS A CARD. `offices-map.html` has three modes and only `pins`
     draws marks, a scroller and the overlay; `provider` (a static map from a key) and
     `fallback` emit a bare `<img class="adv-offices__map">` with nothing on it to tap.
     Hiding the list in those modes would leave the band an image and NO offices at all,
     so the rule asks for the overlay — markup, not script, so the first frame is still
     right. The no-map-at-all case is already answered by the `:not(:has(…))` rule beside
     the desktop list; the provider `<img>` carries that class, so it is not.

     `:where()` KEEPS THIS AT (0,2,0). head.html's noscript rule is (0,2,0) and beats this
     one on SOURCE ORDER; a `:has()` counted into the weight would silently outrank it and
     take the no-script list away again. */
  .adv-band--map:where(:has(.adv-map__overlay)) .adv-offices__list { display: none; }
  /* 24 UPPERCASE, where every other label on this tier is 16 (812:8437: Inter
     Medium 24, burgundy, box 29 tall at x=20). It is not a general step change —
     "Our values", four screens up the SAME frame, is 16 and stays 16 — so this
     is the map header being a header rather than an eyebrow, and it is scoped to
     the band that owns it. */
  .adv-band--map .adv-section-label {
    font-size: 24px;
    line-height: 1.21;
  }
  /* THE LABEL ALONE, 24 down to the map rather than the desktop 60. This row used to
     hold "View as list" beside the label, baseline-aligned (812:8426: the label's 29 box
     at y=0, the link's 25 box at y=2); AD-149 deleted that control, and the
     `justify-content` and `gap` that placed it went with it — both are inert on a single
     flex item. `display: flex` stays so the label keeps the block's own box. */
  .adv-band--map .adv-offices__head {
    display: flex;
    align-items: baseline;
    margin-block-end: var(--adv-m-head-gap);
  }
  .adv-search-results { grid-template-columns: 1fr; gap: var(--adv-space-40); }
  /* ONE COLUMN, AND THE TRACK HAS TO SAY SO (AK, 2026-09-02). The desktop rule
     is a grid of fixed 475px columns now; below this step the container is
     narrower than one of them, and `width: 100%` on a card inside a 475px track
     is 475 — the row would overflow the page rather than fit it. The four
     result kinds each restate `display: flex` at the 402 step for their own
     rails and stacks, but the master's firms group does not, and neither did
     anything between 402 and 860. */
  .adv-result-cards { grid-template-columns: 1fr; }
  .adv-result-cards > * { width: 100%; }
  .adv-split-media { grid-template-columns: 1fr; grid-template-rows: auto auto auto; }
  .adv-split-media__head,
  .adv-split-media__media,
  .adv-split-media__body { grid-column: 1; }
  .adv-split-media__head { grid-row: 1; }
  .adv-split-media__media { grid-row: 2; }
  .adv-split-media__body { grid-row: 3; }
  /* The contact person heads the stack; the thank-you replaces the head. */
  .adv-contact__person { grid-row: 1; grid-column: 1; }
  .adv-split-media--expert .adv-split-media__head { grid-row: 2; }
  .adv-contact__success { grid-column: 1; grid-row: 1; }
  .adv-contact--sent .adv-contact__photo--sent { grid-row: 2; min-height: 238px; }
  .adv-contact--sent .adv-contact__success { margin-block-start: 0; }
  .adv-contact--expert.adv-contact--sent .adv-contact__success { grid-row: 2; margin-block-start: 0; }
  .adv-contact--sent,
  .adv-contact--expert.adv-contact--sent { padding-block: var(--adv-space-60); }
  .adv-split-media--master { padding-block-end: var(--adv-space-60); }
  .adv-breadcrumbs--bare { padding-block-start: var(--adv-space-32); }
  .adv-split-media { padding: var(--adv-space-60) var(--adv-space-26); }
  .adv-split-media__media { min-height: 320px; }
  .adv-listing { gap: 54px; padding-block: 54px; }  /* the listing stack runs on 54 (AK) */
  .adv-listing--careers .adv-pagination { margin-block-start: 0; }
  .adv-controls { justify-content: stretch; }
  .adv-controls .adv-search { max-width: none; flex-basis: 100%; }

  /* LISTING CONTROLS (704:28477 / handoff mobile-practice-areas): the
     search is the LIGHT 56px pill — surface fill, 1px border — and the row
     beneath it is text: "Filters" left, the sort (where a listing has one)
     right. Search first: the markup keeps the trigger before the form for
     the sheet's focus order, so flex order flips them visually.

     "BARE MAGNIFIER ON ITS TAIL" WAS WRONG, and this note said it while the
     rule below stripped the ring to match (AK, 2026-09-02). 664:24580 draws
     the tail as its own 56px circle: `background/main` fill, the same 1px
     `borders/light` ring as the field, `rounded-[70px]`. Reported on the
     practice-areas listing and true of every screen that draws this control,
     because they all render the one component. */
  .adv-controls { display: flex; flex-direction: column; gap: var(--adv-space-16); }
  .adv-controls .adv-search { order: -1; }
  /* THE CONTROL IS 56 AT THIS STEP WHEREVER IT IS DRAWN, and the field's tail
     has to shrink with it. The base rule pulls the tail 60 under the button
     because the button is 60 on the desktop; at 56 the field runs FOUR PIXELS
     past the circle and its pill cap pokes out to the right of the ring.

     NOT SCOPED TO `.adv-controls` ANY MORE (AK, 2026-09-02, on the search page).
     Scoped, it reached the listings and nothing else, and this component is
     rendered from three different places: the listings put it inside
     `.adv-controls`, the search ENTRY screen inside `.adv-search-entry`, and the
     search RESULTS screen straight into `.adv-listing__controls`. So the entry
     screen kept the 60 tail against a 56 button — the four pixels, visible — and
     the results screen stayed 60 tall while every other mobile search was 56.
     One component, one size; the fill and ink stay scoped below, because those
     really are the listing's. */
  .adv-search__field {
    height: var(--adv-m-search-h);
    margin-inline-end: calc(var(--adv-m-search-btn) * -1);
  }
  .adv-search__button {
    width: var(--adv-m-search-btn);
    height: var(--adv-m-search-btn);
  }
  .adv-controls .adv-search__button {
    background: var(--adv-color-surface);
    color: var(--adv-color-ink);
  }

  /* THE FILTERS BECOME A NAVY SHEET (681:26618 / 681:26727) — the menu
     sheet's surface and chrome. Level 1: facet groups as plain white
     rows. Level 2 (a panel open): tickbox rows — the box is drawn by
     ::before off aria-selected — with the back arrow shown by JS. The
     bottom pair are the kit's two short buttons: Clear and the live
     "Results (N)", which closes the sheet (apply is instant, so the
     count is always current). */
  .adv-controls .adv-sort { display: block; }
  /* The head's sort has left for the 402 row (`placeSort()`); a grid with an
     empty second track would still reserve its gap. */
  .adv-results-head--sorted { display: flex; }
  /* "View as" is desktop-only (AD-148, ADR-0025 Amendment 18): below 860 the page is the
     grid it always was, and the engine never sets the list modifier here. */
  .adv-results-head .adv-view { display: none; }
  .adv-filters-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    align-self: stretch;
  }
  .adv-sort__toggle {
    height: auto;
    min-height: var(--adv-m-touch-min);
    padding: 0;
    border: none;
    background: transparent;
    color: var(--adv-color-ink);
    font-size: var(--adv-m-body-size);
    line-height: var(--adv-m-body-lh);
  }
  .adv-filters-open {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    gap: var(--adv-space-8);
    min-height: var(--adv-m-touch-min);
    padding: 0;
    border: none;
    background: transparent;
    color: var(--adv-color-primary-dark);
    font-weight: var(--adv-weight-medium);
    font-size: var(--adv-m-body-size);
    line-height: var(--adv-m-body-lh);
    cursor: pointer;
  }
  .adv-filters-open .adv-icon--caret { display: none; }
  /* THE COMPOSITE PANEL STACKS BELOW THE SHEET BREAKPOINT (AK, 2026-09-01).
     `--columns` is 529:12362's desktop shape — two columns 42 apart — and the
     sheet is 402 wide: measured, the panel came out 413 with its value column
     ending 31px past the screen edge. Stacked, the axes sit above the values,
     which is the same two-step the sheet already asks of every other facet.

     IN THE SHEET IT IS NO LONGER A PANEL AT ALL (AD-185): the axes are rows of
     the group list — see `--flat` at the end of the sheet's rules. This stacked
     form is what a composite opened from its PILL gets between 561 and 860, the
     one case left where the pill is on screen below the sheet breakpoint: none
     today, since the sheet carries every listing's facets. */
  .adv-filter-panel--columns { flex-direction: column; gap: var(--adv-m-stack-gap); }
  /* Stacked, the columns are no longer side by side, so there is nothing for a
     per-column scroller to preserve — two independently scrolling boxes one
     above the other is worse than the one scroll the sheet already gives every
     other facet. The panel takes it back. */
  .adv-filter-panel--columns > .adv-filter-panel__col,
  .adv-filter-panel__pane > .adv-filter-panel__col { overflow: visible; }
  .adv-filter-wrap .adv-filter-panel--columns { overflow-y: auto; }
  .adv-filter-panel__pane { min-width: 0; }
  .adv-controls__filters {
    display: none;
    position: fixed;
    inset: 0;                                   /* the frame covers the WHOLE screen, bar included */
    z-index: calc(var(--adv-z-header) + 1);
    flex-direction: column;
    /* `nowrap`, AND IT IS A BUG FIX, NOT TIDYING (AK, 2026-09-03: a long list
       breaks into a second column). The desktop rule this overrides is a
       WRAPPING row (`flex-wrap: wrap` at the top of the file) and only the
       direction was restated here — so the sheet stayed a wrapping flex
       container that had merely turned vertical, and `inset: 0` gave it a
       definite height to wrap against. Practice area's 22 options overflowed
       that height and the remainder started a new column beside it, which is
       exactly what `flex-wrap: wrap` is for and exactly not what a sheet
       wants. */
    flex-wrap: nowrap;
    align-items: flex-start;
    gap: 0;
    padding: 0 var(--adv-m-margin) var(--adv-space-40);
    background: var(--adv-color-hero-navy);
    overflow-y: auto;
  }
  .adv-controls__filters.is-open { display: flex; }
  .adv-filters-bar {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    align-self: stretch;
    min-height: var(--adv-m-header-h);
    margin-inline: calc(-1 * var(--adv-m-margin));
  }
  /* The sheet's bar is the site bar's (88, the 59.3 wordmark — 1537:19420). */
  .adv-filters-logo { height: var(--adv-m-logo-h); filter: brightness(0) invert(1); }
  .adv-filters-close {
    position: absolute;
    inset-inline-end: calc(var(--adv-m-margin) - 12px);
    top: 34px;   /* on the site bar's burger line (1537:19420), as the toggle's X is */
    transform: translateY(-50%);
  }
  /* The SAME crossed 20px bars the open menu toggle draws. */
  .adv-filters-x,
  .adv-filters-x::before,
  .adv-filters-x::after { display: block; width: 20px; height: 2px; }
  .adv-filters-x { position: relative; background: transparent; }
  .adv-filters-x::before,
  .adv-filters-x::after {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    background: currentColor;
  }
  .adv-filters-x::before { transform: rotate(45deg); }
  .adv-filters-x::after { transform: rotate(-45deg); }
  .adv-filters-head {
    display: flex;
    align-items: center;
    gap: var(--adv-space-12);
    align-self: stretch;
    padding-block: var(--adv-space-24) var(--adv-space-12);
  }
  .adv-filters-title {
    flex: 1;
    font-size: var(--adv-m-label-size);
    font-weight: var(--adv-m-label-weight);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--adv-color-on-navy);
  }
  .adv-filters-head { display: flex; }
  .adv-filters-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--adv-m-touch-min);
    height: var(--adv-m-touch-min);
    border: none;
    background: none;
    color: var(--adv-color-on-navy);
    font-size: 24px;
    cursor: pointer;
  }
  /* Level 1 — the facet groups as rows; a group's own panel replaces the
     dropdown entirely. */
  .adv-controls__filters .adv-filter-wrap { align-self: stretch; }
  .adv-controls__filters .adv-filter {
    width: 100%;
    justify-content: flex-start;
    height: auto;
    min-height: var(--adv-m-touch-min);
    padding: 9.5px 0;
    border: none;
    border-radius: 0;
    background: none;
    color: var(--adv-color-on-navy);
    font-size: var(--adv-m-row-size);
    line-height: var(--adv-m-body-lh);
  }
  /* ── AN ACCORDION, NOT A DRILL-DOWN (AK, 2026-09-02) ─────────────────────
     A DEPARTURE FROM 681:26727, and a deliberate one. The frame draws the sheet
     as two levels: tapping a group replaced the list with that group's options
     and a back arrow returned you. This block used to implement it — the rule
     here hid every sibling group, and the open group's row restyled itself into
     the uppercase title of the screen it had become.

     AK's call is that the groups EXPAND IN PLACE instead. The reader keeps the
     whole set of axes in view while choosing along one of them, which on a
     four-facet listing is the difference between filtering and navigating; and
     the back arrow stops existing, because there is nowhere to go back FROM.

     What made this cheap is that the panel was already `position: static` and
     full-width — the drill-down was never a different LAYOUT, only two rules
     hiding the rest of the sheet. Both are gone; the row keeps its shape and the
     caret turns to say which way the list is going.

     Still one group at a time: `disclosure()` closes a panel on any click
     outside it, and another group's row is outside it, so opening the second
     closes the first without a line of accordion code. */
  /* The caret goes to the ROW'S END — these rows are full-width and start-aligned,
     unlike the desktop pill where the glyph follows the label.

     AND IT IS NOT ROTATED HERE. The turn is already global: `.adv-icon--caret` is
     drawn 180° (the asset points up) and `[aria-expanded="true"] > .adv-icon--caret`
     returns it to 0. A rule in this block restating `rotate(180deg)` for the open
     state was (0,3,0) and beat that, so the caret stopped flipping and BOTH rows
     pointed down — written while adding the accordion and caught by measuring the
     computed transform, which read the same matrix on the open and closed row. */
  .adv-controls__filters .adv-filter .adv-icon--caret { margin-inline-start: auto; }
  /* The open panel is part of the sheet, not a dropdown.

     THE OPEN GROUP IS THE SCROLLER (AK, 2026-09-03). The dropdown's own 320 cap
     was removed here for a good reason — Topic's eight options came out six
     visible in a fixed box, with a hidden scrollbar, inside a sheet that had
     room to spare — but "let the SHEET take the overflow" only holds while the
     list is short enough to fit. Practice area has 22 options, which is taller
     than the screen, and scrolling the sheet to reach them takes the axis rows
     and the Clear / Results buttons off with it.

     So the group claims the space that is left and scrolls INSIDE it: the bar,
     the other axes and the actions stay put, and the reader keeps the sheet's
     shape while running down one list. Not a fixed max-height — the remainder
     depends on how many axes the screen has, which the sheet knows and a number
     here would not.

     `min-height: 0` on both is the part that is easy to omit: a flex item's
     automatic minimum is its content, so without it the wrapper refuses to be
     smaller than 22 rows and the overflow moves back out to the sheet. */
  .adv-controls__filters .adv-filter-wrap { min-height: 0; }
  .adv-controls__filters .adv-filter-wrap:has(.adv-filter[aria-expanded="true"]) {
    display: flex;
    flex-direction: column;
    /* SHRINK-ONLY (`0 1 auto`), not `1 1 auto`. Grow puts the leftover space
       INSIDE the open group whatever its length, so Country's five options came
       out in a 321-tall box with an empty tail and the axes below it pushed down
       for no reason. Shrink-only leaves a short list at its natural height and
       only compresses one that does not fit — which is the only case that wants
       a scrollbar. */
    flex: 0 1 auto;
    min-height: 0;
  }
  .adv-controls__filters .adv-filter-panel {
    position: static;
    width: 100%;
    max-height: none;
    flex: 0 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: var(--adv-space-8) 0 var(--adv-space-16);
    border: none;
    border-radius: 0;
    background: none;
    box-shadow: none;
  }
  /* The stepped composite's axes-only inset (529:10775) is a dropdown's; in the
     sheet it would indent the axes 26 past every other row. Same weight, later. */
  .adv-controls__filters .adv-filter-panel--stepped:not([data-axis-open]) {
    min-width: 0;
    padding: var(--adv-space-8) 0 var(--adv-space-16);
  }
  .adv-controls__filters .adv-filter-panel__row {
    display: flex;
    align-items: center;
    gap: var(--adv-space-12);
    width: 100%;
    min-height: 41px;              /* the frame's own pitch — 25 rows on 41 */
    padding: 0;
    border: none;
    background: none;
    color: var(--adv-color-on-navy);
    font-size: var(--adv-m-row-size);
    line-height: var(--adv-m-body-lh);
    text-align: start;
    cursor: pointer;
  }
  /* TICKBOXES (681:26727) — the drawn box is 16 here against the desktop 19,
     and checked FILLS rather than drawing a check, on the navy sheet's inverse
     ink.

     THE BOX IS THE `.adv-tick` ELEMENT, not a pseudo-element on the row. It was
     a `::before` until 2026-08-31, and that was a second mechanism for a thing
     the markup already had: the search screen's facets have carried a real
     `.adv-tick` since they were built, and they render inside THIS sheet on
     mobile — so every row there drew two boxes, the pseudo-element's and its
     own. Nobody had looked at that screen at 402 with a facet open. The
     listings' rows now carry the same element (see listing-controls.html), so
     one rule dresses both and the duplicate cannot come back. */
  .adv-controls__filters .adv-tick {
    width: var(--adv-m-tick-box);
    height: var(--adv-m-tick-box);
    border-radius: var(--adv-m-tick-radius);
    background: transparent;
    box-shadow: inset 0 0 0 var(--adv-border-width) var(--adv-color-on-navy);
  }
  .adv-controls__filters .adv-filter-panel__row[aria-selected="true"] .adv-tick {
    box-shadow: inset 0 0 0 2px var(--adv-color-hero-navy);
    background: var(--adv-color-on-navy);
  }
  /* The two rules that hid the desktop check glyph are gone: there is no check
     glyph any more, on either tier (529:12257 — see `.adv-tick`). The 402 sheet
     still differs in two real ways, which is why it keeps its own rules above:
     the box is 16 rather than 19, and it fills EDGE TO EDGE on the navy sheet
     instead of holding a 13px core, because the sheet's inverse ink is the fill
     and there is no second colour to inset against. */
  /* No search inside the sheet's groups (AK; the frames draw none). */
  .adv-controls__filters .adv-filter-panel__search { display: none; }
  .adv-controls__filters .adv-filter-panel__none { color: var(--adv-color-on-navy); }
  /* The bottom pair — the kit's two 171 shorts with 20 between; sticky at
     the sheet's foot. */
  .adv-filters-actions {
    display: flex;
    gap: var(--adv-m-stack-gap);
    align-self: stretch;
    margin-block-start: auto;
    padding-block-start: var(--adv-space-24);
  }
  .adv-filters-actions .adv-btn { flex: 1; }
  /* "MORE FILTERS" DISSOLVES INTO THE SHEET (AD-185; ADR-0025 Amendment 24 §3, ADR-0030
     Amendment 17 §1). MD, 2026-10-05: the axes behind "More filters" become rows of their
     own, as 704:29287 lists them (Office · Practice area · Service · Language), with the
     sheet's own chevrons, indent and "Clear" / "Results (n)" kept (681:26727).

     The shell in site.js ("Mobile filter sheet") marks a composite panel `--flat` below
     860, shows it, and moves each axis's value column to just under its axis button —
     INSIDE the panel, so the engine's one binding, the axis counts and the URL keys are
     untouched. Here the composite's pill leaves the list; each axis button takes the
     level-1 row of Office (the 44 touch row, 9.5 inset, the 14/25 Medium row type, the
     caret at its end, turned by the global `[aria-expanded]` rule); an open column takes
     an open group's panel (8 / 16 inset, the tick rows on their pitch). The pane — the
     one search field, which the sheet hides anyway — has nothing left to show.

     THE OPEN COLUMN IS THE SCROLLER, as for a plain group (AK, 2026-09-03): the wrap,
     the panel and the axis column shrink as one flex chain with `min-height: 0`, so a
     long Service list scrolls in place and the other axes and the actions stay put.
     Closed, the composite is its rows' height and does not shrink (`.adv-filter-wrap`'s
     own `flex-shrink: 0`). Three classes at least, over the stepped inset (0,3,0). */
  .adv-controls__filters .adv-filter-wrap:has(> .adv-filter-panel--flat) > .adv-filter { display: none; }
  .adv-controls__filters .adv-filter-wrap:has(> .adv-filter-panel--flat [aria-expanded="true"]) {
    display: flex;
    flex-direction: column;
    flex: 0 1 auto;
    min-height: 0;
  }
  .adv-controls__filters .adv-filter-wrap > .adv-filter-panel--flat {
    gap: 0;
    min-width: 0;
    padding: 0;
    overflow: hidden;
  }
  .adv-controls__filters .adv-filter-panel--flat > .adv-filter-panel__col {
    gap: 0;
    flex: 0 1 auto;
    min-height: 0;
    overflow: hidden;
  }
  .adv-controls__filters .adv-filter-panel--flat > .adv-filter-panel__pane { display: none; }
  /* The row's inset is Office's 9.5: the 44 touch row less the 25 line, halved. Its count
     is "Service (1)" with the one space Office's text node carries — the slot's leading
     space is kept rather than spent on a flex gap. */
  .adv-controls__filters .adv-filter-panel--flat .adv-filter-panel__row[data-axis] {
    flex: none;
    gap: 0;
    min-height: var(--adv-m-touch-min);
    padding: calc((var(--adv-m-touch-min) - var(--adv-m-body-lh)) / 2) 0;
    color: var(--adv-color-on-navy);
    font-weight: var(--adv-weight-medium);
  }
  .adv-controls__filters .adv-filter-panel--flat [data-axis-count] { white-space: pre; }
  /* The chevron takes the row's ink, as Office's does (`.adv-filter .adv-icon--caret`): the
     shared caret's own colour is the header's grey, which read as a disabled row on navy. */
  .adv-controls__filters .adv-filter-panel--flat .adv-filter-panel__row[data-axis] .adv-icon--caret {
    margin-inline-start: auto;
    color: currentColor;
  }
  .adv-controls__filters .adv-filter-panel--flat .adv-filter-panel__col[data-axis-values] {
    gap: var(--adv-space-12);
    flex: 0 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: var(--adv-space-8) 0 var(--adv-space-16);
  }

  /* CLOSING CTA (597:19944 — "Tell us what you need…"): the photograph
     LEADS — 362 × 238 at the mobile radius — then the statement, then the
     full-measure filled button. This block is sections/contact.html
     (.adv-switch-panel--cta + .adv-band__media--tall), NOT .adv-cta-band,
     which is a different composition — the first fix landed on the wrong
     section and this one is scoped to the right markup. */
  .adv-band__split:has(.adv-switch-panel--cta) .adv-band__media--tall {
    order: -1;
    min-height: 0;
    height: auto;
    aspect-ratio: 362 / 238;
    border-radius: var(--adv-m-radius-card);
  }
  /* The desktop plate's 625 and its right alignment do not survive one column
     (AD-137): restated at the base rule's weight, later. */
  .adv-band__split:has(> .adv-switch-panel--cta) > .adv-band__media--tall {
    justify-self: stretch;
    width: auto;
  }
  .adv-switch-panel--cta .adv-btn { width: 100%; }
}

/* THE LIFT STAYS, only the travel to it goes. A mark sitting under the card is not
   decoration — without the lift the reader cannot see what they just chose. site.js
   makes the same call for the horizontal scroll.

   AT THE SAME WEIGHT AS THE RULE IT UNDOES, AND AFTER IT. The transition is declared
   on `.adv-band--map .adv-map__canvas` inside the 860 block (0,2,0); a bare
   `.adv-map__canvas` in a `prefers-reduced-motion` block loses to it on SPECIFICITY,
   which no amount of ordering fixes and which a media query does not change. So this
   restates the same selector and the same width, later — this file's own mechanism,
   the one the noscript block in head.html uses. */
@media (max-width: 860px) and (prefers-reduced-motion: reduce) {
  .adv-band--map .adv-map__canvas { transition: none; }
}

@media (max-width: 560px) {
  /* THE MOBILE RHYTHM (ADR-0017 §3, read off 597:19805's band stack):
     bands sit 34 apart and pad 34 — the desktop 96 — and the 26 stack
     steps to 20. Remapped on the tokens, like the 860 type step, so every
     consumer moves at once; the frame's own numbers are --adv-m-band-gap
     and --adv-m-stack-gap. */
  /* The rails scroll; the PAGE does not — and no scrollbar is drawn
     (597:19805 shows none). */
  html { overflow-x: clip; }
  .adv-card-row,
  .adv-switch-chips,
  .adv-switch-chips--row { scrollbar-width: none; }
  .adv-card-row::-webkit-scrollbar,
  .adv-switch-chips::-webkit-scrollbar { display: none; }

  :root {
    --adv-section-gap:   var(--adv-m-band-gap);
    --adv-section-pad-y: var(--adv-m-band-gap);
    --adv-stack-gap:     var(--adv-m-stack-gap);
    --adv-card-gap:      var(--adv-m-stack-gap);
    /* EVERY page margin is 20 (conflict 1) — remapped on the token so the
       containers that pad with section-pad-x directly (hero intro, stats,
       band inners, anything not in the explicit list below) all move at
       once. --adv-space-26 is NOT remapped: it is also the buttons' inline
       padding, which the kit keeps at 26 (597:19957). */
    --adv-section-pad-x: var(--adv-m-margin);
    /* EVERY page title is 38 (ADR-0017 §3 — the display end lands on one
       number). The clamps already floor at 38; remapping the maxima too
       catches any consumer reading the display variables directly. Large
       card titles take the 22 step the same way. */
    --adv-display-size:    var(--adv-m-title-size);
    --adv-page-title-size: var(--adv-m-title-size);
    /* THE LEADING HAD TO COME WITH IT (AK, 2026-09-02). The size was remapped
       here and the leading was not, so a 38px mobile title ran on the desktop
       1.21 and drew 46px lines where 664:24486 and 681:27071 both draw 42 —
       `--adv-m-title-lh` has said 1.1 since the token was written and nothing
       consumed it. Only `--adv-page-title-lh` is remapped: `--adv-display-lh`
       feeds the closing band's headline too, and the frame keeps THAT at 1.21
       (704:27713 — 92px for two lines). */
    --adv-page-title-lh:   var(--adv-m-title-lh);
    --adv-card-title-size: var(--adv-m-card-title);
  }

  /* Card rows become horizontal RAILS (Frame 223 on 597:19805): the 402
     homepage scrolls its firm cards sideways at the short 320 width —
     stacking them was the B2-era guess. Full-bleed scroll, the page
     margin as inline padding, snap to card starts. */
  .adv-card-row {
    flex-wrap: nowrap;
    overflow-x: auto;
    margin-inline: calc(-1 * var(--adv-m-margin));
    padding-inline: var(--adv-m-margin);
    gap: var(--adv-m-stack-gap);
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
  }
  .adv-card-row {
    scroll-padding-inline-start: var(--adv-m-margin);
    gap: var(--adv-m-band-gap);   /* the firm rail runs on a 34 gap (handoff) */
  }
  .adv-card-row > * {
    flex: 0 0 270px;   /* the rail card (664:24714 / handoff MobileFirmCard, 270 × 349) */
    scroll-snap-align: start;
  }
  /* The mobile firm card KEEPS its panel — the kit symbol (664:24714)
     draws Rectangle 117 behind the text, so the card's own fill, border
     and 8px clip stay; the design agent's unpanelled reading is the
     outlier and the file wins (AK confirmed on device). Photo 270 × 150
     (Rectangle 118); content inset 18/24; the DESKTOP panel's 309px
     min-height and space-between spread are what opened the hole between
     the place line and the tags — the frame's own gap is 46. */
  .adv-card-row { align-items: flex-start; }
  .adv-card-row > * { min-width: 0; }   /* min-width:auto let min-content push past the 270 basis */
  .adv-firm-card__media { height: 150px; }
  .adv-firm-card__panel {
    justify-content: flex-start;
    gap: 46px;                /* place → tags (664:24714: 221 → 267) */
    min-height: 0;
    padding: 18px 24px;
  }
  .adv-firm-card__name { font-weight: var(--adv-weight-medium); color: var(--adv-color-primary-dark); }

  /* ONE HEIGHT ACROSS THE RAIL, TAKEN FROM THE TALLEST CARD — not the frame's
     349. `flex: 0 0 270px` fixes the width and nothing fixed the height, so the
     rail stepped 426 / 401 / 241; the desktop row stretches, which is why it only
     ever looked wrong on mobile.

     A fixed 349 was tried first and rejected on evidence. It equalised the cards
     but had to clip the chip block, and the clipping was not clean: a card with a
     ONE-LINE name left 62px for the chips, enough to start a second 30px row at
     42 but not to finish it, so the second practice area was sliced in half. (The
     two-line-name card was fine at 38px — the second row never began. That is
     what made the earlier "a row is either in or out" reading wrong: it held for
     one card and not the other.)

     `align-items: stretch` gives every card the tallest one's height, so the
     content decides and nothing is cut. It costs the frame's exact 349 on rails
     where one firm carries many areas — the trade AK chose: no truncation over an
     exact number, since a clipped practice area reads as a rendering fault.

     Scoped with `:has`, like the area and person rails below, because this row
     class carries several card types and only this one wants stretching. */
  .adv-card-row:has(.adv-firm-card) { align-items: stretch; }

  /* In the LISTING GRID the firm card is the 362 × 170 ROW instance
     (750:35346) — the expert card's layout: panel, the photo 130 × 170
     flush left (the card clips its corners), name 22 over a 12/16 place,
     and the practice areas as a PLAIN TEXT line, commas and all — not
     chips. */
  /* ONE HEIGHT FOR EVERY CARD, and it is the frame's own 170 — not "as tall as
     the tallest". The listing had been letting each card size to its content, so
     a column of them stepped between 172 and 213: a wrapped name costs 24, and
     the practice-area line, being prose rather than chips, was running to FIVE
     lines on a firm with many areas.

     Equalising upward (`grid-auto-rows: 1fr`) would have matched them at 213 and
     left the short ones half empty, against a comp that draws 170. So the height
     is fixed and the two elastic parts are clamped to what 170 holds: name 2
     lines, areas 2 lines — which is exactly what 750:35346 draws.

     THE AREAS LINE IS THE ONE THAT LOSES CONTENT, deliberately. It is a summary
     of a list that continues in full on the firm's own page; a truncated firm
     NAME would be a worse trade, so the name keeps both of its lines. A name
     needing three is clipped rather than allowed to break the row — flagged to
     AK when this landed. */
  .adv-grid .adv-firm-card { display: flex; flex-direction: row; height: 170px; overflow: hidden; }  /* the base card is a COLUMN — the row must say so */
  .adv-grid .adv-firm-card__name {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
  }
  .adv-grid .adv-firm-card__media {
    /* flex, not block: block was flattening the --empty monogram's own
       centring. `align-self: stretch` now resolves to the card's fixed 170
       rather than following a card that grew — same declaration, and it is what
       keeps the photo full-bleed to both edges of the row. */
    display: flex;
    align-items: center;
    justify-content: center;
    width: 130px;
    height: auto;
    min-height: 170px;
    align-self: stretch;
    flex-shrink: 0;
    border-radius: 0;
    object-fit: cover;
  }
  .adv-grid .adv-firm-card__panel {
    gap: 0;
    min-height: 170px;
    min-width: 0;                 /* min-width:auto again — the nowrap tag line was sizing the panel */
    padding: var(--adv-m-stack-gap);
    justify-content: flex-start;
  }
  .adv-grid .adv-firm-card__place {
    margin-block-start: var(--adv-space-8);
    font-size: 12px;
    line-height: 16px;
  }
  .adv-grid .adv-firm-card__badge { display: none; }
  /* The areas line clamps HERE, not with the name above, because this rule sets
     `display` and would otherwise win on source order — both selectors are one
     class plus one class, so nothing outranks anything and position decides.
     `-webkit-box` replaces the `block` it used to set; the badges inside still
     run inline as prose, which is what the box display wants anyway. */
  .adv-grid .adv-firm-card__tags {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    /* THE CONTAINER HAS TO CARRY THE BADGES' OWN 12/16. It was inheriting 14/25,
       and a line box is as tall as the tallest thing in it — including the
       parent's invisible strut. So the clamped box measured 34px: one 25 line
       plus part of a second, and the cut landed MID-LINE, leaving a firm's areas
       reading "Company Formation ," with the following name sliced off. Two
       matched 16px lines is 32, which is what the 170 row has room for once the
       name (48), the place (16 + 8) and this 24 gap are paid for — 128 of 130. */
    font-size: 12px;
    line-height: 16px;
    margin-block-start: var(--adv-space-24);
  }
  .adv-grid .adv-firm-card__tags .adv-badge {
    display: inline;
    padding: 0;
    border: none;
    background: none;
    border-radius: 0;
    font-size: 12px;
    line-height: 16px;
    color: var(--adv-color-ink);
    white-space: normal;          /* the pill's nowrap has no business in a prose line */
  }
  .adv-grid .adv-firm-card__tags .adv-badge:not(:first-child)::before { content: ", "; }
  .adv-firm-card__tags .adv-badge,
  .adv-meta-group__tags .adv-badge,
  .adv-detail__links .adv-badge,
  /* THE RAIL CARD'S TAGS ARE THE SAME COMPACT TAG (760:10851: 10/normal on an
     8/16 inset, 28 tall) and were missing from this list, so they fell through
     to the 37px full-bleed rail size further down — two rows of 37 where the
     frame draws one row of 28, which is 46 of the 132 the card was over. */
  .adv-insight__tags .adv-badge {
    /* 7, NOT 8. The frame's inset IS 8, and Figma draws a border INSIDE the
       box while CSS adds it outside: 8 + 12.1 + 8 + 2 came out at 30.1 against
       a tag every one of these frames measures at 28 (704:27726, 704:30347,
       750:36063, 760:10851). The same one-pixel-each-side correction the 37px
       tag above already carries, and the same one the stat tile and the person
       card needed. */
    padding: 7px 16px;                               /* category tag size=compact */
    font-size: var(--adv-m-tag-compact);
    line-height: 1.21;                               /* 12px box → the frame's 28px tag (also "Related services", 704:27724) */
  }
  /* Listing density cards (664:24841 — PracticeAreaService, three
     densities on one width): 22/1.1 titles on a 20 inset, not the desktop
     38-on-34/26. */
  /* The density row (664:24841 / AK's reference shot): a 24 inset, the
     22 INK title on an 8 gap over a 12/16 stats line — nothing else. The
     base card is a 290-tall positioned tile (count pinned top-right),
     which is why padding alone changed nothing: the mobile row rebuilds
     the layout — flex column, natural height, stats UNDER the title
     (the card partials put the count inside the body, after the title). */
  .adv-area-card {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--adv-space-8);
    min-height: 0;
    padding: var(--adv-space-24);
  }
  /* Flex column, not block: the body's children are SPANS, and inline they
     run title and copy together on one line. */
  .adv-area-card__body {
    order: 1;
    display: flex;
    flex-direction: column;
    gap: var(--adv-space-8);
    min-height: 0;
    margin-top: 0;   /* the 171px floor + 16 offset are the desktop tile's */
  }
  /* NO RESERVE AT 402 (item 15). The two-line slot exists so cards IN A ROW
     start their copy together; here they are a full-width natural-height stack
     (`.adv-card-row:has(.adv-area-card) > *` below), so reserving a second line
     would only open a hole under a one-line title. THE CLAMP STAYS — an
     unclamped 22/1.1 title is the same latent overflow on a smaller card, and
     two lines is what the mobile benefit card already allots. `--benefit`'s own
     54px reserve is (0,2,0) AND later in source, so this reset cannot reach it;
     that is deliberate — 54 is two lines of 22 on its own frame's leading. */
  .adv-area-card__title { color: var(--adv-color-ink); margin: 0; min-height: 0; }
  /* THE COUNT SITS DIRECTLY UNDER THE TITLE (681:26795, I681:26817 — ADR-0030
     Amendment 1 §7): the card partials put it inside `__body` after the title,
     so the body's own 8 is the gap. It used to be `order: 2` behind the body,
     which on an expanded card put it under the copy and the explore line. 12 /
     400 stays (the August frame's 10 / 500 is under the legibility floor). */
  .adv-area-card__count {
    position: static;
    margin: 0;
    font-size: 12px;
    line-height: 16px;
    color: var(--adv-color-body);
  }
  /* LISTING rows lose their copy (664:24841); the NUMBER goes on every
     mobile card — Benefits keep title + description only (AK). */
  .adv-listing .adv-area-card__text,
  .adv-area-card__num { display: none; }

  /* On 402 NO screen draws breadcrumbs — every frame (listing, detail,
     About) starts at its title — and the listing swaps the 1440 hero
     band for the 362 × 185 container, fed from the same bandImage. */
  .adv-breadcrumbs { display: none; }
  .adv-page-head--listing ~ .adv-page-band { display: none; }
  /* The detail plate (AD-138; the satellite's since AD-145) is a desktop composition —
     the 402 detail (681:27056) opens on the entity title; the photograph moves into the
     362 × 185 container after it (`.adv-listing-photo`). */
  .adv-page-band--detail { display: none; }
  .adv-about-hero { padding-inline: var(--adv-m-margin); }
  /* The `:has(h1)` escape hatch that kept a TITLED band as a plain title block here is
     retired (AD-143): the careers listing was the one band carrying its page's h1, and
     it takes the detail plate now. */
  .adv-detail-head,
  .adv-detail-head--indent { padding: 54px var(--adv-m-margin) 0; margin: 0; }

  /* THE DETAIL RUNS ON THE 54 STACK (681:27056: lede→photo 54, photo→
     rails 54, band on band 54): title→lede is 16 inside the head, and the
     photo and the detail column each take their 54 explicitly — they are
     siblings from different partials, so no flex gap covers them.

     `:has(h1)` HERE IS LOAD-BEARING (AK, 2026-09-02, on the practice-area
     detail: the title→lede and lede→photo gaps both too large). The rule
     above is (0,1,0) and the titled head's own base rule is
     `.adv-detail-head:has(h1)` at (0,1,1) — a media query adds no
     specificity — so everything this block said about the head lost to a
     rule 3000 lines up, and the 402 head kept its DESKTOP rhythm: 40 on top
     (the 1100 block's), `gap: 45` between title and lede, 56 underneath.
     Measured on /practice-areas/commercial/ before the change: title→lede
     61 against the frame's 16, lede→photo 56 + 54 = 110 against 54. One
     selector, both faults, and both tiers — the satellite head paid the same
     56 with nothing in it but the h1.

     This is the same trap the `> h1` indent rules further up already carry a
     note about, and the third head rule in this file to fall into it. */
  /* `--split` IS EXCLUDED. The partner-firm head is a different composition on
     a different frame (430:8087 — logotype above the identity column at 402),
     its h1 is nested rather than a direct child, and it is not among the
     screens this pass reconciled. Left on exactly the values it had before. */
  .adv-detail-head:has(h1):not(.adv-detail-head--split),
  .adv-detail-head--indent:has(h1):not(.adv-detail-head--split) {
    /* 54 under the bar, which is where `.adv-page-head` already puts the
       LISTING title (h1 at y=127 on /practice-areas/) — the two heads read
       as one rhythm rather than differing by 14. Nothing at the foot: the
       photo and the detail column each take their own 54 below. */
    padding-block: 54px 0;
    /* THE FRAME'S OWN GAP (681:27070 is a 16 stack; 664:26019 on the listing
       is the same 16). The lede therefore keeps NO margin of its own — with
       the gap and the margin both it read 32. */
    gap: var(--adv-space-16);
    margin: 0;
  }
  /* 1.1, which is the leading this tier's token already carries and the one
     the frame draws: 681:27071 and 664:24486 both set 42px line boxes at
     38px. The block below remaps the display SIZE to 38 and left the LEADING
     at the desktop 1.21, so every mobile title ran 46 — 4px a line, 8 on the
     two-line practice-area name.

     SCOPED, NOT REMAPPED ON `--adv-display-lh`: that variable also feeds the
     closing band's headline, and 704:27713 draws "Need legal assistance?" at
     92 for two lines, i.e. 1.21 exactly. Only the page title takes 1.1. */
  .adv-detail-head > h1 { line-height: var(--adv-m-title-lh); }
  /* A DUTCH OR GERMAN NAME BREAKS AT A SYLLABLE (AD-82, ADR-0033 Amendment 1). At 38px the
     362 this heading gets holds a compound of about seventeen letters, and the taxonomy's
     names run longer — "Herstructureringsrecht" measured 407, "Restrukturierungsrecht" 412,
     "Vennootschapsrecht" missed by 5 — so the word ran out of the page. AD-144 shortened names
     to fit; since AD-82 the names are data a client edits (AD-165), so the heading breaks
     them instead: the card grids' `--long-words` rule, on the page title of a practice area
     or a service (`detail-head.html` is the only markup that carries the modifier). Scoped by
     language for the reason given at the grids — `hyphens: auto` also splits words that would
     have fit whole, harmless in the compounding languages, a visible change in EN and FR.
     `overflow-wrap` is the floor for a browser with no dictionary for the language. */
  .adv-detail-head--long-words > h1:is(:lang(nl), :lang(de)) { hyphens: auto; overflow-wrap: break-word; }
  .adv-detail-head .adv-lede-mobile { margin: 0; }
  /* THE PHOTO IS 54 UNDER THE HEAD, OR 54 UNDER THE BAR WHEN NO HEAD COMES BEFORE IT
     (TD-27; ADR-0025 Amendment 12, ADR-0030 Amendment 4). The expert, lawyer and both
     insight pages pass `title: false` (the name sits in their own layout), so
     `detail-head.html` renders plate → crumbs → photo with no `.adv-detail-head`
     between them. The first selector never matched there, and with the plate and
     the crumbs hidden in this block the photograph opened flush under the bar
     (y = 89 under the 88 bar). It takes the 54 a titled head pays above its h1, the
     same 54 the careers listing's lead photo already has (760:12865).
     THE PLATE IS THE DISCRIMINATOR. Only `detail-head.html` renders `--detail`, so no
     listing matches, and `:not(:has(.adv-detail-head))` leaves the office page out:
     its identity head comes after the photo in the source but is ordered above it.
     SINCE AD-185 THE MASTER'S DETAIL PAGES RENDER NO PHOTOGRAPH ON A PHONE (Amendment 24
     §5, which reverses Amendment 12 there): these two now place the careers listing's
     lead photo and every satellite detail page's. */
  .adv-detail-head ~ .adv-listing-photo,
  main:not(:has(.adv-detail-head)) > .adv-page-band--detail ~ .adv-listing-photo { margin-block-start: var(--adv-m-detail-gap); }
  .adv-detail--3col { padding-block-start: var(--adv-m-detail-gap); gap: var(--adv-m-detail-gap); }

  /* RELATED INSIGHTS (704:27709): the desktop carousel's transform-track
     collapses at 402 — slides overlap and the square media rule fought
     the card. It becomes a native scroll RAIL: 270 cards on a 34 gap,
     3:2 media, full-bleed scroll, no dots. */
  .adv-reel__viewport,
  .adv-reel[data-ready="true"] .adv-reel__viewport {
    overflow-x: auto;             /* data-ready locks it to `hidden` for the slide JS — the rail scrolls */
    touch-action: auto;           /* the base `pan-y pinch-zoom` is for the dragged track; a rail pans natively */
    margin-inline: calc(-1 * var(--adv-m-margin));
    padding-inline: var(--adv-m-margin);
    scrollbar-width: none;
  }
  .adv-reel__viewport::-webkit-scrollbar { display: none; }
  .adv-reel__track {
    display: flex;
    gap: var(--adv-m-band-gap);
    width: auto;
    transform: none !important;   /* the slide JS keeps writing; the rail scrolls instead */
  }
  /* A desktop SLIDE is a 2-up GROUP (flex: 0 0 100%, two cards at flex:1)
     — at 270 the pair crushed into itself, which was the overlap. The
     group goes width-auto and each CARD takes the rail's 270; group gap =
     track gap, so the pairs read as one continuous rail. */
  .adv-reel__slide { flex: 0 0 auto; width: auto; gap: var(--adv-m-band-gap); }
  /* A scroll container paints NEITHER its end padding NOR the last flex
     item's end margin past the content edge (Chrome) — only a real box
     counts. Each rail gets a 1px ::after spacer whose start margin
     compensates the rail's own gap so the tail lands exactly on the 20px
     page margin. */
  .adv-reel__track::after,
  .adv-card-row::after {
    content: "";
    flex: 0 0 1px;
    margin-inline-start: calc(var(--adv-m-margin) - var(--adv-m-band-gap) - 1px);
  }
  .adv-switch-chips::after {
    content: "";
    flex: 0 0 1px;
    margin-inline-start: calc(var(--adv-m-margin) - var(--adv-m-chip-gap) - 1px);
  }
  .adv-reel__slide > * { flex: 0 0 270px; min-width: 270px; }
  .adv-dots { display: none; }
  /* THE CONTROLS BLOCK IS A 16 STACK AT 402 (760:10328: the search row 0..56,
     the scope tags at 72, the Filters/Sorted-by row at 133 — 16 and 16; since the
     scope tags left in AD-196 the Filters row is 16 under the search row). It was
     running on the section gap, so the rows that make up one control sat 34 apart
     and read as separate bands.

     `[data-listing]` IS LOAD-BEARING (AK, 2026-09-02: the gap under the search
     input on the SEARCH page got too small). "Only the insights listing has more
     than one control row" was wrong when I wrote it — the search results screen
     builds the same three rows into the same `.adv-listing__controls`, and it
     has no 402 frame, so its authored value is the desktop's 34 (measured:
     search ends 396, kinds open at 430). Unscoped, this rule took that screen
     down to 16 as well. The insights listing sits inside `[data-listing]`, the
     search screen inside `[data-search]`, so the attribute separates them
     without a new class. */
  [data-listing] .adv-listing__controls { gap: var(--adv-space-16); }
  /* AND THE APPLIED-FILTER ROW GOES WHEN IT HOLDS NOTHING (AK, 2026-09-02: the
     gap down to "Featured insights" reads too big). The 54 below the controls
     was right — 760:10328 ends at 557 and 760:10335 opens at 611 — but the row
     was adding 16 + 25 of empty above it, so the reader saw 95.

     That row keeps its height on purpose: the sort sits in it, and a row that
     collapses when the last chip is cleared would drop the sort 25px. At 402
     that reason is gone — `placeSort()` lifts the sort into the Filters row, so
     with no chips applied nothing is left in it at all.

     `:has(> *:not([hidden]))` and NOT a flat `display: none`, because the sort
     IS in the row until the deferred bundle runs: keyed on the children, the
     row is visible in the first painted frame and disappears only once the sort
     has actually left it. The same first-frame reasoning as the nav sheet. */
  .adv-controls-row:not(:has(> *:not([hidden]))) { display: none; }
  /* ---- THE RAIL CARD IS `Article post`, 270 x 472 (750:35904) ----------
     Measured child by child, because the sheet had it at 604: a 12 stack, not
     the 20 the mobile card default gives; the tags BETWEEN the title and the
     summary, not after them; the title two lines and not three; the summary on
     a 20 leading and not the body's 25; and the tags at the COMPACT size the
     kit's `category tag` uses inside a card, not the 37 the full-bleed tag
     rails take.

     `12 + 6 + 270 + 12 + 54 + 12 + 28 + 12 + 60 = 466` against the component's
     own 472 box — the frame's children do not fill it either. */
  /* ONE COMPONENT, TWO WIDTHS (AK, 2026-09-02). The rail card (750:35904, 270
     wide) and the listing card (760:10732, 362 wide) are the SAME `Article
     post` instance — identical stack, identical type, identical tag size — and
     only the photograph differs: a 270 square on the rail, 362 x 270 in the
     listing. They were written as two blocks with two sets of numbers, and the
     listing half never got measured at all: 20 between children where the frame
     has 12, the summary on the body's 25 where the frame writes 20, the tags at
     the 37 the full-bleed rails use, and — worst — the tags ordered to the FOOT
     of the card when both frames put them between the title and the summary.

     So the shared rules live on `.adv-insight` here and each context restates
     only its photograph. `12 + 6 + 270 + 12 + 54 + 12 + 28 + 12 + 60` is 466 on
     the rail (against its 472 box) and the same on the listing (against 466). */
  .adv-reel .adv-insight,
  .adv-grid .adv-insight { flex-direction: column; gap: var(--adv-space-12); }
  .adv-reel .adv-insight__media { width: 270px; height: 270px; }  /* the rail's SQUARE (704:27709) */
  /* DATE OVER THE PHOTO (AK, 2026-08-27 — both tiers). The date lives inside
     `__body`, so the body dissolves and `order` lifts the date above the
     media. */
  .adv-reel .adv-insight__body,
  .adv-grid .adv-insight__body { display: contents; }
  /* 6, NOT the stack's 12: the frame nests the date and the photo in one grid
     cell (760:11039 / 760:11070) with the date 12 tall at the top and the photo
     dropped 18 — a caption sitting on the picture, not another step of the
     stack. */
  .adv-reel .adv-insight__date,
  .adv-grid .adv-insight__date { order: -1; margin: 0 0 -6px; }
  /* The master's foot row (AD-138) dissolves with the body, so the date keeps
     its place over the photo; the byline has no 402 frame and is not drawn. */
  .adv-reel .adv-insight__foot,
  .adv-grid .adv-insight__foot { display: contents; }
  .adv-reel .adv-insight__byline,
  .adv-grid .adv-insight__byline { display: none; }
  /* NO `order` ON THE TAGS. Both frames put them between the title and the
     summary (750:35904: title 300, tags 366, summary 406; 760:10732 the same
     sequence), which is the source order already — the rule that moved them to
     the foot left the summary butted against the title on both cards. */
  .adv-reel .adv-insight__tags,
  .adv-grid .adv-insight__tags {
    gap: var(--adv-space-8);
    /* ONE ROW, AND THAT IS WHAT MAKES THE CARD'S HEIGHT DETERMINISTIC (AK,
       2026-09-02, asking whether the cards can come out uneven). The title and
       the summary are already clamped, so the tag block was the only child left
       that could grow: two long labels wrap and the row doubles to 64, taking
       the card — and with it the whole rail, which stretches to its tallest —
       past the frame's box. `max-height` rather than `nowrap` so the overflow
       row is dropped WHOLE instead of a pill being sliced down its middle. */
    max-height: 28px;
    overflow: hidden;
  }
  /* TWO LINES. Both frames draw a 54 title box (2 x 27 at the `normal` leading)
     and the listing's shortest card proves the ceiling: 760:10731 is 446 where
     its siblings are 466, which is one line of summary less, not one of title. */
  .adv-reel .adv-insight__title,
  .adv-grid .adv-insight__title { -webkit-line-clamp: 2; }
  /* 20, not the 25 body step — the frame's summary box is 60 for three lines. */
  .adv-reel .adv-insight__excerpt,
  .adv-grid .adv-insight__excerpt { line-height: 20px; }
  /* 362 x 270, NOT 16/9. The listing photograph is the rail's square stretched
     to the page measure, not a widescreen crop — 760:10732 draws `w-[362px]
     h-[270px]`, and 16/9 gave 203, which is 67 short and the reason a listing
     card and a rail card side by side read as different components. */
  .adv-grid .adv-insight__media {
    width: 100%;
    max-width: 100%;
    height: 270px;
    aspect-ratio: auto;
  }
  /* Long titles and summaries clamp instead of escaping the 270 card. */
  .adv-insight__title {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
  }
  .adv-insight__excerpt {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
  }
  .adv-reel .adv-insight { max-width: 270px; overflow: hidden; }  /* the RAIL card only — the grid card takes the full measure */

  /* FIRM DETAIL on the 402 metrics (750:35822): the photo plate leads at
     362 × 138, the identity stacks under it, the areas move to their own
     labelled block, and REVIEWS come BEFORE the insights rail — the
     desktop order is the reverse, so the page's main column reorders by
     flex (scoped by :has to the firm page alone). */
  .adv-detail-head--split { display: flex; flex-direction: column; gap: var(--adv-space-16); }
  /* AND `:has(h1)` HERE TOO (AK, 2026-09-02: too much air above "Practice
     areas"). The line above is (0,1,0) and lost its `gap` to the titled head's
     base rule at (0,1,1) — the third head in this file caught by that, and the
     one I deliberately left alone last time because I had no frame for it.
     750:35822 is that frame, so it can be measured now: the plate runs 0..138,
     the identity opens at 172 (34 under it) and the block ends at 251, with the
     areas band at 305 — 54, not the 56 + 34 = 90 the page was drawing.
     34 rather than the 16 above it: the frame's own number, and the 16 belongs
     to the rows INSIDE the identity, not to the plate-to-identity step. */
  .adv-detail-head--split:has(h1) {
    padding-block: 54px 0;
    gap: var(--adv-m-band-gap);
  }
  /* Same 1.1 the other heads take — 750:35839 draws the firm's name in a 42px
     line box at 38px. Restated because this h1 is NESTED in the identity
     column, so `.adv-detail-head > h1` above cannot reach it. */
  .adv-detail-head--split h1 { line-height: var(--adv-m-title-lh); }
  /* THE FLOW BANDS OF A DETAIL PAGE RUN ON 54, AND ONLY THOSE. Every gap on
     750:35822 is 54 — identity→areas, areas→about, about→figures, figures→
     story, story→reviews, reviews→insights, insights→closing band — and
     681:27056 and 704:30027 agree. The HOMEPAGE does not: 597:19805 stacks its
     bands 34 apart, and `--adv-m-band-gap` is 34 because of that screen. Both
     are authored, so the sheet cannot carry one number; `.adv-detail-head ~` is
     the discriminator, since a detail page opens with one and the homepage has
     none. */
  .adv-detail-head ~ .adv-band--flow { padding-block-start: var(--adv-m-detail-gap); }
  /* …WITH ONE EXCEPTION ON THE HOMEPAGE (AD-185, ADR-0025 Amendment 24 §1). The
     designer's 2026-10-05 edit of 597:19805 gives the practice-areas group an
     unpainted 34 inset of its own (1957:10810) inside the 34 band stack: the
     Services plate ends at 995 and "PRACTICE AREAS" opens at 1063; "Explore
     practice area" ends at 1359 and "ABOUT ADVERIT LEGAL" opens at 1427 — 68 and
     68, box tops as the frame measures them. 2 × 34 above, 34 below, and About's
     own 34 makes the second 68. */
  .adv-band--areas {
    padding-block: calc(2 * var(--adv-m-band-gap)) var(--adv-m-band-gap);
  }
  /* THE THREE FIGURES ARE THREE PLATES (AD-185, ADR-0025 Amendment 24 §2; 750:36026 on
     597:19805, redrawn 2026-10-05). Home and About only — `--three`; the office page's four
     and the satellite About's keep the 2 × 2 of the ≤860 block (750:35822 still draws it),
     and 561–860 keeps 2 + 1 (Amendment 23). Each plate is 362 × 98, 20 apart: the figure
     (38 SemiBold, a 46 box) and its label (16/25 Medium) side by side, 8 apart, the pair
     centred — "5" ends at 161.5 and "Offices" starts at 169.5. 98 = 1 + 25 + 46 + 25 + 1:
     the frame's 26 inset includes the 1px rule Figma draws inside the box, and CSS adds it
     outside, so the padding is 26 − 1. The MIN-HEIGHT says the same 26 + 46 + 26 once more
     because WebKit floors the figure's 45.98 line box to 45 (measured: a 97 plate on WebKit
     26.5, 98 on Chromium) — the iPhone is the engine that matters here. The label is the
     navigation step, 16/25 Medium, which this tier does NOT remap (the body step is 14 here);
     it drops the base 130 measure, which put "Domaines de droit" on two lines. `data-count`
     is untouched. */
  .adv-stats--three {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--adv-m-stack-gap);
  }
  .adv-stats--three > .adv-stat {
    flex-direction: row;
    gap: var(--adv-space-8);
    min-height: calc(var(--adv-h1-size) * var(--adv-h1-lh) + 2 * var(--adv-space-26));
    padding: calc(var(--adv-space-26) - var(--adv-border-width)) var(--adv-m-margin);
    border-radius: var(--adv-m-radius-card);
  }
  .adv-stats--three .adv-stat__label {
    max-width: none;
    font-size: var(--adv-nav-size);
    line-height: var(--adv-nav-lh);
  }
  .adv-detail-head--split .adv-meta-group__tags { display: none; }
  /* SCOPED BY THE IDENTITY'S OWN MODIFIER SINCE AD-142 — it hung on the logotype plate
     (`main:has(.adv-firm-logo)`), and removing the plate would silently have returned the
     page to desktop order at 402. */
  main:has(.adv-detail-head--office) { display: flex; flex-direction: column; }
  main:has(.adv-detail-head--office) > * { order: 0; }
  /* The existing areas band lifts to the frame's slot under the identity
     (750:36059), instead of its desktop place after the stats. The head takes
     -2 so the band lands between it and the rest, 54 under the identity (the
     band's own top padding — 750:35822 runs identity → 54 → areas). */
  main:has(.adv-detail-head--office) > .adv-detail-head--split { order: -2; }
  main:has(.adv-detail-head--office) > .adv-firm-areas { order: -1; }
  /* (The rule that put the office's photograph between the identity and the areas — TD-30,
     ADR-0025 Amendment 13 — is gone: since AD-185 the office page renders no photograph on a
     phone (`mobilePhoto` false; Amendment 24 §5), as 750:35822 draws none. It was also the
     page's WebKit overflow: a stretched flex item, which WebKit sized to the full column and
     pushed 20 past the screen.) */
  /* WHAT CLIENTS SAY on 402 (750:36270): TWO reviews stacked vertically —
     362 × 134 cards on a 24 gap on the band plate; anything past the pair
     stays desktop-only. */
  .adv-reviews {
    display: flex;
    flex-direction: column;
    gap: var(--adv-space-24);
  }
  .adv-reviews > *:nth-child(n+3) { display: none; }

  /* Our story on the 402 measure (750:36134): the date column narrows to
     a fifth of the row and the entry takes the rest — the desktop's
     97px + 55 gap + capped 660 was sizing against a 1440 band and left
     the dates eating the phone's measure. */
  .adv-story {
    grid-template-columns: 20% minmax(0, 1fr);
    column-gap: var(--adv-m-stack-gap);
    margin-inline-start: 0;
    align-self: stretch;
  }
  main:has(.adv-detail-head--office) > .adv-related { order: 2; }
  main:has(.adv-detail-head--office) > .adv-band:has(.adv-quote),
  main:has(.adv-detail-head--office) > .adv-band:last-of-type { order: 1; }
  main:has(.adv-detail-head--office) > .adv-cta-band,
  main:has(.adv-detail-head--office) > section:has(.adv-switch-panel--cta) { order: 3; }

  /* Expert detail on the 402 metrics (704:30027): the square photo takes
     the measure (362 × 362 at the mobile radius, 34 under the head), the
     contact CTA goes full measure, the fact rows stack on 24. */
  /* THE DESKTOP GRID IS UNDONE HERE (AK, 2026-08-31). 307:6047's two columns
     and the two fact sub-columns are a 1440 composition; 704:30027 stacks the
     lot. Every one of these is a RESET of a rule written for the desktop pass,
     which is why they sit together rather than scattered: the grid, the
     name/CTA row inside it, and the fact columns. Without them the 600/660
     tracks resolved to 151px each on a 402 screen and the 494 portrait ran off
     the side. */
  /* THE 402 ORDER IS THE FRAME'S, NOT THE DOM'S (704:30027): name, photo, the
     outlined CTA 34 under it, then the facts, then the bio. On desktop those
     five live in two column wrappers; here the wrappers `display: contents` so
     the children become direct flex items of one column and can be ordered
     against each other. Same device as `.adv-article__byline` at this step, and
     for the same reason — the composition regroups, the markup does not. */
  .adv-expert-detail {
    display: flex;
    flex-direction: column;
    gap: var(--adv-m-band-gap);
    padding-inline: 0;
    /* 54 UNDER THE BAR (AD-185, ADR-0025 Amendment 24 §5): the master's lawyer page draws no
       photograph on a phone any more, so the name opens the page — 704:30027 sets it at
       y = 120, the tier's 54 under the bar, like every other detail title. It was 42 under
       the section photograph ("as before AD-139"), and that is still the satellite's place:
       its lawyer page keeps the photograph, so `--sat` keeps the 42. */
    margin-block-start: var(--adv-m-detail-gap);
  }
  .adv-expert-detail--sat { margin-block-start: var(--adv-space-42); }
  .adv-expert-detail__aside,
  .adv-expert-detail__main { display: contents; }
  .adv-expert-identity { order: 1; }
  .adv-expert-photo     { order: 2; }
  .adv-expert-cta       { order: 3; grid-column: 1; justify-self: stretch; }
  .adv-expert-facts     { order: 4; }
  .adv-expert-bio       { order: 5; }
  /* ONE STACK, AND THE BLOCKS SIT 18 APART, NOT 34 (704:30385: contact ends
     123, languages opens 141, areas 213 after languages' 195, services 288
     after areas' 270 — 18 four times over). 16 because the scale has no 18 and
     an off-scale token for two pixels is the worse trade; the 34 inherited from
     the desktop rule made the facts read as four separate bands. */
  .adv-expert-facts {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--adv-space-16);
    /* margin-block-start 0, not the desktop's 26-under-the-portrait: here the
       facts follow the CTA, and the column's 34 gap is the whole spacing. */
    margin: 0 var(--adv-m-margin);
  }
  .adv-expert-facts__col { gap: var(--adv-space-16); }
  .adv-expert-identity,
  .adv-expert-bio { margin-inline: var(--adv-m-margin); }
  /* The values take the mobile body line here — 704:30329 measures 25 tall
     against the desktop's 17. The SIZE stays 14: this tier's body is 14/25 by
     decision ("the step change" in the mobile tokens), and the frame's 16 is one
     text node against a scale every other mobile value on the page follows. The
     line-height is what the frame is actually asking for. */
  .adv-expert-fact__value {
    font-size: var(--adv-m-body-size);
    line-height: var(--adv-m-body-lh);
  }
  .adv-expert-name { font-size: var(--adv-m-title-size); line-height: var(--adv-m-title-lh); }
  .adv-expert-education__row { grid-template-columns: minmax(0, 1fr); gap: var(--adv-space-4); }

  .adv-expert-photo {
    /* `align-self: stretch` with `width: auto`, and NEITHER alone works: with
       the aside on `display: contents` the plate is a direct flex item, where
       bare `auto` let the EMPTY variant shrink-wrap to its monogram glyph (37px
       measured) and `100%` resolved against the container BEFORE its own 20px
       margins, so it overhung the right edge by exactly those 20. Stretch sizes
       it to the line minus its margins, which is the whole point of stretch. */
    width: auto;
    align-self: stretch;
    /* AND A CAP, FOR WEBKIT (AD-185, ADR-0025 Amendment 24 §6). WebKit sizes a STRETCHED flex
       item that has `aspect-ratio` and `width: auto` to the container's whole width and
       ignores its inline margins: on iPhone the portrait came out vw × vw, 20 past the
       screen, and iOS zoomed the whole page out to fit it (MD: "у фотографий юристов чуть
       чуть выравнивание поехало"). Chromium was right, and `html { overflow-x: clip }` hid
       the overflow from it. The cap is the stretch Chromium already computes — the line
       less the two margins — so it changes nothing there. Both tiers (ADR-0030 Amendment
       17 §4). */
    max-width: calc(100% - 2 * var(--adv-m-margin));
    /* NO margin-block-start: the column already puts `--adv-m-band-gap` between
       every child, so adding 34 here stacked on that 34 and measured 68 — the
       frame's four gaps (identity→photo→CTA→facts) are all exactly 34. */
    margin: 0 var(--adv-m-margin);
    border-radius: var(--adv-m-radius-card);
  }
  /* THE CTA IS 362 WIDE AT x=20 (760:18353), NOT EDGE-TO-EDGE — the same trap
     the portrait rule above documents, in its sibling: `width: 100%` resolved
     against the column BEFORE margins, so the button measured 387 at x=0 and
     was the one element on the page ignoring the 20px margin. Stretch, like the
     photo. `margin-block-start: 0` undoes the desktop optical nudge; the
     column's own gap supplies the 34. */
  .adv-expert-cta {
    width: auto;
    align-self: stretch;
    margin: 0 var(--adv-m-margin);
  }
  /* THE NAMED LABEL TAKES OVER AT 402 and truncates rather than growing. The
     button is full-measure here, so a long name cannot push the control past
     the page margin the way it would on the desktop's shrink-to-fit one — but
     it CAN wrap the button onto a second line and break the 50px height the
     frame draws, and this network already holds names like "Caterina
     Guidiceandrea".
     `min-width: 0` is the part that is easy to leave out: without it the flex
     item's automatic minimum size keeps the span at its content width and the
     ellipsis never gets a chance to appear. */
  .adv-expert-cta__role { display: none; }
  .adv-expert-cta__named {
    display: block;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }

  /* PA DETAIL ORDER (681:27056 / handoff mobile-practice-area-detail):
     title → photo → related firms as 2-UP TILES → prose → services chips
     → insights rail → CTA. The desktop's left area-nav rail does not
     survive to 402, and the rails column moves ABOVE the prose. */
  .adv-detail--3col { display: flex; flex-direction: column; }
  .adv-detail--3col > .adv-detail__rail { display: none; }   /* the 8-area nav */
  /* THE TOPIC PAGE KEEPS ITS RAIL (AD-164, ADR-0038 §AD-164 §4 — MD's call 17): Related
     topics moves UNDER the text (the lawyers 1, the text 2, this 3), before How we can
     help; the area and service pages' rails stay hidden. A text column with no text — only
     the button, which this step hides — and an empty rail slot take no row: the column
     would pay its 54 twice. */
  .adv-detail--topic > .adv-detail__rail { display: flex; order: 3; align-self: stretch; }
  .adv-detail--topic > .adv-detail__body:not(:has(> .adv-prose)),
  .adv-detail--topic > div:empty { display: none; }
  /* The lede renders in the HEAD on mobile (adv-lede-mobile); the body's
     duplicate — and its "Discuss your case" CTA, which the 402 frame does
     not draw — go with the desktop column. */
  .adv-lede-mobile { display: block; }
  /* Scoped to the --3col detail (practice areas): the expert detail also
     puts an .adv-btn first in its body — its CONTACT CTA, which the frame
     draws — and an unscoped hide swallowed it. */
  .adv-detail--3col .adv-detail__body > .adv-subtitle,
  .adv-detail--3col .adv-detail__body > .adv-btn { display: none; }
  /* align-self: the --3col flex column aligns start (the base grid's
     align-items survives the display swap), so an unstretchd rails
     wrapper shrink-wraps and its 1fr grid tracks collapse with it. */
  .adv-detail__rails { order: 1; align-self: stretch; }
  .adv-detail__body { order: 2; align-self: stretch; }
  /* One rail = head row (label left, "View all" right) over a 2-up tile
     grid on a 22 column gap (the frame's 170 + 22 + 170). */
  .adv-detail__rails .adv-detail__rail {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    /* 24 UNDER THE HEAD ROW, 22 between the tiles — 704:28050 puts the head at
       0..25 and the tiles at 49. It was 12, read off the tile's own internal
       rhythm rather than off the row gap. */
    gap: 24px 22px;
    align-items: start;
  }
  /* Spans the full first row — otherwise a rail with ONE tile and no
     "View all" auto-places that tile into the label's row (the satellite
     PA detail with a single expert did exactly that), and the label
     itself wraps inside a 170px cell. The link overlays column 2 of the
     same row, right-aligned — label left, link right, as before. */
  .adv-detail__rails .adv-section-label { grid-row: 1; grid-column: 1 / -1; margin: 0; }
  /* AND SO DOES THE EMPTY LINE (AK, 2026-08-31). It is a SENTENCE, not a tile:
     auto-placed it took one 170px cell and wrapped "The cooperation's legal
     experts are not published yet." over three lines beside a column of blank
     space. The same span the label needs, for the same reason — a rail's
     2-up grid is for the tiles, and the things that describe the rail run its
     full width. Only visible now because the experts rail renders at all: it
     used to be dropped when empty, until this morning's "show the section,
     state the emptiness" pass. */
  .adv-detail__rails .adv-empty { grid-column: 1 / -1; }
  .adv-detail__rails .adv-link-more {
    grid-row: 1;
    grid-column: 2;
    justify-self: end;
    /* The desktop rail pays the 26 above this link as a margin (see the rule by
       `.adv-detail__rail`); here the link shares the head ROW with the label and
       any of it left standing pushes it off that line. The label's own margin is
       cleared the same way, just above. */
    margin: 0;
    font-size: var(--adv-m-body-size);
    line-height: var(--adv-m-body-lh);
    /* NAVY AND MEDIUM on this tier — 704:28047 binds `corporate/navy` at
       Inter Medium 14. The base link is corporate BLUE at the nav weight,
       which is right where it trails body copy; here it is a head-row label
       sharing a line with the burgundy section label, and the frame ranks the
       two by colour rather than by size. */
    font-weight: var(--adv-weight-medium);
    color: var(--adv-color-primary-dark);
  }
  .adv-detail__rails .adv-link-more:hover { color: var(--adv-hover-accent); }
  /* NO GLYPH ON THIS TIER (AK, 2026-08-31). 704:28047 is a bare "View all" — a
     52px text node with nothing after it, where ours rendered 71: the label
     plus an 8px gap plus the `--out` modifier's ↗. On the desktop rails the
     arrow says "this leaves the page"; in the 402 head row the link is one of
     two labels sharing a 25px line with the section label, and a glyph there
     reads as decoration on a caption.

     SCOPED TO THE RAILS, not to `.adv-link-more`. The homepage's three
     "Explore …" links are the same component in the other context — trailing
     body copy, where the arrow is the point — and no 402 frame says they lose
     it. `gap` goes too, or the removed glyph leaves 8px of air after the label
     and the right edge stops being flush. */
  .adv-detail__rails .adv-link-more { gap: 0; }
  .adv-detail__rails .adv-link-more::after { content: none; }
  /* The tile (170 × 139): logo plate 78 tall at the 4px radius, 14/500
     name over a 14 place line, all ink. The row must be RESTATED as a
     column — the base .adv-person-mini is a flex ROW (photo beside the
     text), and inside a 170px grid cell the 100%-wide photo plus the
     text beside it overflowed into the neighbouring tile. */
  .adv-detail__rails .adv-person-mini {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;   /* photo → name is 12 on the frame (78 → 90, 704:28034) */
  }
  .adv-detail__rails .adv-person-mini__photo {
    width: 100%;
    height: 78px;
    border-radius: var(--adv-radius-xs);
    object-fit: cover;
  }
  /* The satellite's tile (760:17904) runs a taller 90 photo and the name
     alone — no role/place second line. */
  .adv-detail__rails--plain .adv-person-mini__photo { height: 90px; }
  /* The master row's +7 belongs to the desktop row, not to this tile. */
  .adv-detail__rails--frame { --adv-person-mini-name-inset: 0; }
  .adv-detail__rails--plain .adv-person-mini__role { display: none; }
  /* TWO TILES, ONE ROW (AK, 2026-09-03). 760:17903 is a 116-tall frame holding
     exactly two 170-wide tiles at x=0 and x=192 — one row, not the desktop
     rail's four. The tile geometry was already right; the COUNT was not, so the
     page carried a second row the frame does not draw.

     CSS AND NOT `first 2` IN THE TEMPLATE, because the desktop rail keeps its
     four and a template cannot see the viewport. The sibling chain counts the
     tiles themselves — `:nth-of-type` would be wrong here, since the tile and
     the "View all" link are both <a> and the label is a <p>, so type position
     and tile position are different numbers.

     `--plain` scopes it to the satellite's tile; the master's rail is a
     different composition on a different frame and does not move. */
  .adv-detail__rails--plain .adv-person-mini ~ .adv-person-mini ~ .adv-person-mini {
    display: none;
  }
  .adv-person-mini__name {
    font-weight: var(--adv-weight-medium);
    font-size: var(--adv-m-body-size);
    line-height: 20px;
    color: var(--adv-color-ink);
  }
  /* THE PLACE LINE, READ OFF 704:28050 (AK, 2026-08-31). Three corrections in
     one rule: it binds `text/secondary` #51595F, not the name's ink — the tile
     is a two-tone pair, name dark and place quiet — and it sits 12 under the
     name, not the desktop component's 5. 12 is the frame's own arithmetic: the
     name box is 20 and the place starts at +32.

     `--adv-small-lh`, not `1`: the frame's node measures 17 tall on a 14px
     line, which is AUTO for Inter. At `1` the pair came out 5 short and the
     tile stopped matching the drawn 139. */
  .adv-person-mini__role {
    margin-block-start: 12px;
    font-size: var(--adv-m-body-size);
    line-height: var(--adv-small-lh);
    color: var(--adv-color-body);
  }

  /* The listing photo (Rectangle 3, 362 × 185 at radius 8) — a
     mobile-only element, shown where the template renders it. */
  .adv-listing-photo {
    display: block;
    width: auto;
    margin-inline: var(--adv-m-margin);   /* it sits outside any padded container */
    aspect-ratio: 362 / 185;
    border-radius: var(--adv-m-radius-card);
    background-size: cover;
    background-position: center;
  }
  /* The careers detail's firm photograph is squatter (Rectangle 3 on
     760:13723 — 362 × 150), and it sits INSIDE the padded detail column,
     so the bleed margin comes off. */
  .adv-listing-photo--squat {
    aspect-ratio: 362 / 150;
    margin-inline: 0;
    align-self: stretch;   /* its .adv-stack parent aligns flex-start */
  }
  .adv-area-card__title {
    font-size: var(--adv-m-card-title);
    line-height: var(--adv-m-card-title-lh);
  }

  /* The mobile card title step: 22/1.1 in ink (754:38390) — not the
     desktop 28. The place/meta lines are already on the 14/25 body step. */
  .adv-firm-card__name {
    font-size: var(--adv-m-card-title);
    line-height: var(--adv-m-card-title-lh);
  }
  /* The About intro's two CTAs stack at the full measure — the frame
     draws them as two 362 × 50 buttons on a 16 gap (623:23874/23877). */
  .adv-cta-row {
    flex-direction: column;
    align-items: stretch;
    gap: var(--adv-space-16);
    align-self: stretch;
  }
  .adv-cta-row .adv-btn { width: 100%; }
  .adv-btn__label--wide { display: none; }
  .adv-btn__label--narrow { display: inline; }

  /* Band CTAs take the full measure — the kit's size=long button (362 on
     the 402 frame): the help callout and the closing CTA band both draw
     it (597:19882, Frame 225). */
  .adv-band--help .adv-stack > .adv-btn { width: 100%; }

  /* "ABOUT US" RUNS ON TWO GAPS, NOT ONE (AK, 2026-09-03 — the margin from the
     title to the button is too big). 760:16972 is explicit: the headline ends at
     184, the copy opens at 200 and ends at 260, the button opens at 284. So it
     is 16 down to the copy and 24 down to the button, and `.adv-stack`'s single
     20 can only ever be wrong in one of the two places. The 8 is the difference
     paid on the button rather than a second literal, so the pair stays tied to
     the stack gap above it if that ever moves.

     THIS ALSO READS CORRECTLY WITH NO COPY AT ALL, which is the case on every
     firm converted before `introText` existed: the button simply inherits the
     16 + 8 and lands 24 under the headline, which is the gap the frame draws
     below the last line of text either way. */
  .adv-band--intro .adv-stack { gap: var(--adv-space-16); }
  .adv-band--intro .adv-stack > .adv-btn { margin-block-start: var(--adv-space-8); }
  .adv-value { grid-template-columns: 38px minmax(0, 1fr); row-gap: var(--adv-space-8); }
  .adv-value__text { grid-column: 2; }
  .adv-search__field { padding-inline: var(--adv-space-16) 66px; }
  .adv-filter { padding-inline: var(--adv-space-24); }
  .adv-topic-card__body,
  .adv-media-card__body,
  .adv-news-card__body { padding: var(--adv-space-24) var(--adv-space-16); }
  .adv-topic-card__title { min-height: 0; }  /* the 88px title box is a 1440 device */
  .adv-hero__content { padding: var(--adv-space-32) var(--adv-space-26); }
  .adv-grid,
  .adv-grid--wide,
  .adv-grid.adv-grid--wide {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--adv-space-16);   /* the 402 listings stack on 16 (760:18040, 664:24841) */
    /* THE EQUAL-HEIGHT RULE IS OFF IN THE STACK, and it has to be. In one
       column every card is its own row, so `1fr` would size all of them to the
       tallest — and the practice-area ACCORDION below is exactly a set of rows
       that must not be the same height: it collapses to a title and expands one
       card at a time, animating `min-height`. A grid that forced every row to
       the expanded card's height would leave the collapsed ones as tall as the
       open one, which is the accordion with its one job removed. Nothing is
       lost: a single column has no neighbour to line up with. */
    grid-auto-rows: auto;
  }
  /* The article grid runs looser — the expanded posts sit 34 apart
     (760:10727: 446/466 cards in a 1946 stack). */
  .adv-grid.adv-grid--wide { gap: var(--adv-m-band-gap); }

  /* The satellite lawyer detail's own 402 composition (760:18197) retired in AD-145: the page
     is `.adv-expert-detail` now, and the master's 402 order above applies to it. */

  /* MOBILE FOOTER (623:21898, ADR-0017 §7). The frame stacks the LINK
     COLUMNS ABOVE the brand block — the inverse of the desktop row — and
     keeps the two columns side by side (158 + 23 + 150 fits the 362
     measure with room to spare); no accordion. Column headings stay 16/500
     and the links 14, which the type step above already leaves alone.
     54 is the frame's own block rhythm (content starts at y=54 and the
     brand block sits 54 under the columns); 23 is its column gap — both
     measured, neither on a scale. */
  .adv-footer__top {
    flex-direction: column-reverse;
    gap: 54px;
    padding: 54px var(--adv-m-margin) var(--adv-space-40);
  }
  /* TWO EQUAL HALVES, NOT TWO SHRINK-WRAPPED COLUMNS ON A 23px GAP (AK,
     2026-08-31 — "the second column is shifted left"). 681:27073 starts the
     "Explore" column at x=181 of the 362 measure, which is the MIDPOINT, and
     neither column fills its half: the drawn boxes are 158 and 150. Read as a
     23px gap after content-width columns, the second landed at 179 on our
     labels — 22 left of the frame — and would move again the day a link is
     renamed, because the position depended on the length of the longest word
     in the column beside it. A half is a half whatever the words are. */
  .adv-footer__cols {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0;
    flex-basis: auto;
  }
  .adv-footer__brand { flex-basis: auto; }

  /* THE MOBILE CARD SET ROUNDS AT 8 (ADR-0017 §3–4, conflict 4). ADR-0014
     §5's "exactly two radii" becomes two per tier: every CARD surface —
     and the media rails that share a card's corners — takes the 8; the
     glass quick-link tiles, full-bleed media plates (hero, band, CTA,
     detail, article, map, split) and the open-filter panel keep the brand
     12, so both radii live on one phone screen, contained by naming. */
  .adv-card,
  .adv-area-card,
  .adv-person-card,
  .adv-office,
  .adv-quote,
  .adv-vacancy-card,
  .adv-insight__media { border-radius: var(--adv-m-radius-card); }
  .adv-media-card__media {
    border-start-start-radius: var(--adv-m-radius-card);
    border-end-start-radius: var(--adv-m-radius-card);
  }

  /* THE EXPERT CARD BECOMES A ROW (754:38466, ADR-0017 §8): a 130 × 129
     photo at the mobile radius with the name beside it — the desktop 719px
     portrait does not survive to 402, and this designed row is the answer
     that replaces guessing. The panel loses its fill and border: the row
     sits directly on the page, only the photo is a surface. */
  /* The listing instance (704:28512) is PANELLED: a 362 × 129 surface at
     the mobile radius, the 130 × 129 photo flush left (the card clips its
     corners), name 22 at the 20 inset, then the location/firm pair 32
     below — no role line on mobile. */
  /* 129 IS A HEIGHT, NOT A FLOOR (AK, 2026-09-02: the cards come out at
     different heights). `min-height` let any card whose text ran long grow,
     and the text runs long often: at 402 a name wraps once it passes 210px —
     measured 131 / 154 / 170 on the SAME six records at 402 / 375 / 360 —
     and a firm line like "Knijff Trademark Attorneys" wraps on its own. The
     frame draws a fixed 362 x 129 box (704:28511) with the text column pinned
     at 89 tall, which is precisely a design that does not grow.

     The two consequences are handled rather than left to overflow: the name
     clamps at two lines and each meta line at one. A two-line name still fits
     (48.4 + 32 = 80.4 against the 87 the padding leaves), so the clamp only
     bites on a third line — where the alternative is a ragged column. */
  .adv-person-card {
    flex-direction: row;
    gap: var(--adv-m-stack-gap);
    height: 129px;
    min-height: 0;
    background: var(--adv-color-surface-alt);
    border: var(--adv-border-width) solid var(--adv-color-border);
    overflow: hidden;
  }
  .adv-person-card__photo,
  .adv-person-card__photo--empty {
    width: 130px;
    /* 100%, NOT 129: the card is border-box, so its content box is 127 and a
       hard 129 made the photo — not the text — the thing that set the row's
       height. That is where the extra 2px came from (131 measured against the
       frame's 129) even on the cards whose text fitted. */
    height: 100%;
    flex-shrink: 0;
    aspect-ratio: auto;
    border-radius: 0;
  }
  .adv-person-card__photo--empty { font-size: var(--adv-m-title-size); }
  .adv-person-card__body {
    padding: var(--adv-m-stack-gap) var(--adv-m-stack-gap) var(--adv-m-stack-gap) 0;
    background: none;
    border: none;
    border-radius: 0;
  }
  .adv-person-card__name {
    /* `auto`, NOT 32. The frame's text column is `justify-between` on a fixed
       89 (704:29163): the name at the top, the meta pair at the bottom, and
       the 32 is what falls out for a ONE-line name. Written as 32 it was the
       one value that could not survive a second line — it pushed the meta pair
       down instead of eating the slack that was there for it. */
    margin-block-end: auto;
    /* THE CLAMP DECIDES HOW MANY LINES, THE FLEXBOX MUST NOT (AK, 2026-09-03:
       "expert lines height hides two lined names"). This is a flex item in a
       column of fixed height, so its default `flex-shrink: 1` let the layout
       squeeze the box BELOW two lines whenever the rows under it wanted the
       room — the second line was then cut through its middle by the `overflow`
       that the clamp needs, which reads as a rendering fault rather than as a
       truncation. Measured at 34px on a 48.4 two-line name. `0` makes the two
       lines a floor: the arithmetic has room for them (48.4 + the meta pair's
       32 is 80.4 against the 87 the padding leaves), so nothing else gives. */
    flex-shrink: 0;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: var(--adv-m-card-title);
    line-height: var(--adv-m-card-title-lh);
  }
  .adv-person-card__role { display: none; }
  .adv-person-card__role,
  .adv-person-card__meta {
    font-size: 12px;    /* the row's meta pair is 12/16 — measured, below the body step */
    line-height: 16px;
  }
  /* One line each, the pair 32 tall — which is what the fixed box is sized
     for. A wrapped firm name is the other way a card used to grow. */
  .adv-person-card__meta {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .adv-person-card__tags { display: none; }   /* the 754:38466 row carries no tags */
  /* THE SATELLITE ROW KEEPS BOTH CREDENTIAL LINES (760:17282): the desktop listing card
     prints one (ADR-0030 §7), the 402 row the pair its frame still draws. */
  .adv-person-card__meta--m { display: block; }
  /* THE MASTER ROW (AD-139): the name and the hidden role sit in `__head`, so
     the head — not the name — takes the `auto` that pins the one office line to
     the bottom, and the desktop's 26 between the groups goes. One meta line now:
     48.4 + 16 = 64.4 against the 87, where the firm/place pair was 80.4. The
     base `height: 129px` above wins on order over the desktop's 693. */
  .adv-person-card--listing .adv-person-card__body { gap: 0; padding-block-end: var(--adv-m-stack-gap); }
  .adv-person-card--listing .adv-person-card__head { margin-block-end: auto; }

  /* ---- THE RESULTS BLOCK RUNS ON 24, AND THE CLOSING BAND ON ONE 54 ----
     704:28373 (Frame 237) stacks the results head at y=0/44, the card list at
     68 and the pagination at 1236 under a list ending at 1212 — i.e. 24 above
     the cards and 24 above the pagination, where the sheet had the desktop 34
     in both places. */
  .adv-results { gap: var(--adv-space-24); }
  /* THE CHIP ROW'S PULL-DOWN IS KEYED ON THAT GAP, so it has to be restated
     with it: the rule in the 1100 block subtracts 34 because that is what the
     results stack gave it there. Left alone, the 54 the head asks for came out
     as 44 the moment the gap became 24 — the chips would have crept back down
     towards the head, undoing the correction the note upstairs describes. */
  .adv-results > .adv-applied-filters { margin-block-end: calc(54px - var(--adv-space-24)); }
  /* THE 54 WAS PAID TWICE (AK, 2026-09-02: the gap from the pagination down to
     "Need legal assistance?" is too big). The listing ends with 54 of padding
     and the closing band opens with 54 of its own, so the photograph landed
     108 below the pagination against the frame's 54 (Frame 237 ends at 1811,
     Group 196 starts at 1865). Measured on /articles/ and /experts/: 108.

     The LISTING gives its 54 up, not the band. The band is the one that has to
     carry the value — it also closes the practice-area detail (681:27056),
     where nothing above it supplies a gap and its own 54 is the whole of it.
     Scoped with `:has(+ …)` so a listing that ends the page keeps its foot,
     the same shape as the article head's rule further up. */
  .adv-listing:has(+ .adv-cta-band) { padding-block-end: 0; }

  /* PAGINATION SPANS THE COLUMN (704:29268: the row runs the width of the 362
     content column, item centres ~55 apart, chevrons at the two ends). The
     desktop control is a centred cluster on a 26 gap, which at 402 left the
     numbers huddled in the middle 138px of the screen and the chevrons — the
     two controls a thumb actually reaches for — nowhere near the edges. */
  .adv-pagination {
    justify-content: space-between;
    gap: var(--adv-space-8);
  }

  /* THE VACANCY CARD COMPACTS TO THE 130 ROW (760:12646): 24 of padding,
     title 22, and ONE 10px meta line — the office at medium weight left
     (AD-143: the office, where the row read "country, city"), the posted date
     right. The desktop panel's other blocks — the country and the tags with
     their date — do not survive to 402; the meta line's date is drawn ONLY
     here, so its base rule hides it. */
  .adv-vacancy-card {
    min-height: 0;
    gap: var(--adv-space-16);
    padding: var(--adv-space-24);
  }
  .adv-vacancy-card__title {
    max-width: none;
    min-height: 0;
    font-size: 22px;
    line-height: normal;
  }
  .adv-vacancy-card__info {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--adv-space-8);
  }
  .adv-vacancy-card__meta {
    font-size: 10px;
    line-height: normal;
    color: var(--adv-color-body);
  }
  .adv-vacancy-card__office { font-weight: var(--adv-weight-medium); }
  .adv-vacancy-card__country,
  .adv-vacancy-card__foot { display: none; }
  .adv-vacancy-card__posted { display: inline; }
  /* The list keeps the tier's 8 between items (the desktop frame draws none). */
  .adv-job-list { gap: var(--adv-space-8); }

  /* CAREERS DETAIL (760:13351): body blocks run on the 54 stack (head →
     firm 54, firm → role 54, role → photo 54); the sections inside each
     block keep the stack's own tighter rhythm. */
  .adv-job-detail { margin-block-start: 0; padding-block-start: 54px; }
  .adv-job-detail .adv-detail__body { gap: 54px; }

  /* ================= HOMEPAGE HEROES AT 402 =================
     The satellite's photograph hero (760:16467 — title, lede, a 448 photo with the
     bare search floating over its foot, the CTAs under it) retired in AD-145; the
     firm Home is `.adv-about-hero--home` now, with its own 402 rules in the ≤860
     block (1537:19268). What stays here is shared: a page hero opens 54 under the
     bar — the master homepage's does not, it is pulled under the bar at (0,2,0)
     in the ≤860 block (1537:18130) — and the narrow crop is claimed by the
     elements that carry one. */
  .adv-page-hero {
    display: flex;
    flex-direction: column;
    padding-block-start: 54px;
  }
  /* THE NARROW CROP IS CLAIMED ONLY BY THE ELEMENTS THAT CARRY ONE (AK,
     2026-09-03). An inline style cannot hold a media query, so the image partials
     emit the 402 pair as custom properties and this consumes them; the attribute
     selector tests whether THIS element was given a pair, because an undefined
     `var()` would compute `background-image` to `none` rather than fall back to
     the inline url. `!important` is structural: the desktop photograph is in the
     element's `style` attribute, which outranks any stylesheet rule. */
  .adv-page-hero__render[style*="--adv-bg-m"],
  .adv-about-hero__photo[style*="--adv-bg-m"],
  .adv-office-block__photo[style*="--adv-bg-m"] {
    background-image: var(--adv-bg-m-url) !important;
    background-image: var(--adv-bg-m) !important;
  }
  .adv-hero-search__row { gap: 0; }

  /* PRACTICE AREAS stack VERTICALLY here (Frame 251) — not the master
     homepage's sideways rail: NARROWED 75-rows on the page surface, one of
     them EXPANDED (255 — copy, the blue explore row, the corner) once
     tapped. :has scopes the un-railing to rows of area cards; rows of
     firm/insight cards keep scrolling. */
  .adv-card-row:has(.adv-area-card) {
    flex-direction: column;
    overflow-x: visible;
    margin-inline: 0;
    padding-inline: 0;
    gap: var(--adv-space-16);
    scroll-snap-type: none;
  }
  .adv-card-row:has(.adv-area-card) > * { flex: 0 0 auto; width: 100%; }
  /* THE COUNT SHOWS ON EVERY ACCORDION ROW, in both states (664:24471
     collapsed, 681:26795 expanded). It was the master's alone (`--counted`) and
     a firm site's row was a name and nothing else; the design QA brings the
     firm's "N experts" in too (ADR-0030 Amendment 1 §7 — experts only, a firm
     is one office). `--counted` now marks only the master's expanded layout
     below. */
  /* One column again: the 402 rows keep their unhyphenated names (AD-144). */
  .adv-grid--long-words .adv-area-card__title:is(:lang(nl), :lang(de)) { hyphens: manual; }
  .adv-grid--long-words .adv-area-card__count { text-align: start; }
  .adv-accordion .adv-area-card { transition: min-height 0.25s ease; }
  /* THE STACK IS AN ACCORDION (AK, 2026-08-27): tapping a row expands it
     in place — only the blue explore line navigates.

     EVERY CARD STARTS COLLAPSED (the client, ADR-0030 Amendment 2 §4). The
     first card used to be open STRUCTURALLY (`:first-child`) as the no-JS state
     and the initial paint, as 681:26795 and 760:16652 draw it; the client
     overruled both frames. So the collapsed row is the card's own look here —
     no script, no class — and `.is-expanded`, which site.js writes on a tap, is
     the only open look, winning on weight (0,3,0) against this (0,2,0).

     That also retires a slip: the listing engines sort by re-appending cards,
     so `:first-child` moved to whichever card sorted first while the script
     still took card 0 for the open one. `.is-collapsed` is still written by
     both scripts; it names the look this rule already gives, and is harmless. */
  .adv-accordion .adv-area-card {
    min-height: 75px;
    display: flex;
    justify-content: center;
    background: var(--adv-color-surface);   /* FAF9F7 — the page surface (754:38881), not the card warm */
  }
  .adv-accordion .adv-area-card .adv-area-card__text,
  .adv-accordion .adv-area-card .adv-area-card__more,
  .adv-accordion .adv-area-card .adv-area-card__corner { display: none; }
  .adv-accordion .adv-area-card .adv-area-card__body { flex: 0 0 auto; }
  /* The open card. `__text` is restated at (0,4,0): the master tier's
     `.adv-listing` rule strips listing-row copy, and an expanded card shows it
     (760:16652).

     `overflow` goes back with `display`: the base's `overflow: hidden` is half
     of the three-line clamp, and on a flex item it also suppresses the automatic
     minimum size (Flexbox §4.5), so the expanded card's copy — the whole point
     of the disclosure — would stay shrinkable. Undo both or neither. */
  .adv-accordion .adv-area-card.is-expanded {
    min-height: 255px;
    display: flex;
    justify-content: flex-start;
    background: var(--adv-color-surface-alt);
  }
  .adv-accordion .adv-area-card.is-expanded .adv-area-card__body { flex: 1; }
  .adv-accordion .adv-area-card.is-expanded .adv-area-card__text { display: block; overflow: visible; }
  .adv-accordion .adv-area-card.is-expanded .adv-area-card__more {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-block-start: auto;
    font-size: var(--adv-m-body-size);
    line-height: var(--adv-m-body-lh);
    font-weight: var(--adv-weight-medium);
    color: var(--adv-color-primary);
  }
  .adv-accordion .adv-area-card.is-expanded .adv-area-card__corner {
    display: block;
    position: absolute;
    top: var(--adv-space-24);
    right: var(--adv-space-24);
    color: var(--adv-color-ink);
  }
  /* THE OPEN CARD CENTRES ITS COPY, IT DOES NOT PIN ONE CHILD (AK,
     2026-09-03: "practice area card text should be centered vertically").

     760:17096 is a `justify-between` column of 314 x 207 holding the title, the
     copy and the explore line — so the COPY IS THE MIDDLE CHILD and lands in the
     middle of the card. Ours pinned only the explore line, with
     `margin-block-start: auto` on it, which produces a different picture from
     the same three boxes: title and copy locked together at the top and a hole
     between the copy and the foot. Both put the link on the floor, which is why
     this survived the first pass — the link was the thing being checked.

     The auto margin has to go with it: on a `space-between` column an `auto`
     margin eats every unit of free space before the distribution runs, so
     leaving it in would keep exactly the layout being replaced.

     `:not(--counted)` KEEPS THIS OFF THE MASTER, which wears that modifier on
     the same accordion and is signed off on the current look.

     AUTO MARGINS ON THE COPY, NOT `space-between` (AD-145 design QA): the count
     now sits in the body between the title and the copy, and a `space-between`
     column would have spread four children, pulling the count away from its
     title. Equal auto margins above and below the copy centre it between the
     title block and the explore line — the three-child picture, unchanged. */
  .adv-accordion:not(.adv-accordion--counted) .adv-area-card.is-expanded .adv-area-card__text {
    margin-block: auto;
  }
  .adv-accordion:not(.adv-accordion--counted) .adv-area-card.is-expanded .adv-area-card__more {
    margin-block-start: 0;
  }

  /* The listing's corner is a CLOSE control, in the accent blue
     (760:16652) — and a touch target, so it gets padded hit area. */
  .adv-area-card__corner--close {
    padding: 8px;
    margin: -8px;
    color: var(--adv-color-primary);
  }
  .adv-accordion .adv-area-card.is-expanded .adv-area-card__corner--close {
    color: var(--adv-color-primary);
  }

  /* PLAIN ROWS AT 402 — no numbers, no rules, the name over its text, rows 34 apart. Drawn
     first for the satellite's "Our values" (Frame 250; that band retired in AD-168), kept for
     the rows that still use it: the careers "how it works" (the `--values` split) and every
     `--wide` row — the careers "why join", and About's values and Join's benefits (`--top`). */
  /* `--wide` joins the split here. At 402 the frame draws BOTH row-sections the
     same way — the name over its line, no number, no rule (760:12485 and
     760:12523) — so the difference that matters on the desktop, label beside the
     rows against label above them, has none at this width. Two selectors rather
     than broadening to `.adv-values`, which would also catch a future numbered
     stack that wants to keep its numbers. */
  .adv-band__split--values .adv-value__num,
  .adv-values--wide .adv-value__num,
  .adv-band__split--values .adv-rule,
  .adv-values--wide .adv-rule { display: none; }
  .adv-band__split--values .adv-values,
  .adv-values--wide { gap: var(--adv-m-band-gap); }
  .adv-band__split--values .adv-value,
  .adv-values--wide .adv-value { display: block; }
  /* 32/500, NOT the 22/600 card title (AK, 2026-09-02). Reported as "the Our
     values headings are smaller than the design", and they were: this rule
     borrowed `--adv-m-card-title` (22, semibold — the vacancy card's step,
     754:38390) for a heading the About frame sets at **32px Inter Medium on a
     1.1 leading**, box 35 tall (623:23934). Two steps down and one weight too
     heavy. The same three-part row draws "Our vision" and "Our mission" (also
     35 tall on this frame), so the correction lands on all five headings.

     A LITERAL 32 rather than a new token: the tier's `--adv-m-*` set has no 32
     step — hero and band title are both 38, card title 22 — and minting one is
     an ADR under rule 5, which this fix should not be blocked on. Written here
     with the frame id so it converts cleanly when the mobile type scale is
     revisited; noted in the vault's ADR debt with the other four. */
  /* ---- CAREERS LANDING (760:12174) ------------------------------------
     THE SPLIT HERO KEEPS THIS FRAME'S HEAD (AD-143 — the 402 frame was not
     redrawn): the title 34 under the bar, the 362 x 185 plate 54 under the
     button, and the intro's label 54 under the plate (760:12174: the button
     ends at 334, the plate runs 388..573, the label opens at 627). About's
     stacked hero pays 54 above and 34 between; this page's numbers are its
     own frame's. The plate's ratio is the frame's (About's is 402/388). */
  .adv-about-hero--careers { padding-block-start: var(--adv-space-34); gap: 54px; }
  .adv-about-hero--careers .adv-about-hero__photo { aspect-ratio: 362 / 185; }
  .adv-band--careers-intro { padding-block-start: 54px; }
  /* THE CAREERS LISTING OPENS ON ITS PLATE here (AD-143): its h1 moved into the results
     head, so nothing precedes the 362 x 185 photograph but the bar — 54 under it, where
     the old title block stood (760:12865). Scoped to this listing: the detail pages that
     place their own title keep their order rules. */
  .adv-listing-photo:has(+ .adv-listing--careers) { margin-block-start: 54px; }
  /* 54 IN THE PAINTED BAND, and 24 under its label (760:12484 at y=54/19 with
     the rows at 97) — it was running on the section 34 and a 60 that came from
     an inline style, so the label floated in the middle of nothing while the
     band's own edges were tight. */
  .adv-band--why-join { padding-block: 54px; }
  .adv-band--why-join .adv-section-label { margin-block-end: var(--adv-space-24); }
  /* About's values and Join's benefits (AD-168): the label 24 over the rows, as why-join's. */
  .adv-stack--rows { gap: var(--adv-space-24); }
  /* 14/20, THE FRAME'S LEADING FOR THESE ROWS (760:12488 and 760:12526 are both
     40 for two lines), against the tier's 25 body step. Written as a sibling
     selector off the careers hero so it covers BOTH row bands on this page —
     "why join" and "how it works" are the same component on the same frame, and
     fixing one would leave the page arguing with itself.
     NOT the token: `--adv-m-body-lh` is 25 tier-wide and five frames now say 20
     (this one twice, 750:36866, 760:10732, 750:35904). That is an ADR, not a
     page fix, and it is in the vault's debt list. */
  .adv-about-hero--careers ~ .adv-band .adv-value__text { line-height: 20px; }

  .adv-band__split--values .adv-value__name,
  .adv-values--wide .adv-value__name {
    margin: 0 0 var(--adv-space-16);
    font-size: 32px;
    font-weight: var(--adv-weight-medium);
    line-height: 1.1;
  }

  /* OUR TEAM stacks its three row cards (Components 12–14, 362 × 129) —
     the same un-railing as the area stack. */
  .adv-card-row:has(.adv-person-card) {
    flex-direction: column;
    overflow-x: visible;
    margin-inline: 0;
    padding-inline: 0;
    gap: var(--adv-space-16);
    scroll-snap-type: none;
  }
  .adv-card-row:has(.adv-person-card) > * { flex: 0 0 auto; width: 100%; }

  /* The careers landing's three postings STACK too — the frame puts all three at
     x=0, 362 wide, on a 16 gap (760:12536: y=89, 295, 437), not on a rail. Third
     opt-out from the rail default, same shape as the two above; if a fourth
     arrives, invert the rule and let the rails opt IN instead. */
  .adv-card-row:has(.adv-vacancy-card) {
    flex-direction: column;
    overflow-x: visible;
    margin-inline: 0;
    padding-inline: 0;
    gap: var(--adv-space-16);
    scroll-snap-type: none;
  }
  .adv-card-row:has(.adv-vacancy-card) > * { flex: 0 0 auto; width: 100%; }

  /* The vacancy detail collapses to the 402 stack — one column, source order
     (meta, firm, copy), which is what 760:13351 draws. Every explicit placement
     above has to be undone or the single column keeps three empty tracks. */
  .adv-job-layout {
    grid-template-columns: 1fr;
    /* WAS 0, which was only ever right while the mobile stand-in photograph sat
       between the header and the title. With that removed (the frame draws no
       photograph here) the h1 rendered flush against the header. */
    padding-block-start: var(--adv-m-band-gap);
    /* THE HEAD GAP, not the band gap. 760:13367 groups title, dates and chips
       into one 198-tall block with 24 between them; the band rhythm belongs
       between that block and the ones after it, which take it as their own
       margin below. */
    row-gap: var(--adv-m-head-gap);
    /* THE PAGE MARGIN. `.adv-job-layout` is a bare grid — it never sat inside a
       `.adv-band__inner`, so on the desktop tier its `max-width: 1320` +
       `margin-inline: auto` supplied the gutters and nothing here did. At 402
       that leaves the title, the chips, the dates, the firm plate and both
       buttons running edge to edge while every neighbouring band is inset 20
       (760:13365 puts the whole block at x=20, w=362). */
    padding-inline: var(--adv-m-margin);
  }
  .adv-job-layout__title,
  .adv-job-layout__meta,
  .adv-job-layout__body,
  .adv-job-layout__firm { grid-column: 1; grid-row: auto; }
  /* The two blocks that follow the head pay the rest of the separation
     themselves — the row gap above is the head's 24, so these add the second 24
     to sit apart from it. */
  .adv-job-layout__body,
  .adv-job-layout__firm { margin-block-start: var(--adv-m-head-gap); }
  /* Inside the meta block the same 24 (760:13564 at y=108, 760:13579 at y=170
     against a title ending at 84), not the 34 the desktop column uses. */
  .adv-job-layout__meta { gap: var(--adv-m-head-gap); }
  /* Both blocks already carry a 24 top margin from the mobile tier, which INSIDE
     a flex column with a gap is a second mechanism for the same space: the chips
     sat 48 below the dates and the dates 24 below the top of their own column.
     The gap owns it here. */
  .adv-job-layout__meta > * { margin-block-start: 0; }
  /* The hiring office's button takes the column, as the closing band's does. */
  .adv-job-office > .adv-btn { align-self: stretch; }
  /* THE DATES COME BEFORE THE CHIPS AT 402 and sit on ONE line — the frame reads
     title → dates → chips (760:13564 at y=108, 760:13579 at y=170), the reverse
     of the desktop's 235 column, where the chips lead and the dates stack under
     them. Flex `order` rather than a second DOM block: one source order, two
     reading orders. `space-between` because the deadline group is flush right
     (x=223 of 362, w=139). */
  .adv-job-layout__meta .adv-job-meta {
    order: 1;
    flex-direction: row;
    justify-content: space-between;
    gap: var(--adv-space-24);
  }
  .adv-job-layout__meta .adv-job-tags { order: 2; }
  /* THE PHOTOGRAPH LEADS in the about-the-firm band (760:13723 — Rectangle 3 at
     y=0, the copy at y=184), the same swap the closing CTA makes below. Scoped
     by `:has()` to THIS photo: `.adv-band__split--media` is also the master's
     services band, which keeps its own order at 402. */
  .adv-band__split--media:has(.adv-job-firm-photo) .adv-job-firm-photo { order: -1; }
  .adv-job-firm-photo {
    /* `--squat` supplies `aspect-ratio: 362 / 150` here; the desktop ratio is
       overridden, not a height, so the plate stays fluid all the way down. */
    /* THE NARROW SOURCE. `image-set()` picks by density and cannot see the
       viewport, so without this a 402 screen downloads the 660 file — and a
       retina one the 1320. The custom properties come from `func/image-css.html`
       (`mobileWidth`), which always emits both, so neither `var()` is ever
       undefined. Two declarations, later-valid-wins: the plain url for anything
       that cannot parse `image-set`.

       `!important` IS THE MECHANISM, not a patch over one. Every photograph on
       this site is painted by an inline `style` attribute, and an inline
       declaration outranks any selector in a stylesheet — the first version of
       this rule was simply ignored and 402 kept resolving to the 660 file.
       Overriding an inline style is the one thing `!important` is actually for.
       It stays narrow: this rule matches a single class inside the mobile
       block. */
    background-image: var(--adv-bg-m-url) !important;
    background-image: var(--adv-bg-m) !important;
  }

  /* CLOSING CTA (Group 194): the photograph LEADS at 362 × 238, then the
     38 title, then the full-measure button. */
  .adv-cta-split { gap: var(--adv-space-24); }
  .adv-cta-split__media {
    order: -1;
    width: 100%;
    min-height: 0;
    height: 238px;
    border-radius: var(--adv-m-radius-card);
  }
  .adv-cta-split__body { align-self: stretch; }

  /* ================= SATELLITE ABOUT (760:16587) =================
     Composed like the homepage: the head's photograph moves into the
     362 × 185 slot BETWEEN the lede and the CTAs (the 742 band is a
     desktop composition), the offices+map band is not drawn at 402 at
     all — office details live on the contact page — and the approach
     rows run PLAIN: no numbers, no rules, the values band's own mobile
     treatment on this page's classes. */
  /* `--about` is a full-bleed desktop band whose 402 frame puts the same photograph in
     the padded head slot instead. The `.adv-page-head .adv-listing-photo` rule below is
     what replaces it. (`--careers` stood beside it until AD-143 moved that page to the
     split hero.) */
  /* (AD-145: the About head is the split hero now — `--about` and the offices band are
     gone; the office blocks stack, and the hero orders itself in the 860 block.) */
  /* The head slot sits inside the padded stack — the bleed margin comes
     off, and the stack's 20 tops up to the frame's 34 on both sides
     (130 → 164, 349 → 383). */
  .adv-page-head .adv-listing-photo {
    margin-inline: 0;
    margin-block: 14px;
    align-self: stretch;
    width: 100%;
  }
  /* ABOUT'S HEAD JOINS THE TIER'S RHYTHM AT BOTH ENDS (AK, 2026-09-03: too much
     air above the title, too much between the last button and "About us").

     It was the ONLY head on the satellite still paying the desktop's 105/76:
     the base rule's padding is overridden by `--listing` and `--master`, and
     About is the one screen wearing neither, so the correction the rest of the
     tier got never reached it. Measured against the two screens already signed
     off, the title sat at 178 where the homepage and every listing put theirs at
     127 — a page opening 51px lower than its neighbours.

     54 ABOVE, which is 127 under this bar and the number `.adv-detail-head`
     already carries with a note saying it is where `.adv-page-head` puts the
     listing title. NOTHING BELOW: `--statement` on the next band pays the
     frame's 54 once (760:16587 — second CTA ends 499, the label opens 553),
     instead of a head margin and a band padding adding up to 110.

     SCOPED THREE WAYS AND EACH ONE EARNS ITS KEEP. `--master` is every master
     head, which does not move on this pass. `--listing` has its own authored
     pair. `:has(h1)` excludes `detail-head.html`'s bandless section line, which
     wears this class to carry a `<p>` and would otherwise take a page head's
     spacing for a caption. */
  .adv-page-head:not(.adv-page-head--master):not(.adv-page-head--listing):has(h1) {
    padding-block: 54px 0;
  }
  .adv-band--statement { padding-block-start: 54px; }

  /* ---- JOIN: "HOW IT WORKS" CARDS HUG THEIR CONTENT (AD-185, ADR-0025 Amendment 24 §8) ----
     750:36734, the block the designer redrew on 2026-10-05 (MD: "скорректировала размеры
     плашек в фигме"): three 362 cards, 16 apart, 24 inside, the title (Regular 22, ink, a
     276 box — card 2 still wraps "Meet the Adverit Legal / team") 24 above its text (14/20,
     body colour), and the text no longer pinned to the foot: 119 / 166 / 159 tall. This
     reverses Amendment 23's fixed 196 box — a 148 column with the text justified to its
     foot and a two-line 54 title box whatever the title — which left the text 54 or 34
     under the title depending on its length. Desktop has packed it from the top since
     AD-168. The 1px rule is still paid out of the inset: Figma draws it inside the box,
     CSS outside, so 24 − 1 keeps the frame's sizes. 561–860 (2 + 1) and `--plain` (the
     satellite's practice-area card) are untouched; Join is the only `--benefit`. */
  .adv-area-card--benefit {
    padding: calc(var(--adv-space-24) - var(--adv-border-width));
  }
  .adv-area-card--benefit .adv-area-card__body {
    justify-content: flex-start;
    gap: var(--adv-m-head-gap);
    max-width: 314px;
  }
  .adv-area-card--benefit .adv-area-card__title {
    max-width: 276px;
    line-height: 1.21;
  }
  /* 20, not the body step's 25: the frame's paragraph box is 20 a line, and the colour is
     Text Secondary rather than the card's ink. The un-clamp this card needs is stated once,
     on the base rule, because it is true at every width — see `.adv-area-card--benefit
     .adv-area-card__text` beside the base `__text`. */
  .adv-area-card--benefit .adv-area-card__text {
    line-height: 20px;
    color: var(--adv-color-body);
  }
  /* …AND THE BLOCK AROUND THEM RUNS ON 54 (750:36734): the Benefits plate ends at 2214,
     "HOW IT WORKS" opens at 2268; the cards start 24 under the label; the last ends at 2787
     and "Submit a partnership enquiry" opens at 2841. They ran on the section 34 and the
     stack's 20. The enquiry band pays the 54 above its heading, as `--statement` does on
     About, so it holds whichever band comes before it. */
  .adv-band--how-it-works { padding-block-start: var(--adv-m-detail-gap); }
  .adv-band--how-it-works > .adv-stack--labelled { gap: var(--adv-m-head-gap); }
  .adv-band--enquiry { padding-block-start: var(--adv-m-detail-gap); }
  .adv-approach { gap: var(--adv-m-band-gap); }
  .adv-approach__num,
  .adv-approach__rule { display: none; }
  .adv-approach__head { gap: 0; }
  /* THE BAND'S OWN THREE GAPS, all from 760:17564 and all wrong before: the
     band opens at 1238 and its label sits at 1292 (54, not the tier's 34); the
     label's box ends at 1311 and the first row opens at 1335 (24, where the
     desktop's `--adv-sat-approach-gap` was putting 56); the last row ends at
     1916 and the paint ends at 1992 (76, not 34).

     The row-to-row 34 was already right, which is why this band read as almost
     correct — the rhythm inside it matched and everything around it did not.
     `:has(.adv-approach)` keeps it off the other warm bands, which are the same
     class on different compositions. */
  .adv-band--warm:has(.adv-approach) { padding-block: 54px 76px; }
  .adv-stack--approach { gap: var(--adv-space-24); }
  /* THE APPROACH ROW IS THE VALUES ROW'S TYPE, NOT A CARD TITLE'S (AK,
     2026-09-03). 760:17569 is 32px Inter Medium on `corporate/navy` at 1.1 —
     character for character the same as `.adv-value__name` two screens away
     (760:17363), which is what the two components are: a numbered stack of
     name-and-sentence rows. This carried `--adv-m-card-title` (22/24.2 at
     semibold) — the type a CARD uses for the thing inside it, borrowed for a
     band-level heading, so the rows read a size and a weight too small. */
  .adv-approach__title {
    font-size: 32px;
    font-weight: var(--adv-weight-medium);
    line-height: 1.1;
  }
  .adv-approach__text {
    font-size: var(--adv-m-body-size);
    /* 20, not the tier's 25 body step — 760:17570 draws a 60px box for three
       lines and every row on the frame repeats it. SIXTH page to need this
       written locally (careers twice, join, both insight cards, now About),
       which is the argument for moving `--adv-m-body-lh` itself; that is an
       ADR under rule 5 and is in the vault's debt list, awaiting AK's call. */
    line-height: 20px;
  }
  /* The team head's intro copy (a flat child beside label and button on
     About; the homepage wraps it in a stack — both take the full-width
     second row under the 25px label line). */
  .adv-related__head > .adv-approach__text {
    flex-basis: 100%;
    max-width: none !important;
  }

  /* HOMEPAGE BANDS ON THE 402 FRAME (597:19843). Three reworks:

     1. The band head becomes ONE 25px row — the section label left and its
        CTA right, drawn as a plain "View all" text link (Group 190: a
        52 × 25 text node), not the desktop's outlined pill. The label keeps
        the button's longer wording; only the form changes.
     2. The chip column becomes a full-bleed horizontal TAG RAIL (Frame 220:
        x=0, 402 wide, tags on an 8 gap) of UNIFORM 37px tags — on mobile
        the active tag recolours but does not grow: both instances on the
        frame measure 37, unlike the desktop's 45px active step.
     3. The services band keeps its photograph, 362 × 271 (Rectangle 71). */
  /* THE RAIL RUNS ON THE 54 STACK LIKE EVERY OTHER BAND AT THIS STEP, and its
     head sits 24 above the cards. Two frames agree: on 704:30027 the biography
     ends at 1669 and the band opens at 1723, its head at 1723/25 with the
     cards at 1772; on 681:27056 the same band opens 54 under the chips with the
     same 24 under its head. The sheet had the 1100 block's 60 and the desktop's
     40, which is a fifth rhythm on a screen that otherwise has one. */
  .adv-related { padding-block: var(--adv-m-detail-gap); }
  /* AND NO BAND MARGIN ON TOP OF THAT PADDING. `--adv-m-band-gap` is 34 and
     `--adv-section-gap` remaps to it at this step, so a self-padded band was
     opening 34 + 54 = 88 below whatever preceded it. The frames put 54 between
     these bands and nothing more: 704:30027 ends the biography at 1669 and
     starts the rail at 1723, then ends the rail at 2244 and starts the closing
     band at 2298; 681:27056 does the same twice. Both of these bands carry
     their own 54, so the margin is the duplicate — the same doubling the
     listing already had a rule for (`.adv-listing + .adv-cta-band`), reaching
     the two cases that rule does not cover.

     …EXCEPT THAT THE RELATED BAND IS PAINTED, and 54 inside a fill is not 54
     between blocks (AD-185, ADR-0025 Amendment 24 §4; MD's iPhone review,
     2026-10-05: "legal insights очень прибит к предыдущему разделу … 54px", on
     the lawyer and the office page). The rule above read the frames as "54 to
     the band's head" and put the whole 54 inside the paint, so the grey met the
     block above with nothing between — measured 0 under the lawyer's biography
     and under the office's last band, 54 on the practice-area and service pages
     only because two neighbours had been patched with a 54 margin of their own
     (`.adv-help` and `.adv-article-areas`, both retired here). So the band itself
     now takes 54 of page background above its fill, and keeps its 54 inside:
     one rule, order-agnostic, which is what the office page needs — its `main`
     is a flex column with `order`, so the block that visually precedes the band
     is not its DOM neighbour and no adjacency rule could name it. The frames draw
     this band UNPAINTED on mobile (704:30027 "INSIGHTS FROM THIS LAWYER",
     750:35822): MD kept the fill and asked for the gap. Both tiers — the
     satellite's article, lawyer, practice-area, service and topic pages carry
     the same band (ADR-0030 Amendment 17 §3). The closing band stays at 0: it is
     unfilled below 860. The base rule's exceptions (`.adv-listing +`, a plain
     non-flow `.adv-band +`) match no related band at this step — every one
     follows the expert detail, a flow band or the article's tags. */
  .adv-related { margin-block-start: var(--adv-m-detail-gap); }
  .adv-cta-band { margin-block-start: 0; }
  /* A LINE BREAK THE COPY ASKS FOR IS A DESKTOP BREAK (AD-185, ADR-0025 Amendment 24 §9).
     `copy-lines.html` writes a newline in the client's copy as an empty gap and a `<br>`:
     here the break goes and the gap carries the word space, so the text wraps on the phone's
     own measure — the careers closing band broke after "find" and the careers "How it works"
     note after "Vacancy details", in four languages, wherever the 362 had already wrapped
     them. Generated, not written: a minified page drops a space before `<br>`. */
  .adv-copy-br { display: none; }
  .adv-copy-gap::before { content: " "; }
  .adv-related__head,
  .adv-related__head--top {
    margin-block-end: var(--adv-space-24);
    /* --top is a GRID on desktop (its own columns and row placements) —
       display:flex must be restated or the row never forms on mobile.
       align-self too: inside an .adv-stack (align-items: flex-start) the
       head hugs its content and the link stops short of the right edge. */
    align-self: stretch;
    width: 100%;
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--adv-m-stack-gap);
  }
  .adv-related__head .adv-btn {
    height: auto;
    padding: 0;
    border: none;
    background: none;
    width: auto;
    font-size: var(--adv-m-body-size);
    line-height: var(--adv-m-body-lh);
    color: var(--adv-color-primary-dark);
  }
  /* "View all", not the full label (AK, 2026-09-02) — 597:19805 gives all three
     band heads a 52px link at x=330 while the section's noun sits at x=20 on the
     same 25px row. Measured before: 151 / 112 / 143 wide, so on the widest the
     link and the label nearly met in the middle of a 362 column, and every one
     of them said the noun twice. Both strings ship; see view-all.html. */
  .adv-view-all__long { display: none; }
  .adv-view-all__short { display: inline; }
  /* A head that carries INTRO COPY in a stack beside its label (the
     satellite team band): the stack flattens so the label shares the
     25px row with "View all" and the copy takes a full-width second row
     24 below (760:17276: label row 25, text at 49). */
  .adv-related__head { flex-wrap: wrap; row-gap: var(--adv-space-24); }
  .adv-related__head > .adv-stack { display: contents; }
  .adv-related__head .adv-section-label { order: -2; }
  .adv-related__head > .adv-btn { order: -1; margin-inline-start: auto; }
  .adv-related__head .adv-stack > .adv-value__text {
    flex-basis: 100%;
    max-width: none !important;   /* the 70ch cap is inline on the template */
    font-size: var(--adv-m-body-size);
    line-height: var(--adv-m-body-lh);
  }
  /* THE RAIL MUST NOT SIZE ITS TRACK. A grid item's min-width is `auto`,
     so the nowrap rail's min-content width (every tag side by side) blew
     the 1fr track past the viewport — the band background stopped at the
     screen edge and the tags kept going, and the page grew a layout
     viewport wider than the device (the zoom-out symptom on a real
     phone). min-width: 0 lets the track shrink and hands the overflow to
     the rail's own scroll. */
  .adv-band__split > *,
  .adv-switch-column { min-width: 0; }
  .adv-switch-column { align-self: stretch; }

  .adv-switch-chips,
  .adv-switch-chips--row {
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    align-self: stretch;
    margin-inline: calc(-1 * var(--adv-m-margin));
    padding-inline: var(--adv-m-margin);
    gap: var(--adv-m-chip-gap);
    -webkit-overflow-scrolling: touch;
    /* AND THE DESKTOP SIZING IS UNDONE (AK, 2026-08-31 — the services rail ran
       off the screen). `--row` carries `width: max-content` and
       `max-width: calc(100% + 60px)` so the desktop band's four chips reach into
       the split's gutter instead of wrapping. Neither survives a scrolling rail:
       `max-content` makes the TRACK as wide as its content, so the thing that
       was supposed to scroll internally pushed the page instead, and the
       max-width let it end 60 past the right margin.
       `align-self: stretch` above already gives the rail the column's width —
       it just never got to apply.

       `max-width: none`, NOT `100%`: the rail is deliberately full-bleed, pulled
       out to the screen edges by the negative margins so the first and last
       chips can sit flush with the 20 page margin. Capped at `100%` it stayed
       the COLUMN's 362 while starting at x=0, ending 40px short of the right
       edge — measured, and the sort of near-miss that reads as a stray gap
       rather than as a bug. */
    width: auto;
    max-width: none;
  }
  /* On mobile the active tag RECOLOURS but does not grow (597:19850: both
     instances are 37 tall). The attribute selectors are load-bearing — the
     desktop active rule sets a 16px size at (0,2,0) and a bare class here
     would lose to it. */
  .adv-badge,
  .adv-badge--active,
  .adv-badge[aria-current="true"],
  .adv-badge[aria-pressed="true"] {
    flex: 0 0 auto;
    /* 9/15, the same border correction as the desktop tag: 597:19952 draws
       37 tall and 9+17+9+2 is 37, where the drawn 10/16 gave 39. */
    padding: 9px 15px;               /* category tag size=big (597:19952) */
    font-size: var(--adv-m-tag-size);
    line-height: 1.21;               /* 17px box → the frame's 37px tag */
    font-weight: var(--adv-weight-regular);
  }
  .adv-badge[aria-current="true"],
  .adv-badge[aria-pressed="true"],
  .adv-badge--active { font-weight: var(--adv-weight-medium); }


  /* JOIN — the enquiry form on the 402 measure (754:36917): full-width
     fields on the 24 stack, the submit at the full measure. `form
     .adv-btn` is safe: the only other buttons inside forms are the
     search's own round control, which is not an .adv-btn. */
  .adv-form__fields { display: flex; flex-direction: column; gap: var(--adv-space-24); }
  .adv-field { width: 100%; }
  .adv-field input,
  .adv-field textarea,
  .adv-field select { width: 100%; }
  form .adv-btn { width: 100%; }
  /* THE APPLICATION FORM at 402 (AD-167; no frame — by analogy with the enquiry form's
     402): one column on the page margin, the field pairs stacked on the fields' 24, and
     each upload box stacked too — its chips or its two lines, then the button at the
     full measure (`form .adv-btn` above). The thanks sits the head gap under its title. */
  .adv-apply__col { grid-column: 1; }
  .adv-apply__pair { grid-template-columns: 1fr; gap: var(--adv-space-24); }
  .adv-upload__box {
    flex-direction: column;
    align-items: stretch;
    gap: var(--adv-space-16);
  }
  .adv-upload__input { max-width: 100%; }
  .adv-apply__col--done > .adv-band__text { margin-block-start: var(--adv-m-head-gap); }
  /* ============ SEARCH RESULTS (760:19099, both tiers) ============
     Title echoes the query over its count, then the field, then the KIND
     TAGS as a full-bleed rail, then the "Filters (N)" trigger + the same
     navy sheet the listings use, applied chips as their own rail with
     Clear all leading, and the result groups 54 apart — each kind with
     its own mobile shape: experts and articles scroll sideways, areas
     and services stack as narrowed 75-rows. */
  .adv-result-kinds {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    margin-inline: calc(-1 * var(--adv-m-margin));
    padding-inline: var(--adv-m-margin);
    gap: var(--adv-space-8);
    scrollbar-width: none;
  }
  .adv-result-kinds::-webkit-scrollbar { display: none; }
  .adv-result-kinds .adv-badge { flex: 0 0 auto; }
  .adv-search-results__rail > .adv-section-label { display: none; }
  [data-search] .adv-applied-filters {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    align-items: center;
    margin-inline: calc(-1 * var(--adv-m-margin));
    padding-inline: var(--adv-m-margin);
    gap: var(--adv-space-8);
    scrollbar-width: none;
  }
  [data-search] .adv-applied-filters::-webkit-scrollbar { display: none; }
  [data-search] .adv-applied-filters > * { flex: 0 0 auto; }
  /* "Clear all" LEADS the chip rail on the frame (760:19132). */
  /* (the search screen's own copy of this is gone — `.adv-applied-filters__clear`
     now carries `order: -1` for every row in the 560 block above.) */
  .adv-search-results__main { display: flex; flex-direction: column; gap: 54px; }
  /* Group head: label + View all share the 25px row, the count under. */
  .adv-result-group__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    row-gap: var(--adv-space-8);
    column-gap: var(--adv-m-stack-gap);
  }
  .adv-result-group__head .adv-section-label { margin: 0; }
  .adv-result-group__all {
    margin-inline-start: auto;
    font-size: var(--adv-m-body-size);
    line-height: var(--adv-m-body-lh);
    color: var(--adv-color-primary-dark);
  }
  .adv-result-group__count { flex-basis: 100%; order: 1; margin: 0; }
  .adv-result-group__head { margin-block-end: var(--adv-m-band-gap); }
  /* Experts and articles scroll SIDEWAYS (Frames 263 / 253). */
  .adv-result-group--lawyers .adv-result-cards,
  .adv-result-group--articles .adv-result-cards {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    margin-inline: calc(-1 * var(--adv-m-margin));
    padding-inline: var(--adv-m-margin);
    gap: var(--adv-space-24);
    scrollbar-width: none;
  }
  .adv-result-group--lawyers .adv-result-cards::-webkit-scrollbar,
  .adv-result-group--articles .adv-result-cards::-webkit-scrollbar { display: none; }
  /* The expert result is the 320 × 129 row card (Component 12). The
     media is RESTATED to block: the ≤860 "cards lose the media rail"
     rule predates the 402 frames, and this frame draws the photo. */
  .adv-result-group--lawyers .adv-media-card { flex: 0 0 320px; min-height: 129px; }
  .adv-result-group--lawyers .adv-media-card__media {
    display: block;
    width: 130px;
    height: 129px;
    object-fit: cover;
  }
  /* The article result is the COMPACT vertical post (270 × 240). */
  .adv-result-group--articles .adv-media-card {
    flex: 0 0 270px;
    flex-direction: column;
    min-height: 0;
  }
  .adv-result-group--articles .adv-media-card__media {
    display: block;
    width: 100%;
    height: 140px;
    object-fit: cover;
    border-start-start-radius: var(--adv-m-radius-card);
    border-start-end-radius: var(--adv-m-radius-card);
    border-end-start-radius: 0;
  }
  /* The monogram plate keeps its centring flex when it stands in. */
  .adv-result-group--lawyers .adv-media-card__media--empty,
  .adv-result-group--articles .adv-media-card__media--empty { display: flex; }
  /* Areas and services stack as NARROWED rows (75, title only). Topics
     (AD-166, no frame: MD's call 6) are the same row with their chips. */
  .adv-result-group--practice-areas .adv-result-cards,
  .adv-result-group--services .adv-result-cards,
  .adv-result-group--topics .adv-result-cards {
    display: flex;
    flex-direction: column;
    gap: var(--adv-space-16);
  }
  .adv-result-group--practice-areas .adv-topic-card,
  .adv-result-group--services .adv-topic-card,
  .adv-result-group--topics .adv-topic-card {
    min-height: 75px;
    display: flex;
    /* ROW restated: the base card is a COLUMN, where align-items:center
       reads as horizontal centring — the row wants the title LEFT at the
       24 inset (754:38881). */
    flex-direction: row;
    align-items: center;
    background: var(--adv-color-surface);
  }
  .adv-result-group--practice-areas .adv-topic-card__body,
  .adv-result-group--services .adv-topic-card__body { padding: 0 var(--adv-space-24); }
  .adv-result-group--practice-areas .adv-topic-card__snippet,
  .adv-result-group--services .adv-topic-card__snippet,
  .adv-result-group--topics .adv-topic-card__snippet { display: none; }
  /* A topic row GROWS past the 75 with its chips: the body keeps 16 above
     and below, and the chips hang 8 under the name (the body's 4 + 4) and
     wrap. The chip row's desktop 16 is keyed to the snippet, which is
     still in the DOM here, so the scoped (0,2,0) rule restates it. */
  .adv-result-group--topics .adv-topic-card__body { padding: var(--adv-space-16) var(--adv-space-24); }
  .adv-result-group--topics .adv-topic-card__chips { margin-block-start: var(--adv-space-4); }
  /* The compact cards' titles take the 22 card step — their base sizes
     (h2 on a topic row, h3 on a media row) are the 1440 desktop's. */
  .adv-topic-card__title,
  .adv-media-card__title {
    font-size: var(--adv-m-card-title);
    line-height: var(--adv-m-card-title-lh);
  }

  /* CONTACT (760:18841): title over its lede (16), then the 362 × 238
     photograph, then the form — one column on the 54 stack at the 20
     margin. The field set and the form machinery are the join page's. */
  /* EVERY 402 page title is NAVY — the contact frame binds corporate/navy
     on the h1 (760:18857) and every other mobile frame agrees, both
     tiers. The base ink is the satellite DESKTOP read (AD-75); it stays
     above the step. */
  .adv-page-title { color: var(--adv-color-primary-dark); }
  /* The field label at the frame's own metrics (760:18865): 10px in
     secondary at the 16 inset — the desktop's 26 is the pill's inset. */
  .adv-field__label { padding-inline-start: var(--adv-space-16); font-size: 10px; }
  .adv-field__error { padding-inline-start: var(--adv-space-16); }
  .adv-split-media { padding: 54px var(--adv-m-margin); gap: 54px; }
  .adv-split-media__head { display: flex; flex-direction: column; gap: var(--adv-space-16); }
  .adv-split-media__media {
    min-height: 0;
    height: 238px;
    /* THE DESKTOP'S 25 GOES (AK, 2026-09-03: the gap from the hero photo to the
       description). The base rule offsets the photograph by "a field label plus
       its 8" so that on the 1440 composition it starts level with the FIRST
       INPUT rather than with the top of the form — the two sit side by side
       there, and that alignment is the whole point of the value.

       At 402 nothing is beside anything: the frame stacks head → photo → form
       (760:18855) and spaces them 54 apart — 106 to 160, 398 to 452. So the
       alignment offset has nothing left to align to and simply adds itself to
       the grid gap, which measured 79 where the frame draws 54. It also
       inflated the row to 263 for a 238 photograph. */
    margin-block-start: 0;
    border-radius: var(--adv-m-radius-card);
  }
  /* The photo slot inside a band inherits the listing-photo look but the
     band's own 20 padding already places it — no extra margins. */
  .adv-band .adv-listing-photo { margin-inline: 0; }

  /* ARTICLE HEAD ON 402 (760:8183): title → DATE → author card, and the
     labelled practice-area row moves BELOW the body (760:8401). The
     byline dissolves so its children can reorder against the column. */
  .adv-article { display: flex; flex-direction: column; gap: var(--adv-m-stack-gap); }
  .adv-article__byline { display: contents; }
  .adv-article__date { order: -2; margin: 0; text-align: start; }
  .adv-article__byline .adv-person-mini { order: -1; }
  .adv-article__byline .adv-person-mini__photo {
    width: 80px;
    height: 80px;
    border-radius: var(--adv-radius-xs);
    object-fit: cover;
  }
  /* 760:8401 draws the same block the desktop frame does — label, then the
     chips 43 under it — so it needs no mobile rule beyond the page margin
     below; the `order: 1` that used to lift it past the body is gone with the
     markup that made it necessary. */
  /* The head rhythm off the satellite detail frame (760:18469 — the one
     drawn instance of this composition): title → date 8, date → author
     plate 34, plate → body 54. The article column's own gap is 20, so
     the plate margins top it up on both sides. */
  .adv-article__title { margin-block-end: var(--adv-space-8); }
  /* …AND NOTHING ON TOP WHEN THE HEAD ABOVE IT IS EMPTY (AK, 2026-09-03: the
     gap from the menu to the title looks big).

     The article's `.adv-detail-head` holds ONE child, the breadcrumbs, and no
     screen on this tier draws breadcrumbs at 402 — so the head renders as a
     54px box with nothing in it, and the title's own desktop 42 lands under it.
     54 + 42 = 96, which is where the title sat: 169 against the 127 the
     homepage, every listing and About all use. The frame agrees (760:18468 puts
     its first text at y=120 under the bar).

     The head keeps its 54, since that IS the tier's "54 under the bar", and the
     title gives up the 42 it only needs on the desktop composition. The `:has`
     guard is what makes this safe: if the head ever renders something besides
     breadcrumbs — a section line, the band branch of `detail-head.html` — the
     title keeps its margin and does not weld itself to that content. */
  .adv-detail-head:not(:has(> :not(.adv-breadcrumbs))) + .adv-article-body > .adv-article__title {
    margin-block-start: 0;
  }
  /* …AND 54 WHEN NOTHING BUT THE HIDDEN CRUMBS COMES BEFORE IT (AD-185, ADR-0025 Amendment
     24 §5). The article page has passed `title: false` since AD-143, so there is no head here
     any more, and the rule above no longer matches it: the section photograph used to sit
     under the bar instead, and the title followed it. On a phone the master's article draws
     no photograph now, which left only the title's desktop 42 under the bar; 760:8044 sets it
     at y = 120, the tier's 54. A satellite article keeps its photograph between the crumbs
     and the body, so this matches there only for an article without one — where 54 is the
     same answer. */
  .adv-breadcrumbs + .adv-article-body > .adv-article__title { margin-block-start: var(--adv-m-detail-gap); }
  .adv-article__byline .adv-person-mini,
  .adv-article .adv-person-mini {
    margin-block-start: 14px;
    margin-block-end: var(--adv-m-band-gap);
  }
  /* RELATED PRACTICE AREAS ON 402 (AD-185, ADR-0025 Amendment 24 §7; ADR-0030 Amendment 17
     §5). 760:8044 and the satellite's 760:18477 draw the same block: the body ends at 3967,
     the label opens at 4021 (54), the chips at 4064 — 24 under the label's 19 box — and the
     next block at 4146, 54 under the chips' 4092. The base rule's 34 gap and section-gap
     margin are desktop readings. 54 on BOTH sides, so the closing band (unfilled here, no
     margin of its own) gets its 54 too; before a related band the two 54s are one, the
     margins collapsing in the page's block flow. This replaces the `:has(+ .adv-related)`
     54 the tag row carried (AK, 2026-09-03): the related band pays its own 54 since AD-185. */
  .adv-article-areas {
    gap: var(--adv-m-head-gap);
    margin-block: var(--adv-m-detail-gap);
  }
  /* HOW WE CAN HELP AT 402 (681:27056). The label is the section label's 402 size; 24 →
     the chips, which are the switcher's sideways scroller above (no scrollbar, the 20 page
     margin, gap 8, both states 37, the `short` names) → 34 → the heading (32 Medium /
     1.1) → 16 → the text (14 / 20) → 24 → the topics, each a CARD: 362 wide, surface-alt
     on a 1 px border, radius 8, 24 inside; the name 22, 16 → the count 10, all blue; a ↗
     at 330 × 34 and no "View topic" text — the whole card is the link. Cards 16 apart.
     54 → Related insights (the painted band). */
  /* The label keeps its AUTO box (16 × 1.21 = 19, 681:27056's text box): the ≤860 rule
     gives `--auto` labels the label token's 25, which would put the chips 6 lower than
     the frame's 43 under the label's top. (0,2,0), for this block only. */
  .adv-help .adv-section-label--auto { line-height: var(--adv-small-lh); }
  .adv-help__chips { margin-block-start: var(--adv-m-head-gap); }
  .adv-help__long { display: none; }
  .adv-help__short { display: inline; }
  .adv-help__panel { margin-block-start: var(--adv-space-34); row-gap: var(--adv-space-24); }
  .adv-help__heading {
    font-size: var(--adv-help-m-heading);
    font-weight: var(--adv-weight-medium);
    line-height: var(--adv-m-title-lh);
  }
  .adv-help__text {
    font-size: var(--adv-m-body-size);
    line-height: var(--adv-help-m-text-lh);
  }
  /* (0,2,0) in the list, to undo the desktop rule between rows. Inset 24 from the card's
     outer edge, the 1 px border inside it (Figma strokes inside). */
  .adv-help__topic,
  .adv-help__topic + .adv-help__topic {
    box-sizing: border-box;
    display: block;
    min-height: 0;
    margin-block-start: 0;
    padding: calc(var(--adv-space-24) - var(--adv-border-width));
    /* Clear the ↗ (9 wide, 24 from the edge) by 8: the frame's text box runs 314 wide,
       under the arrow's column, which only its short sample names get away with. */
    padding-inline-end: calc(var(--adv-space-24) + 9px + var(--adv-space-8));
    background: var(--adv-color-surface-alt);
    border: var(--adv-border-width) solid var(--adv-color-border);
    border-radius: var(--adv-m-radius-card);
  }
  .adv-help__topic + .adv-help__topic { margin-block-start: var(--adv-m-tile-gap); }
  .adv-help__topic-name {
    display: block;
    font-size: var(--adv-m-card-title);
    line-height: var(--adv-h3-lh);
  }
  .adv-help__topic-meta {
    display: block;
    margin-block-start: var(--adv-space-16);
    font-size: var(--adv-caption-size);
    line-height: var(--adv-caption-lh);
    color: var(--adv-color-primary);
  }
  /* The link covers the card; its text goes to the screen reader only (`.adv-sr-only`'s
     clip, not `display: none`, which would take the name away). The link itself stays
     static, so its `::after` and the ↗ are placed on the card (the row's `position:
     relative` and the `::after` are the base's since AD-172; the card adds its border's
     inset, its radius and the focus ring). */
  /* No box of its own in the card's flow: its text is clipped and its ↗ is placed on the
     card, and an empty inline box would still make a 25 line under the count. */
  .adv-help__view { display: block; height: 0; }
  .adv-help__view-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .adv-help__view .adv-icon {
    position: absolute;
    top: calc(var(--adv-space-34) - var(--adv-border-width));
    right: calc(var(--adv-space-24) - var(--adv-border-width));
  }
  a.adv-help__view::after {
    inset: calc(-1 * var(--adv-border-width));
    border-radius: var(--adv-m-radius-card);
  }
  a.adv-help__view:focus-visible { outline: none; }
  a.adv-help__view:focus-visible::after {
    outline: var(--adv-focus-ring-width) solid var(--adv-focus-ring);
    outline-offset: var(--adv-focus-ring-offset);
  }
  /* TOPICS BY PRACTICE AREA AT 402 (1734:29837): the label (16 caps, 19) → 24 → THE PILL
     AT FULL WIDTH, 362 × 56 (the light 56 control of the listings' search), its name 14
     Medium centred with the caret, 26 inside → 24 → the heading, where the chips' block has
     34. Everything below the heading is How we can help's 402 block above. The name may
     take two lines inside the pill (a floor, not a height), and the menu is the pill's
     width, so neither can widen the page. The caret stays the header's 8: the frame's 10.7
     is the Office caret's slip the hero leaves too. (0,2,0), after the ≤560 `.adv-filter`
     rule. */
  .adv-help--menu .adv-filter {
    width: 100%;
    min-width: 0;
    height: auto;
    min-height: var(--adv-m-search-h);
    padding-inline: var(--adv-space-26);
    gap: var(--adv-space-8);
    font-size: var(--adv-small-size);
    line-height: var(--adv-small-lh);
    text-align: center;
  }
  .adv-help--menu .adv-filter-panel {
    inset-inline: 0;
    min-width: 0;
  }
  .adv-help--menu .adv-help__panel { margin-block-start: var(--adv-space-24); }
  [data-switcher-panel] { scroll-margin-top: calc(var(--adv-m-header-h) + var(--adv-border-width)); }
  .adv-apply,
  .adv-apply-done,
  .adv-apply .adv-form-banner--target { scroll-margin-top: calc(var(--adv-m-header-h) + var(--adv-border-width)); }
  /* NO "RELATED LAWYERS" ON A PHONE (AD-185, ADR-0025 Amendment 24 §7, ADR-0030 Amendment
     17 §5; MD, 2026-10-05: "В дизайне нет related lawyers, давай их уберем"). Neither
     article frame draws the column at 402 (760:8044, 760:18469) — it was AD-153's
     practice-area rail tiles under the body (Amendment 22). Desktop and 561–1439 keep it.
     Its portraits are `loading="lazy"`, so a column that is not rendered fetches none. The
     `--experts` grid modifier sets nothing at this step that the one-column grid needs. */
  .adv-article__experts { display: none; }

  /* A long article title must break, not escape: the body grid's 1fr has
     the min-width:auto floor (again), and an unbroken word rode it past
     the measure. */
  .adv-article-body { grid-template-columns: minmax(0, 1fr); }
  .adv-article__title,
  .adv-article-body h1 { overflow-wrap: break-word; }

  /* THE PAGE MARGIN IS 20, NOT 26 (ADR-0017 §3, conflict 1). Every band on
     597:19805 starts at x=20 and is 362 wide; the 26 this sheet relaxed to
     below 1100 was authored under B2 and is superseded at the mobile step.
     Last in the block so it wins over the width-specific rules above. */
  .adv-band__inner,
  .adv-page-head,
  .adv-breadcrumbs,
  .adv-listing,
  .adv-cta-band__inner,
  .adv-detail,
  .adv-detail-head,
  .adv-article-body,
  .adv-article-areas,
  .adv-split-media,
  .adv-hero__content,
  .adv-footer__bottom { padding-inline: var(--adv-m-margin); }
}

/* (The `(hover: none)` undo of the card scale that lived here is gone: the whole
   card hover is gated on `(hover: hover)` where it is declared.) */

/* ---------------------------------------------------------------------
   Image placeholder (PREVIEW SCAFFOLDING ONLY — not a brand token)
   Fills media slots in the styleguide so structure is visible without
   assets. Never ship it on a real page.
   --------------------------------------------------------------------- */
.adv-imgph {
  display: flex;
  align-items: center;
  justify-content: center;
  background: repeating-linear-gradient(45deg,
    var(--adv-color-surface-alt) 0 11px,
    var(--adv-color-border) 11px 22px);
  font-family: var(--adv-font-mono);
  font-size: var(--adv-eyebrow-size);
  color: var(--adv-color-body);
}
/* =====================================================================
   Adverit master site — layout layer
   Page glue not shipped by the design system. Token-only (var(--adv-*)),
   no raw colours/sizes (CLAUDE.md rule 5). Brand components come from
   design-system/css/components.css.

   AD-76 REMOVED THE v1 HEADER AND HOMEPAGE LAYER from this file. The header,
   the footer and the homepage are design-system components now
   (`.adv-nav`, `.adv-footer`, the bands), so their glue here was not merely
   redundant — it FOUGHT the shared layer. The worst of it was a
   `@media (max-width:900px)` block that set `.adv-nav__links { display:none;
   position:absolute }`, one breakpoint away from the design system's own
   860px nav rules: two collapsing navs on one element, and which one won
   depended on the viewport.

   Gone with it: `.hero-stats`, `.discover-launch*`, `.entry-chip*`,
   `.area-*`, `.region*`, `.firm-grid` — all of them the old homepage's, and
   all of them unreferenced now. `.firm-card__*`, `.partner-card*`,
   `.agg-card*`, the facet rail and the chips STAY: /discover/, /articles/
   and /search/ still render them, server-side and from facets.js. They go
   when those screens are rebuilt, not before.
   ===================================================================== */

/* Accessibility */
.skip-link { position:absolute; left:-9999px; top:0; z-index:100; background:var(--adv-color-primary); color:var(--adv-color-white); padding:var(--adv-space-8) var(--adv-space-16); border-radius:var(--adv-radius-button); }
.skip-link:focus { left:var(--adv-space-8); top:var(--adv-space-8); }

/* Section heading + breadcrumb */
.section-head { max-width:760px; margin:0 auto var(--adv-space-32); text-align:center; }
.section-head .adv-eyebrow { color:var(--adv-color-link); }
.section-head h2 { margin:var(--adv-space-12) 0; }
.breadcrumb { font-family:var(--adv-font-mono); font-size:12px; color:var(--adv-text-muted); margin:0 0 var(--adv-space-12); }
.breadcrumb a { color:var(--adv-color-link); text-decoration:none; }

/* Search field on the listing screens (/discover/, /articles/, /search/) */
.hero-search { display:flex; gap:var(--adv-space-8); max-width:520px; }
.hero-search input { flex:1; font-family:var(--adv-font-body); font-size:15px; padding:12px 14px; border:none; border-radius:var(--adv-radius-button); }
.hero-search--inline { max-width:560px; margin-top:var(--adv-space-16); }
.hero-search--inline input { border:var(--adv-border); }

/* Firm card — still rendered by facets.js on /discover/ */
.firm-card { display:flex; flex-direction:column; gap:var(--adv-space-12); padding:var(--adv-space-24); text-decoration:none; }
.firm-card__head { display:flex; align-items:center; gap:var(--adv-space-12); }
.firm-card__head > div { min-width:0; }
.firm-card__mono { display:inline-flex; align-items:center; justify-content:center; width:38px; height:38px; flex-shrink:0; border-radius:var(--adv-radius-pill); background:var(--adv-color-tint); color:var(--adv-color-primary); font-family:var(--adv-font-heading); font-weight:var(--adv-weight-bold); }
.firm-card__name { margin:0; font-family:var(--adv-font-heading); font-weight:var(--adv-weight-semibold); font-size:15px; color:var(--adv-text); }
.firm-card__place { margin:0; font-size:12.5px; color:var(--adv-text-muted); }
.firm-card__url { margin:0; font-family:var(--adv-font-mono); font-size:11.5px; color:var(--adv-color-link); }
/* AD-42: logo tile (falls back to the monogram), lawyer count, and the master-preview badge. */
.firm-card__mono--logo { background:var(--adv-color-surface); overflow:hidden; }
.firm-card__mono--logo img { width:100%; height:100%; object-fit:contain; display:block; }
.firm-card__meta { margin:0; font-size:12.5px; color:var(--adv-text-muted); }
.firm-card__url { margin-top:auto; }
.firm-card__badge { align-self:flex-start; }
.firm-card--preview { border:1px dashed var(--adv-color-tint-edge); }
/* AD-53: article sibling of the master-preview firm badge — same dashed edge + badge. */
.agg-card__badge { align-self:flex-start; margin:var(--adv-space-8) 0 0; }
.agg-card--preview { border:1px dashed var(--adv-color-tint-edge); }

/* Filter layout */
.filter-layout { display:grid; grid-template-columns:260px 1fr; gap:var(--adv-space-48); align-items:start; }
.facets-toggle { display:none; }
.facet { margin-bottom:var(--adv-space-24); }
.facet__title { display:flex; justify-content:space-between; font-family:var(--adv-font-heading); font-weight:var(--adv-weight-semibold); font-size:13px; color:var(--adv-text); margin:0 0 var(--adv-space-8); }
.facet__step { font-family:var(--adv-font-mono); color:var(--adv-color-faint); }
.facet__hint { font-size:12px; color:var(--adv-text-muted); margin:0 0 var(--adv-space-8); }
.facet__list { display:flex; flex-direction:column; gap:2px; }
.facet__opt { display:flex; align-items:center; gap:var(--adv-space-8); width:100%; background:none; border:none; cursor:pointer; padding:6px 8px; border-radius:var(--adv-radius-button); font-family:var(--adv-font-body); font-size:14px; color:var(--adv-text-body); text-align:left; }
.facet__opt:hover { background:var(--adv-color-tint); }
.facet__opt[disabled] { opacity:0.4; cursor:not-allowed; }
.facet__box { width:15px; height:15px; flex-shrink:0; border:1.5px solid var(--adv-color-tint-edge); border-radius:var(--adv-radius-xs); }
.facet__opt[aria-pressed="true"] .facet__box { background:var(--adv-color-primary); border-color:var(--adv-color-primary); }
.facet__opt .label { flex:1; }
.facet__count { font-family:var(--adv-font-mono); font-size:11px; color:var(--adv-text-muted); }

/* Results bar / chips */
.results-bar { display:flex; align-items:center; justify-content:space-between; gap:var(--adv-space-16); margin-bottom:var(--adv-space-12); }
.results-count { margin:0; font-size:14px; color:var(--adv-text-body); }
.results-sort { font-family:var(--adv-font-body); font-size:13px; padding:8px 10px; border:var(--adv-border); border-radius:var(--adv-radius-button); background:var(--adv-bg-card); }
.chips { display:flex; flex-wrap:wrap; align-items:center; gap:var(--adv-space-8); margin-bottom:var(--adv-space-16); }
.chips__label { font-family:var(--adv-font-mono); font-size:11px; text-transform:uppercase; letter-spacing:0.06em; color:var(--adv-text-muted); }
.chip { display:inline-flex; align-items:center; gap:6px; font-size:13px; color:var(--adv-color-primary); background:var(--adv-color-tint); border:1px solid var(--adv-color-tint-edge); padding:4px 6px 4px 10px; border-radius:var(--adv-radius-pill); }
.chip__kind { font-family:var(--adv-font-mono); font-size:10px; text-transform:uppercase; color:var(--adv-text-muted); }
.chip__x { background:none; border:none; cursor:pointer; font-size:15px; line-height:1; color:var(--adv-color-primary); padding:0 2px; }
.chips__clear { background:none; border:none; cursor:pointer; font-size:13px; color:var(--adv-color-link); text-decoration:underline; }

/* Feeds */
.feed { display:flex; flex-direction:column; gap:var(--adv-space-16); }
.feed-empty { padding:var(--adv-space-48); text-align:center; background:var(--adv-bg-card); border:var(--adv-border); border-radius:var(--adv-radius-card); }

/* Partner card (discover) — auto-fill so cards stay wide inside the faceted
   layout (the directory grid shares the row with a 260px filter sidebar, so a
   fixed 4-column grid collapses each card and overflows its text). */
.partner-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(260px, 1fr)); gap:var(--adv-space-24); }
.partner-card { display:flex; flex-direction:column; gap:var(--adv-space-12); padding:var(--adv-space-24); text-decoration:none; }
.partner-card__head { display:flex; align-items:center; gap:var(--adv-space-12); }
.partner-card__head > div { min-width:0; }
.partner-card__head .firm-card__mono { width:38px; height:38px; }
.partner-card__cc { margin-left:auto; font-family:var(--adv-font-mono); font-size:11px; color:var(--adv-text-muted); border:var(--adv-border); border-radius:var(--adv-radius-xs); padding:2px 6px; }
.partner-card__foot { display:flex; justify-content:space-between; gap:var(--adv-space-8); font-size:12px; color:var(--adv-text-muted); }
.partner-card__visit { font-family:var(--adv-font-mono); color:var(--adv-color-link); }

/* Aggregated article card (articles archive) */
.agg-card { display:flex; flex-direction:column; }
.agg-card__top { display:flex; align-items:center; gap:var(--adv-space-12); padding:var(--adv-space-16) var(--adv-space-24); border-bottom:1px solid var(--adv-color-border-soft); }
.agg-card__firmdot { display:inline-flex; align-items:center; justify-content:center; width:30px; height:30px; border-radius:var(--adv-radius-pill); background:var(--adv-color-primary); color:var(--adv-color-white); font-family:var(--adv-font-heading); font-weight:var(--adv-weight-semibold); font-size:12px; }
.agg-card__firm { font-family:var(--adv-font-heading); font-weight:var(--adv-weight-semibold); font-size:13.5px; color:var(--adv-text); }
.agg-card__place { font-size:11.5px; color:var(--adv-text-muted); }
.agg-card__locale { margin-left:auto; font-family:var(--adv-font-mono); font-size:11px; color:var(--adv-text-muted); border:var(--adv-border); border-radius:var(--adv-radius-xs); padding:2px 6px; }
.agg-card__body { padding:var(--adv-space-24); }
.agg-card__date { font-family:var(--adv-font-mono); font-size:11px; color:var(--adv-text-muted); margin:0 0 var(--adv-space-8); }
.agg-card__title { margin:0 0 var(--adv-space-8); font-size:18px; }
.agg-card__title a { color:var(--adv-text); text-decoration:none; }
.agg-card__title a:hover { color:var(--adv-color-primary); }
.agg-card__summary { margin:0 0 var(--adv-space-12); font-size:14px; line-height:1.6; color:var(--adv-text-muted); }
.agg-card__foot { display:flex; align-items:center; justify-content:space-between; gap:var(--adv-space-12); margin-top:var(--adv-space-12); font-size:13px; }
.agg-card__author { color:var(--adv-text-muted); }
.agg-card__source { color:var(--adv-color-link); text-decoration:none; font-weight:var(--adv-weight-semibold); }

/* AD-43: universal search results */
.search-group + .search-group { margin-top:var(--adv-space-48); }
.search-more { margin-top:var(--adv-space-16); }

/* Tag chip (shared with firm theme — not in DS) */
.tag-row { display:flex; flex-wrap:wrap; gap:var(--adv-space-8); }
.tag { display:inline-block; font-family:var(--adv-font-heading); font-weight:var(--adv-weight-medium); font-size:12px; color:var(--adv-color-primary); background:var(--adv-color-tint); border:1px solid var(--adv-color-tint-edge); padding:3px 10px; border-radius:var(--adv-radius-pill); text-decoration:none; }

/* Responsive.
   NOTE there is no nav block here any more. The header collapses at 860px in
   design-system/css/components.css, and this file used to collapse it again at
   900 with a different mechanism — see the header note at the top. */
@media (max-width:1024px){
  .partner-grid { grid-template-columns:repeat(2,1fr); }
  .filter-layout { grid-template-columns:1fr; }
  .facets-toggle { display:inline-flex; }
  .facet-panel { display:none; margin-top:var(--adv-space-16); }
  .facet-panel.is-open { display:block; }
}
@media (max-width:560px){
  .partner-grid { grid-template-columns:1fr; }
}
