/* ===========================================================================
   editorial.css — the Coastal SD Pros editorial design system.

   READ THIS BLOCK. It is the whole contract. Every downstream page and every
   downstream agent builds on the classes named here. If you invent a class
   instead of using one below, the directory stops looking like one publication
   and starts looking like a template, which is the exact thing a homeowner
   with a $20,000 decision reads as "this site is not serious".

   ---------------------------------------------------------------------------
   0. LOAD ORDER — NOT OPTIONAL
   ---------------------------------------------------------------------------
       <link rel="stylesheet" href="/assets/tool-chassis.css">
       <link rel="stylesheet" href="/assets/editorial.css">

   tool-chassis.css is a hard dependency. It declares the ten canon palette
   tokens and it owns the form primitives, the provenance chip, the honest
   blank, the live region and the no-JS notice. THIS FILE REDEFINES NONE OF
   THEM. There is not one `.tc-` rule in this file and not one colour literal
   below the token block — both are grep-checkable, keep both true.

   Use the chassis classes directly wherever they fit:
       .tc-control .tc-label .tc-hint .tc-select .tc-text .tc-error
       .tc-btn .tc-btn--primary .tc-btn--quiet .tc-actions
       .tc-chip .tc-chip--held        (provenance: "SOURCE · checked DATE")
       .tc-live .tc-status .tc-nojs .tc-sr  [data-tc-js-only]

   They work anywhere on an editorial page because `.ed-page` re-declares the
   chassis's derived tokens at page scope — see CHASSIS TOKEN BRIDGE below.
   The chassis puts those tokens on `.tc-tool`, and every one of the primitives
   above is used here OUTSIDE a `.tc-tool`. Delete that bridge and the submit
   button in the filter bar turns into white text on nothing.

   ---------------------------------------------------------------------------
   1. TYPE SYSTEM
   ---------------------------------------------------------------------------
   TWO FACES, and only two.

   --ed-font-editorial   The headline face. NEWSREADER, self-hosted from
                         assets/fonts/ as a variable woff2 (wght 200-800,
                         opsz 6-72). No CDN, no remote request. Falls back to
                         Iowan Old Style (Apple) / Georgia (Windows) / Noto
                         Serif (Android) if the files ever go missing.
                         Used for: h1/h2/h3, business names, pull quotes.
                         Because it is variable, 400-700 are all real weights,
                         not synthesised.
   --ed-font-interface   Everything else: body, labels, buttons, ALL NUMERALS.
                         Same stack v4.css already uses, so nothing shifts.
                         NOTE, measured: Inter leads that stack but is NOT
                         installed and is NOT self-hosted anywhere in this
                         repo, so on Windows it resolves to Segoe UI via
                         system-ui. That is fine — Segoe UI has true tabular
                         lining figures — but do not assume Inter is present.

   HARD RULE — NO DIGITS IN THE EDITORIAL FACE.
   The fallbacks (Iowan Old Style, Georgia) default to OLD-STYLE, non-lining
   figures. A "4.9" set in them sits below the baseline and will not align
   with a "4.9" set in the interface face, so the moment the webfont fails
   the column breaks. Every rating, review count, year, price and date in
   this system is therefore set in --ed-font-interface, which is also why
   the numerals survived the font swap intact. If a headline must carry a
   digit, wrap it in `.ed-lining`.

   TYPE LADDER — whole pixels at a 16px root. Was a 1.200 modular scale, which
   computed to 11.1px and 13.3px; fractional sizes render soft and were the
   source of every odd size on the homepage and the listing pages. Steps now
   land on 12/14/16/20/24/32/40/48, still in rem so user zoom is preserved.
   --ed-t--2  0.75rem   12px     micro label, eyebrow, chip, term
   --ed-t--1  0.875rem  14px     meta, caption, card fact value
   --ed-t-0   1rem      16px     interface body
   --ed-t-1   1.25rem   20px     lead-in, card name (narrow)
   --ed-t-2   1.5rem    24px     card name, h4
   --ed-t-3   1.75rem   28px     h3, rating value
   --ed-t-4   2rem      32px     h2 floor
   --ed-t-5   2.5rem    40px     h1 floor
   --ed-t-6   3rem      48px     h2 ceiling / h1 mid
   --ed-t-7   3.5rem    56px     h1 ceiling (display only)
   Fluid heads clamp BETWEEN two real steps. Never type a size that is not
   on the scale.

   NUMERALS — --ed-nums is `tabular-nums lining-nums`, applied to every
   numeric element in this file. That is what makes 25 ratings and 25 review
   counts form true columns down a list. Do not override it to
   `proportional-nums` anywhere.

   MEASURE (line length) — max-width tokens, in ch, so they follow the face:
   --ed-measure-prose  66ch  editorial prose, article body, guide copy
   --ed-measure-deck   52ch  section decks and standfirsts
   --ed-measure-card   44ch  ALL text inside a business card
   --ed-measure-micro  38ch  captions, notes, why-it-appears
   Applied by .ed-prose / .ed-deck / .bc (card text inherits the card measure).

   TYPE UTILITIES
   .ed-display    h1 scale, editorial face, tight leading. Page title only.
   .ed-h1 .ed-h2 .ed-h3 .ed-h4   Editorial face heads on the scale above.
   .ed-eyebrow    Micro uppercase kicker above a head. Pacific 700. The ONLY
                  place uppercase is allowed. Never uppercase body copy.
   .ed-deck       Standfirst under a head. Interface face, 52ch.
   .ed-prose      Editorial body copy block, 66ch, spaced paragraphs.
   .ed-lead       One emphasised opening paragraph.
   .ed-micro      11px meta line. Tabular numerals on.
   .ed-num        Forces the interface face + tabular lining figures on any
                  inline number that sits inside editorial text.
   .ed-lining     Lining figures without changing face (headline escape hatch).

   ---------------------------------------------------------------------------
   2. PALETTE — mapped onto the canon tokens, no new hue
   ---------------------------------------------------------------------------
   Canon token          Editorial role                       Contrast
   Pacific 900          primary ink, strong rules, primary    11.89:1 on white
                        button ground                         11.21:1 on ground
   Pacific 700          secondary ink, links, labels           6.97:1 on white
                                                               6.58:1 on ground
   Ocean 600            CONTROL EDGES ONLY, never text         4.17:1 on white
                        (4.17 clears 3:1 non-text, fails 4.5 normal text)
   Aqua 400             THE accent. Rules, marks, active bar.  1.69:1 on white
                        NEVER text on a light ground. It is    7.02:1 on navy
                        legible only as navy-on-aqua or as
                        aqua-on-navy.
   Sand 200             warm ground, band, honest-blank edge    9.46:1 w/ P900
   Coral 400            correction/alert marker BAR only, never text
   Sky 400 / Sun 300    NOT USED by this system. Do not reintroduce them.

   DERIVED TOKENS (color-mix of canon tokens — still no new hue, still no hex)
   --ed-ground     Sand 200 @26% on white   #FCF8EE  warm page ground
   --ed-band       Sand 200 @45% on white   #FBF3E1  section + sponsored band
   --ed-paper      white                             card + panel surface
   --ed-hairline   Pacific 900 @32% on white #B0BFD1 1.87:1 — the card edge
   --ed-rule-color Pacific 900 @50% on white #839BB7 2.86:1 — section rules
   Each has a plain-token fallback, switched by @supports — see the note on
   the token block for why a second declaration does not work for variables.

   INTENDED USAGE RATIO (share of painted page area, the thing to hold to)
       warm ground + white card surface .......... 78%
       navy ink (Pacific 900 / 700) .............. 15%   all text + strong rules
       sand band + sand blank edges ...............  5%
       ocean teal Aqua 400 .......................  ~2%   rules and marks only
       coral 400 ................................. <0.5%  correction bar only
   Reads as 80% clean marketplace / 15% coastal warmth / 5% accent-and-mark.
   If teal is covering more area than the text does, the page is wrong.

   CARDS ARE WHITE WITH A 1px HAIRLINE AND NO SHADOW AT REST. There is one
   soft shadow token (--ed-lift) and it is used only on the sponsored panel
   to push it out of the editorial plane. Do not add shadows to .bc.

   ---------------------------------------------------------------------------
   3. LAYOUT + SECTION FURNITURE
   ---------------------------------------------------------------------------
   .ed-page            Root scope. Put it on <body>. Sets ground, ink,
                       interface face, and the CORRECTED focus ring (the same
                       Pacific-900-outline + Aqua-400-halo ring as
                       tool-chassis.css §focus, re-scoped so it also covers
                       cards and nav which sit outside .tc-tool. The four
                       declarations are byte-identical to the chassis — if you
                       change one, change both).
   .ed-shell           Centred column. min(100% - gutter, 1120px).
   .ed-shell--narrow   Same, 760px. For prose pages.
   .ed-section         Vertical section rhythm.
   .ed-section--band   Section on the warm band ground, hairlines top+bottom.
   .ed-section--paper  Section on the white paper ground, hairlines top+bottom.
                       Lifts a filter bar or panel off the warm page ground.
   .ed-section__head   Head row: eyebrow + h2 + deck on the left, meta right.
   .ed-section__headings  Left cell of that row — wraps the eyebrow, head and
                       deck so .ed-section__meta can sit opposite them.
   .ed-section__meta   Right-hand slot: counts and captured date. Tabular.
   .ed-rule            1px hairline divider.
   .ed-rule--accent    3px Aqua 400 short rule. The accent mark. Decorative.
   .ed-wave            Pure-CSS coastal scallop divider, Aqua 400, ~20px tall.
                       Decoration only, aria-hidden. No image file, no CDN.

   ---------------------------------------------------------------------------
   4. THE BUSINESS CARD  (`.bc`) — the most repeated component on the site
   ---------------------------------------------------------------------------
   Markup lives in _partials/business-card.html. That partial keeps the SAME
   csdp:block names and the SAME {{SLOT}} tokens as the old guide-card.html —
   this is a visual replacement, not a data-contract change. New optional
   slots are additive: {{PHOTO_SLOT}}, {{BADGES_SLOT}}, {{WHY_SLOT}}.

   .bc                 The card. <li> or <article>. White, 1px hairline,
                       14px radius, no shadow. Card text measure = 44ch.
   .bc--sponsored      Sponsored variant. Only ever inside .ed-sponsored.
   .bc--photo          Explicit "this card has a photo" modifier. Optional —
                       .bc:has(.bc__photo img) does the same automatically.
   .bc__photo          PHOTO SLOT. display:none by default. Contributes ZERO
                       height, ZERO gap and ZERO grid track when empty. The
                       card is designed to look finished without it; a photo
                       is an upgrade a claimed profile earns, never a hole.
   .bc__body           Everything that is not the action strip or the foot.
   .bc__head           Name + locality on the left, reputation on the right.
   .bc__name           Business name. EDITORIAL FACE, 700. Wraps anywhere.
   .bc__locality       Locality line under the name. Interface face.
   .bc__place          "Based in Carlsbad" — the address city.
   .bc__scope          Small outline pill: "North County" / "San Diego County".
                       A locality LABEL, not a badge, not a rank, not a prize.

   .bc__reputation     THE INDIVISIBLE UNIT. Rating, review count and captured
                       date live in this ONE box and may never be separated,
                       reordered into different regions, or rendered without
                       each other. Aqua 400 left rule. FIXED width (13.5rem),
                       not min-width — that is what makes the numerals a true
                       column. Measured: all 25 rating values, review counts
                       and captured dates share one left edge, at 1280px and
                       at 390px.
   .bc__rating         Line 1 wrapper.
   .bc__rating-value   "4.9". Interface face, tabular lining, 27.6px.
   .bc__rating-max     "out of 5". Never a row of stars — a star row is a
                       verdict cue and this site does not judge businesses.
   .bc__reviews        "4,300 public Google reviews". Tabular.
   .bc__captured       "captured on 25 July 2026". Tabular. Required. The word
                       is "captured", never "verified", never "updated".
   .bc__reputation--blank  No public rating on the record. Same box, same size,
                       same weight — see the honest-blank rule below.

   .bc__badges/.bc__badge   Factual bands only ("20+ years in business",
                       "Open 24 hours"). No score, no seal, no winner cue.
   .bc__facts          <dl> of Services / Serves. 2 cols wide, 1 col narrow.
   .bc__fact           One row.
   .bc__term           <dt>. Micro uppercase label.
   .bc__value          <dd>. The value.
   .bc__blank          <dd> for an absent value ("Ask the business").
                       .bc__value and .bc__blank SHARE ONE DECLARATION —
                       identical size, weight and colour. This is the chassis
                       honest-blank rule at card density. Never dim it, never
                       italicise it, never shrink it. Verified in-browser:
                       size, weight, colour, opacity and font-style all match
                       .bc__value exactly.
   .bc__fact--blank    The row wrapper for a blank: white ground instead of the
                       warm one, plus a 4px Sand 200 left bar. Sand measures
                       1.19:1 against the fact ground — that bar is a HUE cue,
                       not a luminance cue, and it is deliberately not
                       load-bearing. The words carry the meaning.

   .bc__why            "Why this appears" — the ordering disclosure. One
                       sentence, factual, no ranking number.
   .bc__why-term       The inline label inside it.

   .bc__actions        Action strip. Warm ground, hairline top.
   .bc__action         One action. 44px min target, Ocean 600 edge.
   .bc__action--call   Primary. Pacific 900 ground, white text (11.89:1).
   .bc__action--absent Action with nothing behind it ("Website not listed").
                       Same box, same type size, dashed edge. Not dimmed.
   .bc__action-label   The verb ("Call").
   .bc__action-detail  The value under it (number, host). Truncates, never
                       widens the card.

   .bc__foot           Advisory + management links.
   .bc__advisory       "Good to know" line from the record.
   .bc__manage         Claim listing / Report update links.

   ---------------------------------------------------------------------------
   5. SEARCH + FILTER CONTROLS
   ---------------------------------------------------------------------------
   .ed-filters         <form>. Layout only — the CONTROLS are chassis classes.
                       Build every field as .tc-control / .tc-label /
                       .tc-hint / .tc-select / .tc-text / .tc-error and every
                       button as .tc-btn. Must submit and work with JS off.
   .ed-filters__row    Auto-fit grid of controls, 220px min track.
   .ed-filters__foot   Actions row + result count + status line.
   .ed-filters__count  "25 of 303 businesses". Tabular. Not a live region —
                       announce through .tc-live.
   .ed-appliedset      <ul> of currently applied filters.
   .ed-applied         One applied filter. Its remove control is a real link
                       or button, 44px, so it works with JS off.

   ---------------------------------------------------------------------------
   6. TRUST STRIP
   ---------------------------------------------------------------------------
   .ed-trust           The band that states what this site is and is not.
   .ed-trust__list     Grid of items.
   .ed-trust__item     One item.
   .ed-trust__label    Micro uppercase term.
   .ed-trust__body     The sentence.
   .ed-trust__note     REQUIRED, verbatim, on every page that lists a
                       business: "Coastal SD Pros does not independently
                       verify licensing, insurance, pricing, availability or
                       workmanship. Confirm all credentials directly before
                       hiring." Coral left bar. The bar is decoration; the
                       words carry it.

   ---------------------------------------------------------------------------
   7. LISTS, PAGINATION, SPONSORED, EMPTY
   ---------------------------------------------------------------------------
   .ed-list            The card list. ONE COLUMN by default — that is what
                       makes ratings and review counts read as a column.
   .ed-list--two       Opt-in two columns at >=1040px. Numerals still align
                       within each column.
   .ed-pager           Pagination / load-more region.
   .ed-pager__status   "Showing 1-25 of 303". Tabular. Always rendered.
   .ed-pager__links    Numbered page links. Mark the current one with
                       aria-current="page" — the style keys off that
                       attribute, not off a class, so state cannot drift.
   .ed-pager__more     Load-more button wrapper. Carry [data-tc-js-only] and
                       always ship the numbered links as the no-JS path.

   .ed-sponsored       Sponsored placement panel. Sits OUTSIDE .ed-list, in
                       its own region, on the band ground with a stronger
                       rule and the one lift shadow in the system. It must
                       never be adjacent-styled to look like an organic card.
   .ed-sponsored__head   Row holding the label and any placement meta.
   .ed-sponsored__label  "Advertising". Uppercase, boxed, first thing in the
                       panel, and it is a real text node — not a ::before —
                       so it survives with CSS off.
   .ed-sponsored__note   "Paid placement. Payment does not affect the order
                       of the listings on this page." Required.

   .ed-empty           Empty or thin result state. Full-weight type, editorial
                       head, a real next step. Never an apology, never a
                       shrug, never a dead end.
   .ed-empty--thin     Same box, for "we hold few records here" rather than
                       none.
   .ed-empty__mark     The coastal scallop mark. Pure CSS. A future restrained
                       mascot SVG can be dropped in as a child and the CSS
                       mark switches off automatically.
   .ed-empty__title / .ed-empty__body / .ed-empty__actions

   ---------------------------------------------------------------------------
   8. RULES THIS FILE ENCODES — do not undo them downstream
   ---------------------------------------------------------------------------
   - No colour literal below the token block. All colour is a canon token or
     a color-mix of canon tokens.
   - No .tc-* rule anywhere in this file.
   - No score, verdict, seal, star row, medal, rank number or winner cue has
     a class here. That is deliberate. Do not add one.
   - Every interactive target is >=44px in both axes.
   - Focus ring is Pacific 900 3px outline, 2px offset, 8px Aqua 400 halo.
   - Photographs: a photo slot exists and is empty. No image may make a place
     claim it cannot support. Where there is no verifiable local photograph,
     the design uses type, ground and rule — the absence must read as
     restraint, and it does, because the card was composed without it.
   - prefers-reduced-motion removes every transition; nothing is carried by
     motion in the first place.

   ---------------------------------------------------------------------------
   9. PROBLEMS — stated plainly, per the build brief
   ---------------------------------------------------------------------------
   THE EDITORIAL FACE IS REAL AND SELF-HOSTED — but this file does not own
   the font files. assets/fonts/newsreader-{normal,italic}.woff2 appeared on
   disk mid-build (they were not there when this file was started; the first
   draft shipped a system serif stack and said so). They are verified genuine
   variable woff2, so the stack now leads with Newsreader. If another agent
   moves or renames those two files, the @font-face src 404s silently and
   every head falls back to Georgia — visually a downgrade, functionally
   fine, and the numerals are unaffected because they never used this face.
   Whoever owns assets/fonts/ should know this file points at it.

   SECOND: Inter is a phantom. The interface stack inherits `Inter` from
   v4.css, but Inter is not installed on the build machine and no Inter file
   exists in this repo. It resolves to Segoe UI / system-ui in practice.
   Nothing here depends on Inter; flagged so nobody "fixes" a bug that is
   actually just the system face doing its job.
   =========================================================================== */

/* --------------------------------------------------------------------------
   THE EDITORIAL FACE — self-hosted, no CDN, no remote request.

   Newsreader, the variable woff2 pair already sitting in assets/fonts/.
   Verified by decoding the WOFF2 table directory: both files carry fvar,
   gvar, avar, HVAR and STAT, so they are genuine variable fonts, not static
   instances. Newsreader's axes are wght 200-800 and opsz 6-72; the weight
   range below is declared to match, and optical sizing is left on its
   default (auto) so display sizes get the display cut for free.

   This file only READS those two files. It does not own them. If they move,
   the stack in --ed-font-editorial falls back to Iowan Old Style / Georgia
   and the page still reads correctly — it just loses the branded face.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: Newsreader;
  src: url("/assets/fonts/newsreader-normal.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: Newsreader;
  src: url("/assets/fonts/newsreader-italic.woff2") format("woff2");
  font-weight: 200 800;
  font-style: italic;
  font-display: swap;
}

/* --------------------------------------------------------------------------
   TOKENS. Every colour below resolves to a canon token declared by
   tool-chassis.css / v4.css, or a color-mix of them. There is no hex here.
   Each color-mix is preceded by a plain-token fallback declaration.
   -------------------------------------------------------------------------- */
:root {
  /* --- faces ------------------------------------------------------------ */
  --ed-font-editorial: Newsreader, "Iowan Old Style", Charter, Georgia, "Noto Serif", "Liberation Serif", "Times New Roman", serif;
  --ed-font-interface: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --ed-nums: tabular-nums lining-nums;

  /* --- modular scale, ratio 1.200, base 16px ---------------------------- */
  --ed-t--2: 0.75rem;
  --ed-t--1: 0.875rem;
  --ed-t-0: 1rem;
  --ed-t-1: 1.25rem;
  --ed-t-2: 1.5rem;
  --ed-t-3: 1.75rem;
  --ed-t-4: 2rem;
  --ed-t-5: 2.5rem;
  --ed-t-6: 3rem;
  --ed-t-7: 3.5rem;

  /* --- leading ---------------------------------------------------------- */
  --ed-lh-flat: 1;
  --ed-lh-tight: 1.08;
  --ed-lh-head: 1.18;
  --ed-lh-snug: 1.35;
  --ed-lh-body: 1.6;

  /* --- measure ---------------------------------------------------------- */
  --ed-measure-prose: 66ch;
  --ed-measure-deck: 52ch;
  --ed-measure-card: 44ch;
  --ed-measure-micro: 38ch;

  /* --- ink -------------------------------------------------------------- */
  --ed-ink: var(--pacific-900);
  --ed-ink-soft: var(--pacific-700);
  /* `white` is the CSS keyword, not a palette hue — same position v4.css and
     tool-chassis.css already take. It is a neutral surface, never a colour. */
  --ed-ink-invert: white;

  /* --- grounds ---------------------------------------------------------- */
  /* These four are the plain-token FALLBACKS. The color-mix values live in
     the @supports block below, NOT in a second declaration here. A custom
     property accepts any token stream at parse time, so the usual
     "declare twice, let the invalid one lose" trick silently does not work
     for variables — the color-mix would always win and simply fail to
     compute on an engine that lacks it, dropping the ground to transparent.
     @supports is the only correct guard. */
  --ed-paper: white;
  --ed-ground: var(--foam-50);
  --ed-band: var(--sand-200);

  /* --- edges ------------------------------------------------------------ */
  --ed-hairline: var(--sky-400);
  --ed-rule-color: var(--sky-400);
  --ed-edge: var(--ocean-600);
  --ed-accent: var(--aqua-400);
  --ed-warm: var(--sand-200);
  --ed-alert: var(--coral-400);

  /* --- geometry --------------------------------------------------------- */
  --ed-radius-sm: 8px;
  --ed-radius-md: 8px;
  --ed-radius-lg: 8px;
  --ed-tap: 44px;
  --ed-gutter: 20px;
  --ed-shell: 1120px;
  --ed-shell-narrow: 760px;

  /* the ONE shadow in the system; sponsored panel only */
  --ed-lift: 0 10px 30px rgba(7, 54, 111, .10);

  /* --- motion ----------------------------------------------------------- */
  --ed-t-control: 160ms;
  --ed-ease: cubic-bezier(.2, .7, .3, 1);
}

/* The warm editorial grounds. Derived from canon tokens only — no new hue and
   no hex. Guarded so an engine without color-mix keeps the plain-token
   fallbacks above and still renders a coherent, readable page.
   Resolved values, measured in Chrome:
     --ed-ground     #FCF8EE  Pacific 900 on it = 11.21:1
     --ed-band       #FBF3E1  Pacific 900 on it = 10.76:1
     --ed-hairline   #B0BFD1  1.87:1 on white, 1.76:1 on ground — card edge
     --ed-rule-color #839BB7  2.86:1 on white, 2.70:1 on ground — section rule
   A white card on the warm ground is only 1.06:1, so the hairline is what
   actually draws the card. It was 22% and measured 1.43:1 against the
   ground, which was too faint to hold an object edge; 32% keeps it a
   refined 1px line and still reads as a boundary. Anything that is an
   interactive edge uses --ed-edge (Ocean 600, 4.17:1) instead — measured
   above 3:1 for every control on the page. */
@supports (background: color-mix(in srgb, currentColor 50%, white)) {
  :root {
    --ed-ground: color-mix(in srgb, var(--sand-200) 26%, white);
    --ed-band: color-mix(in srgb, var(--sand-200) 45%, white);
    --ed-hairline: color-mix(in srgb, var(--pacific-900) 32%, white);
    --ed-rule-color: color-mix(in srgb, var(--pacific-900) 50%, white);
  }
}

/* ==========================================================================
   ROOT SCOPE
   ========================================================================== */

.ed-page {
  margin: 0;
  /* This is a light-only editorial system. Without this, a reader whose OS
     prefers dark gets dark-themed native selects, scrollbars and autofill on
     a warm paper page. Measured: prefers-color-scheme:dark rendered the
     canvas near-black behind these grounds until this was set. */
  color-scheme: light;
  color: var(--ed-ink);
  background: var(--ed-ground);
  font-family: var(--ed-font-interface);
  font-size: var(--ed-t-0);
  line-height: var(--ed-lh-body);
  -webkit-text-size-adjust: 100%;
  overflow-x: clip;
}

/* CHASSIS TOKEN BRIDGE — required, and easy to delete by accident.
   tool-chassis.css declares its derived tokens (--tc-ink, --tc-edge, --tc-tap,
   --tc-radius-*, …) on `.tc-tool`, not on :root. Editorial pages use the
   chassis form primitives OUTSIDE any .tc-tool — in the filter bar, the pager
   and the empty state. Without this block --tc-ink resolves to nothing and
   `.tc-btn--primary` paints a white label on a transparent ground: an
   invisible submit button. Measured in the browser, not guessed.

   This declares VARIABLES ONLY. It does not add or override one .tc-* rule.
   Values are copied verbatim from tool-chassis.css "Derived tokens"; a nested
   .tc-tool redeclares them identically, so nothing conflicts either way. */
.ed-page {
  --tc-ink: var(--pacific-900);
  --tc-ink-soft: var(--pacific-700);
  --tc-surface: white;
  --tc-ground: var(--foam-50);
  --tc-quiet: var(--foam-100);
  --tc-warm: var(--sand-200);
  --tc-cue: var(--sun-300);
  --tc-live: var(--aqua-400);
  --tc-alert: var(--coral-400);
  --tc-edge: var(--ocean-600);
  --tc-divider: var(--sky-400);
  --tc-focus-ring: var(--pacific-900);
  --tc-focus-halo: var(--aqua-400);
  --tc-radius-sm: 8px;
  --tc-radius-md: 8px;
  --tc-radius-lg: 8px;
  --tc-tap: 44px;
  --tc-t-control: 180ms;
  --tc-t-panel: 320ms;
  --tc-t-enter: 480ms;
  --tc-ease: cubic-bezier(.2, .7, .3, 1);
}

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

.ed-page [hidden] {
  display: none !important;
}

/* The corrected focus ring, re-scoped. Byte-identical to tool-chassis.css §
   THE CORRECTED FOCUS RING. Specificity (0,2,0) matches the chassis, so load
   order is irrelevant — the two rules resolve to the same paint. Change one,
   change both. Pacific 900 carries the 11:1; the aqua halo is the coastal
   signature and is decorative. */
.ed-page :focus-visible,
.ed-page:focus-visible {
  outline: 3px solid var(--pacific-900);
  outline-offset: 2px;
  box-shadow: 0 0 0 8px var(--aqua-400);
  border-radius: var(--ed-radius-sm);
}

.ed-page :focus:not(:focus-visible) {
  outline: none;
}

/* ==========================================================================
   1. TYPE
   ========================================================================== */

.ed-display,
.ed-h1,
.ed-h2,
.ed-h3,
.ed-h4 {
  margin: 0;
  color: var(--ed-ink);
  font-family: var(--ed-font-editorial);
  font-weight: 700;
  letter-spacing: -.012em;
  text-wrap: balance;
}

.ed-display {
  font-size: clamp(var(--ed-t-5), 5.4vw, var(--ed-t-7));
  line-height: var(--ed-lh-tight);
}

.ed-h1 {
  font-size: clamp(var(--ed-t-4), 4.6vw, var(--ed-t-6));
  line-height: var(--ed-lh-tight);
}

.ed-h2 {
  font-size: clamp(var(--ed-t-3), 3.4vw, var(--ed-t-4));
  line-height: var(--ed-lh-head);
}

.ed-h3 {
  font-size: var(--ed-t-2);
  line-height: var(--ed-lh-head);
}

.ed-h4 {
  font-size: var(--ed-t-1);
  line-height: var(--ed-lh-snug);
}

/* The only uppercase in the system. Micro labels, never body copy. */
.ed-eyebrow {
  margin: 0 0 10px;
  color: var(--ed-ink-soft);
  font-family: var(--ed-font-interface);
  font-size: var(--ed-t--2);
  font-weight: 700;
  letter-spacing: .1em;
  line-height: var(--ed-lh-snug);
  text-transform: uppercase;
}

.ed-deck {
  max-width: var(--ed-measure-deck);
  margin: 12px 0 0;
  color: var(--ed-ink-soft);
  font-size: var(--ed-t-1);
  line-height: var(--ed-lh-snug);
  text-wrap: pretty;
}

.ed-prose {
  max-width: var(--ed-measure-prose);
  color: var(--ed-ink);
  font-size: var(--ed-t-0);
  line-height: var(--ed-lh-body);
}

.ed-prose > * + * {
  margin-top: 1em;
}

.ed-prose p,
.ed-prose li {
  text-wrap: pretty;
}

.ed-prose a {
  color: var(--ed-ink-soft);
  text-decoration: underline;
  text-decoration-color: var(--ed-accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

.ed-prose a:hover {
  color: var(--ed-ink);
  text-decoration-color: var(--ed-ink);
}

.ed-lead {
  max-width: var(--ed-measure-deck);
  font-size: var(--ed-t-1);
  line-height: var(--ed-lh-snug);
}

.ed-micro {
  margin: 0;
  max-width: var(--ed-measure-micro);
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--2);
  font-variant-numeric: var(--ed-nums);
  letter-spacing: .01em;
  line-height: var(--ed-lh-snug);
}

/* Any number that sits inside editorial text. Pulls it back to the interface
   face so it keeps lining, tabular figures. */
.ed-num {
  font-family: var(--ed-font-interface);
  font-variant-numeric: var(--ed-nums);
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* Headline escape hatch: lining figures without leaving the editorial face. */
.ed-lining {
  font-variant-numeric: lining-nums;
  font-feature-settings: "lnum" 1;
}

/* ==========================================================================
   2. LAYOUT + SECTION FURNITURE
   ========================================================================== */

.ed-shell {
  width: min(100% - (var(--ed-gutter) * 2), var(--ed-shell));
  margin-inline: auto;
}

.ed-shell--narrow {
  --ed-shell: var(--ed-shell-narrow);
}

.ed-section {
  padding-block: clamp(40px, 6vw, 72px);
}

.ed-section--band {
  background: var(--ed-band);
  border-block: 1px solid var(--ed-hairline);
}

.ed-section--paper {
  background: var(--ed-paper);
  border-block: 1px solid var(--ed-hairline);
}

.ed-section__head {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 32px;
  align-items: end;
  justify-content: space-between;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--ed-rule-color);
}

.ed-section__headings {
  min-width: 0;
  flex: 1 1 min(100%, 30ch);
}

.ed-section__meta {
  flex: 0 0 auto;
  margin: 0;
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--1);
  font-variant-numeric: var(--ed-nums);
  line-height: var(--ed-lh-snug);
}

.ed-rule {
  height: 1px;
  margin: 0;
  border: 0;
  background: var(--ed-hairline);
}

.ed-rule--accent {
  width: 56px;
  height: 3px;
  border-radius: 2px;
  background: var(--ed-accent);
}

/* Coastal scallop divider. Two offset radial gradients make an alternating
   wave line. No image file, no CDN, colour from a token. Decoration only. */
.ed-wave {
  height: 20px;
  border: 0;
  margin: 0;
  background:
    radial-gradient(circle at 10px -4px, transparent 11px, var(--ed-accent) 11px 13px, transparent 13px) 0 0 / 20px 20px repeat-x,
    radial-gradient(circle at 10px 24px, transparent 11px, var(--ed-accent) 11px 13px, transparent 13px) 10px 0 / 20px 20px repeat-x;
}

/* ==========================================================================
   3. THE BUSINESS CARD
   ========================================================================== */

.bc {
  --bc-pad: clamp(16px, 2.4vw, 22px);
  position: relative;
  display: grid;
  gap: 0;
  color: var(--ed-ink);
  background: var(--ed-paper);
  border: 1px solid var(--ed-hairline);
  border-radius: var(--ed-radius-md);
  font-size: var(--ed-t-0);
  line-height: var(--ed-lh-snug);
  overflow: hidden;
  transition:
    border-color var(--ed-t-control) var(--ed-ease),
    box-shadow var(--ed-t-control) var(--ed-ease),
    transform var(--ed-t-control) var(--ed-ease);
}

/* The one elevation layer, on the one state that earns it. The card rests flat
   — this is a border-led list and 25 resting shadows would be wallpaper — and
   picks up --ed-lift only while it is the card being acted on. :focus-within
   gives the keyboard the same signal the mouse gets, since every card holds a
   name link and two actions. */
.bc:hover,
.bc:focus-within {
  border-color: var(--ed-rule-color);
  box-shadow: var(--ed-lift);
  transform: translateY(-2px);
}

/* Card text never runs longer than the card measure. */
.bc p,
.bc dd,
.bc li {
  max-width: var(--ed-measure-card);
}

/* --- photo slot ----------------------------------------------------------
   Invisible when empty. Contributes no height, no gap, no grid track. The
   card was composed to be finished without it. */
.bc__photo {
  display: none;
}

/* max-height is not optional. On a one-column list a 16/9 band on a 1118px
   card measured 629px tall — one photo taller than three whole cards, which
   destroys the scan rhythm the list exists for. Capped, with object-fit
   cropping rather than letterboxing. */
.bc--photo .bc__photo,
.bc:has(.bc__photo img) .bc__photo,
.bc:has(.bc__photo picture) .bc__photo {
  display: block;
  aspect-ratio: 16 / 9;
  max-height: 220px;
  overflow: hidden;
  background: var(--ed-band);
  border-bottom: 1px solid var(--ed-hairline);
}

.bc__photo img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

.bc__body {
  display: grid;
  gap: 16px;
  padding: var(--bc-pad);
}

/* --- head ---------------------------------------------------------------- */

.bc__head {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 20px;
  align-items: flex-start;
  justify-content: space-between;
}

.bc__identity {
  min-width: 0;
  flex: 1 1 16ch;
}

.bc__name {
  margin: 0;
  max-width: var(--ed-measure-card);
  color: var(--ed-ink);
  font-family: var(--ed-font-editorial);
  font-size: clamp(var(--ed-t-1), 2.4vw, var(--ed-t-2));
  font-weight: 700;
  letter-spacing: -.01em;
  line-height: var(--ed-lh-head);
  overflow-wrap: anywhere;
  text-wrap: balance;
}

.bc__name a {
  color: inherit;
  text-decoration: none;
}

.bc__name a:hover {
  text-decoration: underline;
  text-decoration-color: var(--ed-accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

.bc__locality {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 10px;
  align-items: center;
  margin: 8px 0 0;
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--1);
  line-height: var(--ed-lh-snug);
}

.bc__place {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* A locality LABEL. Not a badge, not a rank, not a prize. */
.bc__scope {
  display: inline-flex;
  align-items: center;
  padding: 2px 9px;
  color: var(--ed-ink);
  background: var(--ed-paper);
  border: 1px solid var(--ed-edge);
  border-radius: 999px;
  font-size: var(--ed-t--2);
  font-weight: 600;
  letter-spacing: .04em;
  line-height: 1.5;
  white-space: nowrap;
}

/* --- THE INDIVISIBLE REPUTATION UNIT ------------------------------------- */

/* FIXED width, not min-width. This is what makes the numerals a real column.
   With min-width the block sizes to its content, so a card reading "4,300
   public Google reviews" pushed its left edge ~17px further left than one
   reading "77 …" — measured 4 different left edges across 25 cards. A fixed
   basis gives all 25 the same left edge, and tabular figures then line the
   digits up inside it. 13.5rem = 216px, which clears the widest real string
   in the dataset ("4,300 public Google reviews", 169.7px) inside 32px of
   padding and border. Do not change this to min-width or max-content. */
.bc__reputation {
  flex: 0 0 13.5rem;
  display: grid;
  gap: 2px;
  padding: 10px 14px;
  background: var(--ed-paper);
  border: 1px solid var(--ed-hairline);
  border-left: 3px solid var(--ed-accent);
  border-radius: var(--ed-radius-sm);
  font-variant-numeric: var(--ed-nums);
  font-feature-settings: "tnum" 1, "lnum" 1;
}

.bc__rating {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin: 0;
  max-width: none;
}

.bc__rating-value {
  color: var(--ed-ink);
  font-family: var(--ed-font-interface);
  font-size: var(--ed-t-3);
  font-weight: 700;
  font-variant-numeric: var(--ed-nums);
  letter-spacing: -.02em;
  line-height: var(--ed-lh-flat);
}

.bc__rating-max {
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--2);
  font-weight: 600;
  letter-spacing: .02em;
  white-space: nowrap;
}

.bc__reviews {
  margin: 0;
  max-width: none;
  color: var(--ed-ink);
  font-size: var(--ed-t--1);
  font-weight: 600;
  font-variant-numeric: var(--ed-nums);
  line-height: var(--ed-lh-snug);
}

.bc__captured {
  margin: 0;
  max-width: none;
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--2);
  font-variant-numeric: var(--ed-nums);
  line-height: var(--ed-lh-snug);
}

/* No public rating on the record. Same box, same weight — a result, not an
   apology. Sand edge instead of the aqua accent. */
.bc__reputation--blank {
  border-left-color: var(--ed-warm);
  border-left-width: 3px;
}

.bc__reputation--blank .bc__rating-value {
  font-size: var(--ed-t-1);
  letter-spacing: 0;
}

/* --- badges (factual bands only) ----------------------------------------- */

.bc__badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.bc__badge {
  max-width: none;
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  color: var(--ed-ink);
  background: var(--ed-band);
  border: 1px solid var(--ed-hairline);
  border-radius: 999px;
  font-size: var(--ed-t--2);
  font-weight: 600;
  font-variant-numeric: var(--ed-nums);
  line-height: 1.6;
}

/* --- facts --------------------------------------------------------------- */

.bc__facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: 10px;
  margin: 0;
}

.bc__fact {
  min-width: 0;
  padding: 10px 12px;
  background: var(--ed-ground);
  border: 1px solid var(--ed-hairline);
  border-radius: var(--ed-radius-sm);
}

/* The honest blank: identical box, identical type. The differences are a sand
   left edge and a white ground instead of the warm one — white is not
   "lesser" than warm, it is just other, which is the whole point.
   Measured honestly: Sand 200 against the fact ground is 1.19:1 and against
   white 1.26:1. That bar is a HUE cue, not a luminance cue, and it is
   deliberately not load-bearing — the words ("Ask the business") carry the
   meaning, exactly as the chassis honest-blank requires. Do not "fix" the
   bar by dimming, italicising or shrinking the value next to it. */
.bc__fact--blank {
  background: var(--ed-paper);
  border-left: 4px solid var(--ed-warm);
}

.bc__term {
  margin: 0 0 3px;
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--2);
  font-weight: 700;
  letter-spacing: .09em;
  line-height: var(--ed-lh-snug);
  text-transform: uppercase;
}

/* .bc__value and .bc__blank share ONE declaration. Splitting them is how a
   blank quietly becomes a greyed-out apology. Do not split them. */
.bc__value,
.bc__blank {
  margin: 0;
  max-width: none;
  color: var(--ed-ink);
  font-size: var(--ed-t--1);
  font-weight: 500;
  font-variant-numeric: var(--ed-nums);
  line-height: var(--ed-lh-snug);
  overflow-wrap: anywhere;
}

/* --- why it appears ------------------------------------------------------ */

.bc__why {
  margin: 0;
  max-width: var(--ed-measure-card);
  padding-left: 12px;
  border-left: 2px solid var(--ed-hairline);
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--2);
  line-height: var(--ed-lh-snug);
  text-wrap: pretty;
}

.bc__why-term {
  color: var(--ed-ink);
  font-weight: 700;
}

/* --- actions ------------------------------------------------------------- */

.bc__actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
  gap: 8px;
  padding: 12px var(--bc-pad);
  background: var(--ed-ground);
  border-top: 1px solid var(--ed-hairline);
}

.bc__action {
  min-width: 0;
  min-height: var(--ed-tap);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  padding: 6px 12px;
  color: var(--ed-ink);
  background: var(--ed-paper);
  border: 1px solid var(--ed-edge);
  border-radius: var(--ed-radius-sm);
  font-size: var(--ed-t--1);
  font-weight: 600;
  text-align: center;
  text-decoration: none;
  transition: background-color var(--ed-t-control) var(--ed-ease);
}

a.bc__action:hover {
  background: var(--ed-band);
}

.bc__action--call {
  color: var(--ed-ink-invert);
  background: var(--ed-ink);
  border-color: var(--ed-ink);
}

a.bc__action--call:hover {
  background: var(--pacific-700);
  border-color: var(--pacific-700);
}

/* Nothing behind this action. Same box, same type size, same weight. */
.bc__action--absent {
  background: var(--ed-ground);
  border-style: dashed;
  cursor: default;
}

.bc__action-label {
  display: block;
  line-height: var(--ed-lh-snug);
}

.bc__action-detail {
  display: block;
  max-width: 100%;
  color: inherit;
  font-size: var(--ed-t--2);
  font-weight: 500;
  font-variant-numeric: var(--ed-nums);
  line-height: var(--ed-lh-snug);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- foot ---------------------------------------------------------------- */

.bc__foot {
  display: grid;
  gap: 10px;
  padding: 12px var(--bc-pad) 14px;
  border-top: 1px solid var(--ed-hairline);
}

.bc__advisory {
  margin: 0;
  color: var(--ed-ink);
  font-size: var(--ed-t--1);
  line-height: var(--ed-lh-snug);
  text-wrap: pretty;
}

.bc__advisory b {
  font-weight: 700;
}

.bc__manage {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 18px;
  margin: 0;
  max-width: none;
}

.bc__manage a {
  min-height: var(--ed-tap);
  display: inline-flex;
  align-items: center;
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--2);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--ed-accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

.bc__manage a:hover {
  color: var(--ed-ink);
  text-decoration-color: var(--ed-ink);
}

/* ==========================================================================
   4. LISTS
   ========================================================================== */

.ed-list {
  display: grid;
  gap: 16px;
  margin: 24px 0 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 1040px) {
  .ed-list--two {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
  }
}

/* ==========================================================================
   5. SEARCH + FILTER CONTROLS
   Layout only. Every control is a tool-chassis primitive.
   ========================================================================== */

.ed-filters {
  display: grid;
  gap: 16px;
  padding: clamp(16px, 2.4vw, 22px);
  background: var(--ed-paper);
  border: 1px solid var(--ed-hairline);
  border-radius: var(--ed-radius-md);
}

.ed-filters__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: 14px;
  align-items: start;
}

.ed-filters__foot {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 20px;
  align-items: center;
  justify-content: space-between;
  padding-top: 14px;
  border-top: 1px solid var(--ed-hairline);
}

.ed-filters__count {
  margin: 0;
  color: var(--ed-ink);
  font-size: var(--ed-t--1);
  font-weight: 600;
  font-variant-numeric: var(--ed-nums);
}

.ed-appliedset {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ed-applied {
  display: inline-flex;
  align-items: center;
}

.ed-applied a,
.ed-applied button {
  min-height: var(--ed-tap);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  color: var(--ed-ink);
  background: var(--ed-band);
  border: 1px solid var(--ed-edge);
  border-radius: 999px;
  font: inherit;
  font-size: var(--ed-t--1);
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
}

.ed-applied a:hover,
.ed-applied button:hover {
  background: var(--ed-warm);
}

/* ==========================================================================
   6. TRUST STRIP
   ========================================================================== */

.ed-trust {
  display: grid;
  gap: 18px;
}

.ed-trust__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: 18px 28px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ed-trust__item {
  min-width: 0;
  padding-top: 12px;
  border-top: 2px solid var(--ed-accent);
}

.ed-trust__label {
  margin: 0 0 4px;
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--2);
  font-weight: 700;
  letter-spacing: .09em;
  line-height: var(--ed-lh-snug);
  text-transform: uppercase;
}

.ed-trust__body {
  margin: 0;
  max-width: var(--ed-measure-micro);
  color: var(--ed-ink);
  font-size: var(--ed-t--1);
  line-height: var(--ed-lh-snug);
  text-wrap: pretty;
}

/* The required non-verification sentence. Coral is the marker bar only —
   coral as text on any light ground here is 2.67:1 and fails. */
.ed-trust__note {
  position: relative;
  margin: 0;
  max-width: var(--ed-measure-prose);
  padding: 12px 14px 12px 18px;
  color: var(--ed-ink);
  background: var(--ed-paper);
  border: 1px solid var(--ed-hairline);
  border-radius: var(--ed-radius-sm);
  font-size: var(--ed-t--1);
  line-height: var(--ed-lh-snug);
  text-wrap: pretty;
  overflow: hidden;
}

.ed-trust__note::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: 5px;
  background: var(--ed-alert);
}

/* ==========================================================================
   7. PAGINATION
   ========================================================================== */

.ed-pager {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 24px;
  align-items: center;
  justify-content: space-between;
  margin-top: 28px;
  padding-top: 18px;
  border-top: 1px solid var(--ed-rule-color);
}

.ed-pager__status {
  margin: 0;
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--1);
  font-variant-numeric: var(--ed-nums);
}

.ed-pager__links {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ed-pager__links a,
.ed-pager__links span {
  min-width: var(--ed-tap);
  min-height: var(--ed-tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px 12px;
  color: var(--ed-ink);
  background: var(--ed-paper);
  border: 1px solid var(--ed-edge);
  border-radius: var(--ed-radius-sm);
  font-size: var(--ed-t--1);
  font-weight: 600;
  font-variant-numeric: var(--ed-nums);
  text-decoration: none;
}

.ed-pager__links a:hover {
  background: var(--ed-band);
}

/* State keys off the attribute, not a class, so it cannot drift. */
.ed-pager__links [aria-current="page"] {
  color: var(--ed-ink-invert);
  background: var(--ed-ink);
  border-color: var(--ed-ink);
}

.ed-pager__more {
  display: flex;
  gap: 10px;
  align-items: center;
}

/* ==========================================================================
   8. SPONSORED PLACEMENT
   Outside the organic list, on its own ground, labelled advertising.
   ========================================================================== */

.ed-sponsored {
  display: grid;
  gap: 14px;
  margin: 28px 0;
  padding: clamp(16px, 2.4vw, 22px);
  background: var(--ed-band);
  border: 1px solid var(--ed-rule-color);
  border-radius: var(--ed-radius-lg);
  box-shadow: var(--ed-lift);
}

.ed-sponsored__head {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  align-items: baseline;
  justify-content: space-between;
}

/* A real text node, not a ::before — it must survive with CSS off. */
.ed-sponsored__label {
  display: inline-flex;
  align-items: center;
  margin: 0;
  padding: 4px 10px;
  color: var(--ed-ink);
  background: var(--ed-paper);
  border: 1px solid var(--ed-ink);
  border-radius: var(--ed-radius-sm);
  font-size: var(--ed-t--2);
  font-weight: 700;
  letter-spacing: .12em;
  line-height: var(--ed-lh-snug);
  text-transform: uppercase;
}

.ed-sponsored__note {
  margin: 0;
  max-width: var(--ed-measure-prose);
  color: var(--ed-ink);
  font-size: var(--ed-t--1);
  line-height: var(--ed-lh-snug);
  text-wrap: pretty;
}

.ed-sponsored .ed-list {
  margin: 0;
}

/* The sponsored card keeps card geometry but never the organic card's edge —
   a reader must not be able to mistake one for the other. */
.bc--sponsored {
  border-color: var(--ed-rule-color);
  border-style: dashed;
}

.bc--sponsored .bc__actions,
.bc--sponsored .bc__fact {
  background: var(--ed-paper);
}

/* ==========================================================================
   9. EMPTY + THIN STATES
   ========================================================================== */

.ed-empty {
  display: grid;
  gap: 14px;
  justify-items: start;
  padding: clamp(22px, 4vw, 36px);
  background: var(--ed-paper);
  border: 1px solid var(--ed-hairline);
  border-radius: var(--ed-radius-md);
}

.ed-empty--thin {
  background: var(--ed-band);
}

/* Pure-CSS coastal scallop. If a restrained mascot SVG is dropped in as a
   child later, the CSS mark switches itself off. */
.ed-empty__mark {
  width: 120px;
  height: 20px;
  background:
    radial-gradient(circle at 10px -4px, transparent 11px, var(--ed-accent) 11px 13px, transparent 13px) 0 0 / 20px 20px repeat-x,
    radial-gradient(circle at 10px 24px, transparent 11px, var(--ed-accent) 11px 13px, transparent 13px) 10px 0 / 20px 20px repeat-x;
}

.ed-empty__mark:not(:empty) {
  width: auto;
  height: auto;
  background: none;
}

.ed-empty__title {
  margin: 0;
  color: var(--ed-ink);
  font-family: var(--ed-font-editorial);
  font-size: var(--ed-t-2);
  font-weight: 700;
  line-height: var(--ed-lh-head);
}

.ed-empty__body {
  margin: 0;
  max-width: var(--ed-measure-deck);
  color: var(--ed-ink);
  font-size: var(--ed-t-0);
  line-height: var(--ed-lh-body);
  text-wrap: pretty;
}

.ed-empty__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}

/* ==========================================================================
   10. DIRECTORY GUIDE EVIDENCE LAYER
   The guide remains a scan-first marketplace. This adds one concise answer
   panel and the same evidence vocabulary to every business row.
   ========================================================================== */

.dg-answer {
  border-bottom: 1px solid var(--ed-hairline);
  background: var(--ed-paper);
}

.dg-answer__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(20rem, .8fr);
  gap: clamp(20px, 4vw, 48px);
  padding-block: 22px 26px;
}

.dg-answer__primary {
  align-self: start;
}

.dg-answer__primary h2 {
  margin: 4px 0 8px;
  color: var(--ed-ink);
  font-family: var(--ed-font-interface);
  font-size: clamp(var(--ed-t-1), 2.2vw, var(--ed-t-2));
  line-height: var(--ed-lh-head);
  text-wrap: balance;
}

.dg-answer__primary > p:last-child {
  margin: 0;
  max-width: 72ch;
  color: var(--ed-ink);
  font-size: var(--ed-t--1);
  line-height: var(--ed-lh-body);
  text-wrap: pretty;
}

.dg-answer__facts {
  display: grid;
  gap: 10px;
  margin: 0;
}

.dg-answer__facts > div {
  display: grid;
  grid-template-columns: 8.75rem minmax(0, 1fr);
  gap: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--ed-hairline);
}

.dg-answer__facts dt,
.dg-answer__facts dd {
  margin: 0;
}

.dg-answer__facts dt {
  color: var(--ed-ink);
  font-size: var(--ed-t--2);
  font-weight: 700;
}

.dg-answer__facts dd {
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--2);
  line-height: var(--ed-lh-snug);
  text-wrap: pretty;
}

.bc__fact--wide {
  grid-column: 1 / -1;
}

.bc__inclusion,
.bc__evidence,
.bc__unknowns {
  margin: 0;
  max-width: none;
  color: var(--ed-ink-soft);
  font-size: var(--ed-t--2);
  line-height: var(--ed-lh-snug);
  text-wrap: pretty;
}

.bc__inclusion {
  padding: 10px 12px;
  border-left: 3px solid var(--ed-accent);
  background: var(--ed-ground);
}

.bc__evidence {
  padding-top: 10px;
  border-top: 1px solid var(--ed-hairline);
}

.bc__unknowns {
  padding: 9px 10px;
  border: 1px solid var(--ed-hairline);
  background: var(--ed-paper);
}

.bc__inclusion-term,
.bc__evidence-term,
.bc__unknowns-term {
  margin-right: 7px;
  color: var(--ed-ink);
  font-weight: 700;
}

/* ==========================================================================
   11. NARROW VIEWPORTS
   ========================================================================== */

@media (max-width: 640px) {
  :root {
    --ed-gutter: 16px;
  }

  .bc__head {
    flex-direction: column;
    align-items: stretch;
  }

  /* .bc__identity carries `flex: 1 1 16ch` for the row layout. Once the head
     becomes a column, flex-basis and flex-grow act on the HEIGHT, and the
     identity stretched to open a ~70px void between the locality line and the
     reputation block. Measured at 390px. Reset it here. */
  .bc__identity {
    flex: 0 0 auto;
  }

  .bc__reputation {
    flex: 0 0 auto;
    width: 100%;
    justify-items: start;
  }

  .ed-section__head {
    align-items: start;
  }

  .ed-pager {
    flex-direction: column;
    align-items: flex-start;
  }

  .dg-answer__inner {
    grid-template-columns: 1fr;
    gap: 18px;
    padding-block: 18px 20px;
  }

  .dg-answer__facts > div {
    grid-template-columns: 1fr;
    gap: 3px;
  }

  body.dg-guide .bc__facts {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   12. REDUCED MOTION
   Nothing in this system is carried by motion, so removing it costs nothing.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .ed-page *,
  .ed-page *::before,
  .ed-page *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }

  /* Zeroing the duration only makes the card jump instead of glide, so the
     displacement itself is dropped. The border and shadow still change, so the
     hovered card is still identifiable without any movement at all. */
  .bc:hover,
  .bc:focus-within {
    transform: none;
  }
}

/* ==========================================================================
   13. FORCED COLORS
   ========================================================================== */

@media (forced-colors: active) {
  .bc,
  .bc__reputation,
  .bc__fact,
  .bc__action,
  .ed-filters,
  .ed-empty,
  .ed-sponsored,
  .ed-trust__note {
    border: 1px solid CanvasText;
  }

  .ed-page :focus-visible {
    outline: 3px solid Highlight;
    box-shadow: none;
  }

  .ed-trust__note::before,
  .ed-rule--accent {
    background: CanvasText;
    forced-color-adjust: none;
  }
}
