/* ══════════════════════════════════════════════════════
   Frontera Facts — the Apple-way vocabulary
   ══════════════════════════════════════════════════════
   A port of the design reference, docs/design/apple/src/base.css +
   src/desk.css + src/phone.css, with every class prefixed `ffa-` so
   nothing collides with style.css. Those three files are the source of
   truth: every size, colour, spacing and radius below is theirs.
   Renames follow docs/superpowers/specs/2026-09-12-apple-way-redesign-design.md §3.

   Loaded sitewide right after style.css (page/template.header.php).
   Site chrome is style.css's, so the mockup's .page, .nav, .screen,
   .top-space, .tabbar, .tab and .nav-title are deliberately not ported.

   Sections: base · placeholder · layout · type · grounds · components ·
   grids · breakpoints (900px, then 600px with the phone vocabulary).
   ══════════════════════════════════════════════════════ */

/* ── Base ──────────────────────────────────────────────
   src/base.css carries three bare element rules — `body`, `a`, `p`.
   None of them is emitted here, on purpose. This file loads on every
   public page AND on the admin, and slice 1 ships vocabulary only: it
   must change no page body. A bare `a { color: … }` would recolour
   every link on every not-yet-converted page and throughout the admin.
   style.css already owns the rest: body font, background, colour and
   smoothing (css/style.css:35-43), `a { color: inherit }` (:44) and the
   `p` margin via the `*` reset (:33).
   So base.css's link colours are carried into the vocabulary, scoped to
   it, and the one body-level property worth keeping — `text-wrap:
   pretty` — rides on .ffa-wrap instead of body.                        */

.ffa-wrap a, .ffa-wrap--narrow a, .ffa-card a, .ffa-links a, .ffa-body a, .ffa-lead a, .ffa-group a { color: var(--accent); text-decoration: none; }
.ffa-wrap a:hover, .ffa-wrap--narrow a:hover, .ffa-card a:hover, .ffa-links a:hover, .ffa-body a:hover, .ffa-lead a:hover, .ffa-group a:hover { color: var(--navy); text-decoration: underline; }

/* ── Framework states ──────────────────────────────────
   css/style.css:53-56 owns the .load-data vocabulary: the fade while a
   block is loading, the terracotta border on one that failed, and the
   `:not(.loaded):not(.loading):not(.cached) [class*="view-"]` rule that
   keeps a row template invisible until its data arrives.

   That last rule covers the WAIT. It does not cover the FAILURE: a
   block whose fetch errors stops being .loading and never becomes
   .loaded, so the selector lets go of it at exactly the moment there is
   nothing to put in it, and the reader is handed the template's own
   source — {doc_name}, {issue_label}, "Full agenda, {item_count}
   items". Hiding the CHILDREN rather than the block is the point:
   style.css:55's border is untouched, so a failure is still marked for
   whoever went looking for it, and the band collapses instead of
   printing a brace at a reader who did nothing wrong.

   Opt-in, by the second class rather than by .load-data alone: the three
   Home bands are each their OWN .load-data, so collapsing one leaves the
   page standing, while the four screens of this slice wrap the WHOLE
   article in one — crumbs, h1, dek, every band and the .ffa-missing
   fallback written for exactly this case. Hiding all of that is a blank
   screen, which is worse than the braces. ffa-band-load names the
   wrappers that may collapse; a page-level wrapper never takes it.

   Here rather than beside its three siblings because of the order this
   slice uploads in (sql/DEPLOY_apple_3_meetings.md §1): css/ffa.css is
   file 6, the templates that carry those placeholders are 12–17, and
   css/style.css is 19 — LAST, after all of them. A rule added there
   would not be live until the deploy was over.                        */

.load-data.ffa-band-load.load-error > * { display: none; }

/* ── Placeholder ───────────────────────────────────────
   src/base.css .ph / .ph-tag / .ph-cap — the dashed block that stands
   in for art that does not exist yet. Its four colours have no token.  */

.ffa-ph { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; text-align: center; background: #EFE9DD; border: 2px dashed #C9BFAD; color: #6E6558; padding: 28px; box-sizing: border-box; }
.ffa-ph-tag { font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--color-text-tertiary); background: var(--warmwhite); border-radius: 999px; padding: 5px 12px; }
.ffa-ph-cap { font-size: 15px; line-height: 1.45; max-width: 520px; color: var(--ink-soft); }
.ffa-ph svg { width: 40px; height: 40px; stroke: #A89F8E; fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

/* ── Layout ────────────────────────────────────────────
   .wrap is 980px (src/desk.css). The 1200px variant is the hero-media
   column the mockups inline (src/main-body.html:18,188) — spec §3.
   House rule 7: images are full-bleed or 1200 wide with a 36px radius.

   Both are the mockup's width OR the viewport less a 24px gutter each
   side, whichever is smaller. The artboards are drawn at one fixed width
   and can say 980px and 1200px flat; a page cannot. A flat 1200px spills
   off every viewport under 1248px — and a flat 980px off every one under
   1028px — and the <= 900px block below is too late to catch either, so
   the whole band between 900px and the column's own width would scroll
   sideways. min() clamps that band; above it nothing changes, and the
   24px matches the margin the <= 900px block drops to. */

.ffa-wrap, .ffa-wrap--wide, .ffa-wrap--narrow { margin: 0 auto; text-wrap: pretty; }
.ffa-wrap { width: min(980px, calc(100% - 48px)); }
.ffa-wrap--wide { width: min(1200px, calc(100% - 48px)); }
/* The 680px variant is /meetings (slice 3, task 5): a list of rows whose
   longest line is a body's name has no business spanning 980px, so that
   page is the phone artboard widened to a reading column rather than a
   desktop layout of its own. Same min() clamp as its two siblings, so it
   needs no entry in the <= 900px block either.                         */
.ffa-wrap--narrow { width: min(680px, calc(100% - 48px)); }
.ffa-media { display: block; width: 100%; border-radius: var(--ffa-radius-media); overflow: hidden; }
.ffa-media--bleed { border-radius: 0; }

/* ── Type ──────────────────────────────────────────────
   src/desk.css. House rule 4: 92 hero, 60 section, 40 sub, 26 lead,
   19 body, 13 meta; tight tracking on anything above 40.              */

.ffa-eyebrow { font-size: 19px; font-weight: 600; color: var(--terracotta); letter-spacing: -.01em; }
.ffa-h1 { font-size: 92px; line-height: 1.0; letter-spacing: -.04em; font-weight: 700; margin: 0; }
.ffa-h2 { font-size: 60px; line-height: 1.04; letter-spacing: -.035em; font-weight: 700; margin: 0; }
.ffa-h3 { font-size: 40px; line-height: 1.08; letter-spacing: -.03em; font-weight: 700; margin: 0; }
.ffa-lead { font-size: 26px; line-height: 1.3; letter-spacing: -.012em; color: var(--ink-soft); }
.ffa-body { font-size: 19px; line-height: 1.5; color: var(--ink-soft); }
.ffa-links { display: flex; gap: 36px; font-size: 19px; font-weight: 500; }
.ffa-links a::after { content: " \203A"; }

/* ── Grounds ───────────────────────────────────────────
   House rule 3: warm white, then sand, then near-black. The band
   change is the section break.                                        */

.ffa-dark { background: var(--ffa-ink-dark); color: var(--sand); }
.ffa-dark .ffa-lead, .ffa-dark .ffa-body { color: #B9AF9E; }
.ffa-dark a { color: var(--sky-light); }
/* In the mockup `.dark a` outranks `a:hover`, so a link on the dark
   ground keeps #A0CBE0 when hovered. The scoped hover above is one
   class more specific, so the pairing is restated here.               */
.ffa-dark a:hover { color: var(--sky-light); }
/* Two dark bands that meet. Every screen orders its sections so a warm
   white or sand band separates them — page/page.agenda-item.php puts
   the documents and the related list between the public-input band and
   the speak band (:505-538), page/page.agenda-meeting.php puts the map
   and the documents between the speak band and the public-comment band
   (:357-404) — but each of those in-between bands is gated, and
   js/page.js REMOVES what does not match (:566-588) rather than hiding
   it. So an item with no documents and no related items, and a meeting
   with no mapped sites and no documents, end with two dark grounds
   touching: 240px of unbroken near-black on the desktop artboard with a
   heading somewhere in the middle of it, which reads as one long
   section that changed its mind. House rule 3 says the band change IS
   the section break, and here there is no band change left to make it.

   The hairline makes it instead, in the sand-at-12% this ground already
   spends on a ghost pill (:713). The 72px is ADDED and overrides
   nothing: .ffa-wrap carries width and margin and no padding at all
   (:81-82), so the band below the seam opens 192px under it against the
   120px the band above leaves over it. Space belongs to what is under
   it, and that asymmetry is what says the line opens a band rather than
   divides one.

   Because it is ADDED it has to step down with what it is added to.
   The bands drop from 120px to 80px at the 900px breakpoint and stay
   there on a phone, and a 72px seam under an 80px band is nearly the
   whole desktop gesture on a 390px screen — the asymmetry stops
   reading as an opening and starts reading as a gap. The counterpart
   rule is in the breakpoint block at the foot of this file, beside the
   band paddings it is proportional to.                                */

.ffa-dark + .ffa-dark { border-top: 1px solid rgba(245, 240, 232, .12); }
.ffa-dark + .ffa-dark > .ffa-wrap { padding-top: 72px; }

.ffa-sand { background: var(--sand); }

/* ── Components ────────────────────────────────────────
   src/desk.css. House rule 6: cards are white, 28px radius, soft
   shadow. House rule 2: one number gets the whole viewport.           */

.ffa-card { background: #FFFFFF; border-radius: var(--ffa-radius-card); padding: 40px; box-shadow: 0 2px 14px rgba(44,36,24,.06); display: flex; flex-direction: column; gap: 18px; }
.ffa-dark .ffa-card { background: var(--ffa-card-dark); box-shadow: none; }
.ffa-stat { font-size: 120px; line-height: 1; letter-spacing: -.05em; font-weight: 700; }
.ffa-stat-l { font-size: 22px; line-height: 1.3; color: var(--ink-soft); letter-spacing: -.01em; }
.ffa-dark .ffa-stat-l { color: #B9AF9E; }
/* The micro-label: the small all-caps line over a value. Three rules on
   three pages carried these four declarations and differed only in the
   colour of them — /this-week's pin tooltip line "CITY PLAN COMMISSION ·
   THU · ITEM 7" (retired with that page's old map by the This Week design
   pass, 2026-09-27), the facts strip's "CASE NUMBER" (.ffa-fact-l) and the
   public-input card's "WHEN" (.ffa-ai-input-l), whose ground is dark and
   whose colour is therefore the sand grey. One rule and one modifier.  */
.ffa-label { font-size: 12px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-tertiary); }
.ffa-label--soft { color: #B9AF9E; }
.ffa-pill { display: inline-flex; align-items: center; gap: 8px; border-radius: 999px; padding: 6px 12px; font-size: 13px; font-weight: 600; letter-spacing: .01em; }
.ffa-seg { display: flex; background: rgba(44,36,24,.08); border-radius: 12px; padding: 3px; font-size: 14px; font-weight: 500; }
/* Spans AND links: the artboard's segmented control is a drawing, so its
   segments are spans; a real one whose segments are URLs (the /this-week topic
   filter) is the same control and must not be a second set of rules.        */
.ffa-seg span, .ffa-seg a { padding: 8px 18px; border-radius: 9px; color: var(--ink-soft); }
/* Two ways in, one look: the class for a segment a template marks up
   itself, the attribute for one cloned from loader rows (/meetings'
   body chips), which cannot add a class conditionally and says the
   active state the way a navigation control is supposed to.         */
.ffa-seg .ffa-on, .ffa-seg a[aria-current="page"] { background: #FFFFFF; color: var(--ink); box-shadow: 0 1px 4px rgba(44,36,24,.14); font-weight: 600; }
.ffa-foot { display: flex; justify-content: space-between; font-size: 12px; color: var(--color-text-tertiary); padding: 24px 0; border-top: 1px solid rgba(44,36,24,.1); }

/* ── Grids ─────────────────────────────────────────────
   So templates never inline grid rules.                               */

.ffa-grid-2, .ffa-grid-3, .ffa-grid-4 { display: grid; gap: 24px; }
.ffa-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ffa-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ffa-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* ── One utility ───────────────────────────────────────
   Taking something off the page from script. `!important` because the
   things it is put on already carry a `display` of their own (.ffa-row
   is a flex row, .ffa-search a flex box), and a utility that loses to
   the rule it is meant to override is a bug waiting for a filter.
   It is also the JS-only gate: a control that cannot work without
   script ships with this class and js/ffa.js takes it off once the
   control is wired, so a reader with no JS never meets a dead box.   */
.ffa-hide { display: none !important; }

/* ── Home ──────────────────────────────────────────────
   The launch home (slice LH): docs/design/apple/launch-home/project/
   Main.dc.html (1440) and ShowcasePhone.dc.html (390), built by build.mjs
   in that folder. Everything the artboard inlines as a style attribute is a
   class here under the ffa-hm- family, so page/page.home.php carries markup
   and copy and no numbers. Two fixed heights on the artboard — the 440px
   photo, the 190px tract map — are aspect ratios here, for the reason the
   old hero's 620px was: a flat height under a width that shrinks is a
   cropped picture at every size but one.

   The pin map that used to sit further down this section left with its last
   reader: the This Week design pass (2026-09-27) drew /this-week's Where band
   with the shared pin_map module instead, and deleted it.                  */

.ffa-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.ffa-eyebrow--warm { color: var(--terracotta-light); }

/* The action pill — "You can still speak", "Still being decided". On a
   white card the canvas draws it sky-on-navy; on the dark ground the same
   pair, inverted. Used by Home alone, so restyled rather than renamed.    */
.ffa-pill--act { background: #E3EEF3; color: var(--navy); align-self: flex-start; }
.ffa-dark .ffa-pill--act { background: #2F4450; color: #C5E0EE; }
/* The category chip on an item card ("Zoning") and the step number.       */
.ffa-pill--kind { background: var(--sand); color: var(--ink); align-self: flex-start; }
.ffa-pill--n { background: var(--ink); color: var(--warmwhite); width: 30px; height: 30px; padding: 0; justify-content: center; font-size: 15px; }
.ffa-dark .ffa-pill--n { background: var(--sand); color: var(--ffa-ink-dark); }
/* The status→colour pairing /issues teaches; the agenda item and /issues
   still print these pills, so the rules stay where the sheet has had them. */
.ffa-pill--status.status-active     { background: rgba(164, 196, 150, .35); color: #46603C; }
.ffa-pill--status.status-monitoring { background: rgba(232, 201, 106, .35); color: #7C6420; }
.ffa-pill--status.status-resolved   { background: var(--navy-soft); color: var(--navy); }
.ffa-pill--status.status-decided    { background: var(--sky-light); color: var(--navy); }
.ffa-pill--status.status-ongoing    { background: rgba(232, 201, 106, .35); color: #7C6420; }
.ffa-pill--draft { background: rgba(44, 36, 24, .08); color: var(--ink-soft); }

/* 1. Hero — split (build.mjs H3 / A2). 540px of headline, then the figure;
   .is-solo is what js/home.js adds when the intro loader answers has_intro
   "" or fails, and the headline block then centres as the earlier round of
   the artboard drew it.                                                    */
.ffa-hm-hero { display: grid; grid-template-columns: 540px minmax(0, 1fr); gap: 72px; align-items: center; padding: 88px 0 96px; }
.ffa-hm-hero-copy { display: flex; flex-direction: column; gap: 24px; }
.ffa-hm-h1 { font-size: 76px; }
.ffa-hm-hero-links { flex-wrap: wrap; row-gap: 10px; }
.ffa-hm-hero-side { min-width: 0; }
.ffa-hm-hero.is-solo { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 112px 0 64px; }
.ffa-hm-hero.is-solo .ffa-hm-hero-copy { align-items: center; max-width: 980px; }
.ffa-hm-hero.is-solo .ffa-hm-h1 { font-size: 92px; }
.ffa-hm-hero.is-solo .ffa-hm-lead { max-width: 760px; }
.ffa-hm-hero.is-solo .ffa-hm-hero-links { justify-content: center; }
.ffa-hm-hero.is-solo .ffa-hm-hero-side { display: none; }
.ffa-hm-fig { margin: 0; display: flex; flex-direction: column; }
.ffa-hm-photo { display: block; width: 100%; aspect-ratio: 660 / 440; object-fit: cover; border-radius: var(--ffa-radius-media); }
/* The photo's src is set by js/home.js from data-src, never a literal {img} request; until
   it is, the element takes no room. The placeholder is the has_image "" branch and keeps
   its own rule below.                                                                    */
img.ffa-hm-photo:not([src]) { display: none; }
.ffa-hm-photo--ph { padding: 28px 28px 120px; }
/* The caption card floats up over the photo's foot (margin -96px), as the
   artboard draws it. position: relative so it paints over the picture.    */
.ffa-hm-cap { position: relative; margin: -96px 28px 0; padding: 28px; border-radius: 24px; gap: 12px; box-shadow: 0 10px 34px rgba(44, 36, 24, .16); }
.ffa-hm-kicker { color: var(--terracotta); }
.ffa-hm-title { font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.2; }
.ffa-hm-title a { color: var(--ink); }
.ffa-hm-title a:hover { color: var(--accent); }
.ffa-hm-cap-body { font-size: 17px; }
/* The button to the issue page (owner, 2026-09-26). Outlined, not filled: the one
   black pill on this page is the address form's (house rule 5). Two classes, so it
   outranks .ffa-card a and .ffa-card a:hover.                                     */
.ffa-hm-cap .ffa-hm-go { align-self: flex-start; display: inline-flex; align-items: center; gap: 8px; min-height: 48px; padding: 0 24px; border: 1.5px solid var(--ink); border-radius: 999px; font-size: 17px; font-weight: 700; letter-spacing: -.01em; color: var(--ink); text-decoration: none; }
.ffa-hm-cap .ffa-hm-go::after { content: "\203A"; content: "\203A" / ""; }
.ffa-hm-cap .ffa-hm-go:hover { background: var(--ink); color: var(--warmwhite); text-decoration: none; }
/* The photo's own caption, when it has one (a company's drawing says so here too). */
.ffa-hm-credit { margin: 0; font-size: 13px; line-height: 1.45; color: var(--ink-soft); }

/* The doors — HIDDEN since round 2 (page.home.php $home_show_doors); the rules stay. */
.ffa-hm-doors { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; padding: 0 0 110px; }
.ffa-hm-door { padding: 28px; border-radius: 24px; gap: 10px; color: var(--ink); }
.ffa-hm-doors .ffa-hm-door, .ffa-hm-doors .ffa-hm-door:hover { color: var(--ink); text-decoration: none; }
.ffa-hm-door-w { display: flex; align-items: center; gap: 10px; color: var(--terracotta); font-size: 15px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.ffa-hm-ico { width: 28px; height: 28px; stroke: currentColor; fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; flex: none; }
.ffa-hm-door-t { font-size: 22px; font-weight: 700; letter-spacing: -.015em; line-height: 1.2; }
.ffa-hm-door-s { font-size: 15px; line-height: 1.4; color: var(--color-text-tertiary); }

/* 3. This week (build.mjs weekStrip, itemCard). The strip is one column
   per day, however many days the loader answers (five, or six or seven
   when a weekend has a meeting): auto-flow columns of equal width.        */
.ffa-hm-week { padding: 120px 0; }
.ffa-hm-week-inner { display: flex; flex-direction: column; gap: 24px; }
.ffa-hm-week-lead { max-width: 820px; }
.ffa-hm-strip { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 12px; margin-top: 32px; }
.ffa-hm-day { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.ffa-hm-day-l { font-size: 13px; letter-spacing: .06em; }
.ffa-hm-day-list { display: flex; flex-direction: column; gap: 8px; }
.ffa-hm-day-card { padding: 18px; border-radius: 18px; gap: 6px; min-height: 112px; box-sizing: border-box; font-size: 16px; }
.ffa-hm-strip .ffa-hm-day-card, .ffa-hm-strip .ffa-hm-day-card:hover { color: var(--ink); text-decoration: none; }
.ffa-hm-day-body { display: flex; align-items: center; gap: 8px; font-size: 16px; font-weight: 600; line-height: 1.25; }
.ffa-hm-dot { flex: none; display: inline-block; width: 10px; height: 10px; border-radius: 999px; }
.ffa-hm-day-s { font-size: 13px; line-height: 1.4; color: var(--color-text-tertiary); }
.ffa-hm-day-none { min-height: 112px; border-radius: 18px; border: 1.5px dashed rgba(138, 130, 117, .45); box-sizing: border-box; display: flex; align-items: center; justify-content: center; }
.ffa-hm-week-links { margin-top: 4px; flex-wrap: wrap; row-gap: 10px; }
.ffa-hm-what { margin-top: 72px; display: flex; flex-direction: column; gap: 36px; }
.ffa-hm-what-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 32px; }
.ffa-hm-what-title { display: flex; flex-direction: column; gap: 12px; }
.ffa-hm-what-note { max-width: 300px; font-size: 15px; line-height: 1.4; color: var(--color-text-tertiary); }
.ffa-hm-items { gap: 24px; }
.ffa-hm-item { gap: 14px; padding: 24px 24px 28px; }
/* The small street map is an <img> whose src js/home.js sets from the
   Mapbox static API; without a token or a script it has no src and takes
   no room — the card is complete without it.                              */
.ffa-hm-item-map { display: block; width: 100%; aspect-ratio: 16 / 7; object-fit: cover; border-radius: 18px; }
.ffa-hm-item-map:not([src]) { display: none; }
.ffa-hm-item-nomap { aspect-ratio: 16 / 7; border-radius: 18px; border: 1.5px dashed rgba(138, 130, 117, .45); box-sizing: border-box; display: flex; align-items: center; justify-content: center; padding: 12px; text-align: center; }
.ffa-hm-item-who { display: flex; align-items: center; gap: 8px; }
.ffa-hm-item-t { font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.2; margin: 0; }
.ffa-hm-item-why { font-size: 17px; margin: 0; }
.ffa-hm-item-act { margin-top: auto; }
.ffa-hm-item-links { font-size: 17px; }

/* 2. Your neighborhood — sand (build.mjs tractPreview). The form is L3's,
   unchanged: one black pill per page (house rule 5) and this is it.       */
.ffa-hm-hood { padding: 120px 0; }
.ffa-hm-hood-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 64px; align-items: center; }
.ffa-hm-hood-copy { display: flex; flex-direction: column; gap: 22px; }
.ffa-hm-hood-h, .ffa-hm-hood-lead { max-width: 560px; }
.ffa-hm-hood-links { flex-wrap: wrap; row-gap: 10px; }
.ffa-hm-hood-side { min-width: 0; }
.ffa-address-form { display: flex; align-items: center; gap: 12px; background: #FFFFFF; border: 1px solid rgba(44, 36, 24, .14); border-radius: 999px; padding: 8px 8px 8px 22px; margin-top: 8px; max-width: 460px; }
.ffa-address-form input { flex: 1; min-width: 0; border: 0; background: none; font: inherit; font-size: 19px; color: var(--ink); }
.ffa-address-form input::placeholder { color: var(--color-text-tertiary); }
.ffa-address-form input:focus { outline: none; }
.ffa-address-form:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(61, 107, 133, .18); }
.ffa-pill--go { background: var(--ink); color: var(--warmwhite); font-size: 15px; padding: 12px 20px; border: 0; font-family: inherit; cursor: pointer; }
.ffa-address-err { color: var(--brick); font-weight: 600; max-width: 640px; }
.ffa-address-credit { margin-top: 8px; font-size: 13px; color: var(--color-text-tertiary); }
/* The card is one link; its children are spans made blocks.               */
.ffa-hm-card { padding: 40px 36px 36px; border-radius: 36px; gap: 22px; }
.ffa-hm-hood .ffa-hm-card, .ffa-hm-hood .ffa-hm-card:hover { color: var(--ink); text-decoration: none; }
.ffa-hm-tmap { display: block; position: relative; width: 100%; aspect-ratio: 480 / 190; border-radius: 20px; overflow: hidden; background: var(--sand); }
.ffa-hm-tmap-ph { position: absolute; inset: 0; border-radius: 20px; }
.ffa-hm-tmap .leaflet-container { font: inherit; font-size: 11px; background: var(--sand); }
.ffa-hm-card-meta, .ffa-hm-card-h { display: block; }
.ffa-hm-measures { display: flex; flex-direction: column; gap: 18px; }
.ffa-hm-m { display: flex; flex-direction: column; gap: 8px; }
.ffa-hm-m-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.ffa-hm-m-l { font-size: 17px; font-weight: 500; }
.ffa-hm-m-v { font-size: 26px; font-weight: 700; letter-spacing: -.02em; }
/* The median band: on a PERCENTILE track the middle half of the county is
   always the box from 25% to 75%, so the band is one fixed rule and needs
   no loader key. In front of the rail, outlined (slice 6k's band look).   */
.ffa-hm-track { display: block; position: relative; height: 20px; }
.ffa-hm-band { position: absolute; top: 0; left: 25%; width: 50%; height: 20px; border: 1.5px solid #8A8275; border-radius: 6px; box-sizing: border-box; z-index: 2; pointer-events: none; }
.ffa-hm-rail { position: absolute; left: 0; right: 0; top: 7px; height: 6px; border-radius: 3px; background: #E6DDCC; }
.ffa-hm-mark { position: absolute; top: 2px; width: 16px; height: 16px; border-radius: 50%; background: var(--terracotta); border: 2px solid #FFFFFF; margin-left: -10px; box-sizing: content-box; z-index: 3; }
.ffa-hm-ends { display: flex; justify-content: space-between; font-size: 13px; color: var(--color-text-tertiary); margin-top: 2px; }
.ffa-hm-key { display: flex; align-items: center; gap: 6px; margin-top: 4px; text-transform: none; letter-spacing: 0; font-weight: 500; }
.ffa-hm-key-swatch { flex: none; display: inline-block; width: 24px; height: 14px; border: 1.5px solid #8A8275; border-radius: 4px; box-sizing: border-box; }

/* 4. The map — dark (build.mjs, the map band). The card is the wrapper;
   the pill and the sources link stand outside it.                         */
.ffa-hm-map { padding: 120px 0; }
.ffa-hm-map-head { display: flex; flex-direction: column; gap: 24px; }
.ffa-hm-map-h, .ffa-hm-map-lead { max-width: 820px; }
.ffa-hm-mapcard-wrap { margin-top: 56px; }
.ffa-hm-mapcard { background: #24201B; border-radius: 36px; padding: 40px 48px; box-sizing: border-box; }
.ffa-hm-chips { display: flex; flex-wrap: wrap; gap: 10px; }
.ffa-hm-chip { display: inline-flex; align-items: center; gap: 10px; background: rgba(253, 251, 247, .96); color: var(--ink); border-radius: 999px; padding: 0 18px; min-height: 44px; font-size: 15px; font-weight: 600; border: 0; font-family: inherit; cursor: pointer; box-shadow: 0 4px 18px rgba(0, 0, 0, .25); }
.ffa-hm-chip[aria-pressed="false"] { background: transparent; color: var(--sand); box-shadow: inset 0 0 0 1.5px rgba(245, 240, 232, .4); }
.ffa-hm-chip:focus-visible { outline: 2px solid var(--sky-light); outline-offset: 3px; }
.ffa-hm-mapcap { margin-top: 14px; font-size: 15px; text-transform: none; letter-spacing: 0; }
/* The tract map (round 2, spec §5): a real Leaflet map in the card where the
   mosaic was — the mosaic's three heights (620 / 480 / 340) so the band's
   rhythm does not move, the card's ground behind the tiles, 20px radius
   clipping them. Its tooltip and popup rules sit with js/home.js's classes
   below; every override is prefixed with the mount so it beats Leaflet's
   own stylesheet, which FFA.leaflet() appends AFTER this one.            */
.ffa-hm-tractmap { position: relative; height: 620px; margin-top: 24px; border-radius: 20px; overflow: hidden; background: #2E2923; }
.ffa-hm-tractmap .leaflet-container { font: inherit; font-size: 13px; background: #2E2923; }
.ffa-hm-tractmap .leaflet-control-attribution { font-size: 10px; }
.ffa-hm-tractmap .leaflet-interactive { cursor: pointer; }
/* The hover tooltip and the click popup — what /map shows, in the card's own
   type. Every rule is prefixed with the mount to beat Leaflet's stylesheet,
   which arrives after this one. No arrow on the tooltip; the popup's
   wrapper takes the card radius; the link is the site's chevron link.   */
.ffa-hm-tractmap .leaflet-tooltip.ffa-hm-tip { background: #FFFFFF; color: var(--ink); border: 0; border-radius: 10px; padding: 8px 12px; box-shadow: 0 2px 12px rgba(0, 0, 0, .18); font-size: 13px; line-height: 1.4; }
.ffa-hm-tractmap .ffa-hm-tip::before { display: none; }
.ffa-hm-tractmap .ffa-hm-pop .leaflet-popup-content-wrapper { border-radius: 14px; box-shadow: 0 6px 24px rgba(0, 0, 0, .2); }
.ffa-hm-tractmap .ffa-hm-pop .leaflet-popup-content { margin: 14px 16px; font: inherit; font-size: 14px; line-height: 1.4; color: var(--ink); }
.ffa-hm-tip-name { display: block; font-weight: 600; }
.ffa-hm-tip-v { display: block; }
.ffa-hm-tip-rank { display: block; font-size: 12px; color: var(--ink-soft); }
.ffa-hm-tractmap .ffa-hm-pop-link { display: inline-block; margin-top: 8px; color: var(--terracotta); font-weight: 600; text-decoration: none; }
.ffa-hm-tractmap .ffa-hm-pop-link::after { content: " \203A"; }
.ffa-hm-legend { display: flex; flex-wrap: wrap; gap: 18px; margin-top: 28px; font-size: 13px; color: #B9AF9E; }
.ffa-hm-legend-item { display: flex; align-items: center; gap: 7px; }
.ffa-hm-legend-swatch { flex: none; width: 12px; height: 12px; border-radius: 3px; }
.ffa-hm-map-links { display: flex; align-items: center; flex-wrap: wrap; gap: 16px 36px; margin-top: 48px; }
/* The light pill: sand on the dark ground, the one prominent way into the
   map. A second pill beside the page's black one, which the house rule
   allows because it is light.                                             */
.ffa-hm-cta { display: inline-flex; align-items: center; gap: 8px; background: var(--sand); color: var(--ffa-ink-dark); border-radius: 999px; padding: 0 30px; min-height: 56px; font-size: 19px; font-weight: 700; letter-spacing: -.01em; }
.ffa-dark a.ffa-hm-cta, .ffa-dark a.ffa-hm-cta:hover { color: var(--ffa-ink-dark); text-decoration: none; }
.ffa-hm-cta::after { content: "\203A"; }
.ffa-hm-cta:hover { background: #FFFFFF; }

/* 5. Doctrine — white now.                                                 */
.ffa-doctrine { padding: 120px 0; }
.ffa-doctrine-inner { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 24px; }
.ffa-doctrine-h { max-width: 820px; }
.ffa-doctrine-p { max-width: 640px; }

/* ── This Week ─────────────────────────────────────────
   src/thisweek-body.html — the /this-week screen (page.this-week.php), re-laid
   by the design pass of 2026-09-27 from the owner's mockup (docs/superpowers/
   specs/2026-09-27-this-week-design-pass-design.md): a split hero with a live
   calendar card, one sand panel per meeting, the Where band on the shared
   pin_map module beside a numbered list, then the shared speak band below.

   The `ffa-tw-` namespace is "this week" in the new vocabulary. The retired
   `.tw-*` block in style.css is the OLD screen and has nothing to do with it;
   it is deleted once no template references it (spec §3), which is the last
   task of this slice — page.meetings.php and page.agenda-meeting.php still
   render `tw-` classes until they are rewritten.                            */

/* 1. The hero — split, in the home hero's shape (.ffa-hm-hero): 540px of copy,
   then the calendar card. Left-aligned now; only the quiet band below still
   centres. The h1 is 72px — at the vocabulary's 92px "One meeting." does not
   fit 540px, and at the home split hero's 76px "Three meetings." (555px) and
   "Seven meetings." (564px) wrap onto a third line; at 72px every count from
   One to Nine holds one line (owner, browser review 2026-09-27). Each sentence
   is its own line, the second in the accent; an empty tail (the quiet and
   filter-empty sentences) is an empty block of no height.                  */
.ffa-tw-intro { display: grid; grid-template-columns: minmax(0, 540px) minmax(320px, 1fr); gap: 72px; align-items: center; padding: 88px 0 96px; }
.ffa-tw-intro-copy { display: flex; flex-direction: column; gap: 24px; min-width: 0; }
.ffa-tw-h { font-size: 72px; }
.ffa-tw-h-lead { display: block; }
.ffa-tw-h-tail { display: block; color: var(--accent); }
.ffa-tw-lead { max-width: 660px; }
.ffa-tw-links { justify-content: flex-start; flex-wrap: wrap; row-gap: 10px; }
/* Three links since launch slice L2 ("Why go"): at 390px the row no longer fits on one line,
   and without flex-wrap the anchors shrink and break inside a label. Seen in the browser
   review, 2026-09-21. The quiet week's row (also L2) takes the band's centring: text-align
   does not centre flex items.                                                              */
.ffa-tw-quiet .ffa-links { justify-content: center; flex-wrap: wrap; row-gap: 10px; margin-top: 16px; }

/* The topic filter, drawn as the vocabulary's segmented control. Its own rules
   are layout only — the segments themselves are .ffa-seg's above.           */
.ffa-tw-filters { align-self: flex-start; flex-wrap: wrap; }
/* No underline on a segment: the hero sits in .ffa-wrap--wide, which the link
   reset at the top of this file does not name.                              */
.ffa-tw-filters a { text-decoration: none; }
.ffa-tw-filters a:hover { color: var(--ink); text-decoration: none; }
/* (owner, 2026-09-27: hidden for now; delete this declaration to bring it back)
   nav.ffa-seg.ffa-tw-filters is (0,2,1) and .ffa-seg's display: flex above is
   (0,1,0), so this wins wherever either sits, and no breakpoint block sets the
   nav's display. The markup stays, and an old ?cat= link still works.        */
nav.ffa-seg.ffa-tw-filters { display: none; }

.ffa-tw-quiet { padding: 0 0 96px; text-align: center; }

/* The calendar card (the owner's ruling R2): a live picture of the week, drawn
   in HTML from the loader's cal_days, so it is always the real month. The
   column is aria-hidden in the template — the meetings are listed one screen
   down. The blob and the card share one grid cell, centred; the strokes and
   the note hang off the column's corner.                                    */
.ffa-tw-art { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); place-items: center; min-width: 0; min-height: 380px; container-type: inline-size; }
/* The column's one track is minmax(0, 1fr), so the blob's max-width reads the
   column and not its own 460px (review, 2026-09-27: with an auto track the art
   pushed the page sideways from 901 to 1095px and under 384px). The strokes and
   the note hang off the column's corner and would sit on the card below about
   580px of column, so they go there: a container query on the art itself, not a
   third @media block (the file keeps exactly one per breakpoint).           */
@container (max-width: 579px) { .ffa-tw-note, .ffa-tw-marks { display: none; } }
.ffa-tw-blob { grid-area: 1 / 1; width: 460px; max-width: 100%; height: 320px; background: var(--sand); border-radius: 48% 52% 60% 40% / 50% 40% 60% 50%; }
.ffa-tw-cal { grid-area: 1 / 1; position: relative; z-index: 1; display: flex; flex-direction: column; gap: 14px; width: 300px; box-sizing: border-box; padding: 22px 26px; background: #FFFFFF; border-radius: 20px; box-shadow: 0 2px 14px rgba(44, 36, 24, .06); transform: rotate(-4deg); }
.ffa-tw-cal-m { font-size: 15px; font-weight: 600; color: var(--ink); text-transform: uppercase; letter-spacing: .04em; }
.ffa-tw-cal-row { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.ffa-tw-cal-d { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.ffa-tw-cal-dow { font-size: 11px; font-weight: 600; color: var(--ink-soft); }
.ffa-tw-cal-n { display: grid; place-items: center; width: 32px; height: 32px; border-radius: 50%; font-size: 15px; font-weight: 600; color: var(--ink); }
.ffa-tw-cal-d.is-meeting .ffa-tw-cal-n { background: var(--terracotta); color: #FFFFFF; }
/* Saturday and Sunday, faded (owner, 2026-09-27, prototype B): the week is
   Monday–Friday and the weekend is never marked, but the card still draws a
   whole week. {weekend_mod} in the template, from ff_week_cal_days().      */
.ffa-tw-cal-d.is-weekend { opacity: .35; }
.ffa-tw-cal-key { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-soft); }
.ffa-tw-cal-key::before { content: ""; flex: none; width: 10px; height: 10px; border-radius: 50%; background: var(--terracotta-light); }
.ffa-tw-marks { position: absolute; z-index: 1; top: 6%; right: 18%; width: 40px; height: 40px; stroke: var(--ink); fill: none; stroke-width: 1.5; stroke-linecap: round; opacity: .7; }
.ffa-tw-note { position: absolute; z-index: 1; top: 30%; right: 0; max-width: 132px; margin: 0; font-size: 16px; line-height: 1.3; font-style: italic; color: var(--ink-soft); transform: rotate(6deg); }
.ffa-tw-note svg { display: block; width: 90px; height: 60px; margin: 10px 0 0 -48px; stroke: var(--ink); fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

/* 2. One panel per meeting (the owner's mockup): a rounded sand ground each, in
   the hero's 1200px column (.ffa-wrap--wide, as the mockup draws it — owner,
   browser review 2026-09-27; the Where band beside it takes the same column),
   white cards on every one — the grounds no longer alternate by position, so
   the template carries no ground class. The head is three parts: the date
   tile, the facts over the body's name, the pill.                          */
.ffa-tw-meets { display: flex; flex-direction: column; gap: 32px; }
.ffa-tw-meeting { background: var(--sand); border-radius: 36px; padding: 56px 48px; container-type: inline-size; }
/* A narrow panel (up to about 1044px of screen) has no room for the tile, the
   longest word of a body's name and the pill on one row: the tile (120), two
   gaps (64), "Commissioners" at 60px (429) and the ES pill "Agenda completa,
   12 puntos" (280) come to 893px of the panel's 900. So the pill moves under
   the name there, as it does under 900px of screen, and the name stays whole
   (owner, browser review 2026-09-27; before this "Commissioners Court" broke
   mid-word from 901 to 973px). A container query on the panel, not a third
   @media block (the file keeps exactly one per breakpoint).                */
@container (max-width: 900px) { .ffa-tw-head { grid-template-columns: auto minmax(0, 1fr); row-gap: 20px; } .ffa-tw-agenda { grid-column: 2; } }
.ffa-tw-inner { display: flex; flex-direction: column; gap: 40px; }
.ffa-tw-head { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 32px; align-items: center; }
.ffa-tw-tile { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; width: 120px; height: 96px; box-sizing: border-box; margin: 0; background: #FFFFFF; border-radius: 24px; box-shadow: 0 2px 14px rgba(44, 36, 24, .06); }
.ffa-tw-tile-d { font-size: 15px; font-weight: 600; color: var(--terracotta); text-transform: uppercase; letter-spacing: .04em; }
.ffa-tw-tile-n { font-size: 26px; font-weight: 700; line-height: 1.1; letter-spacing: -.02em; color: var(--ink); text-transform: uppercase; white-space: nowrap; }
.ffa-tw-title { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.ffa-tw-title .ffa-h2 { overflow-wrap: anywhere; }
.ffa-tw-facts { display: flex; flex-wrap: wrap; gap: 8px 22px; margin: 0; }
/* A meeting with no time and no room: both facts are removed by js/page.js,
   and the empty row would still take its 12px gap above the name.          */
.ffa-tw-facts:not(:has(.ffa-tw-fact)) { display: none; }
.ffa-tw-fact { display: inline-flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 600; color: var(--terracotta); }
.ffa-tw-fact-ico { flex: none; width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
/* The outlined pill — the accent's ring and ink, and the CSS chevron (A4), with
   no leading space because the pill's own 8px gap spaces it (the home's
   .ffa-hm-go::after). Two classes, so the vocabulary's .ffa-wrap a and
   .ffa-wrap a:hover at the top of this file cannot turn it navy or underline
   it. It is not the page's one black pill (house rule 5).                  */
.ffa-pill.ffa-pill--outline { border: 1.5px solid var(--accent); background: transparent; color: var(--accent); font-size: 16px; font-weight: 600; padding: 12px 22px; text-decoration: none; }
.ffa-pill.ffa-pill--outline::after { content: "\203A"; content: "\203A" / ""; }
.ffa-pill.ffa-pill--outline:hover { background: rgba(61, 107, 133, .08); color: var(--accent); text-decoration: none; }

/* 3. The item cards. The whole card is the one link: the chip and the item
   number share its top row, the title is the accent, and the chevron circle in
   the corner is decoration (the card is what opens), so the card keeps 64px at
   its foot for it. Two classes on the colour rule for the reason the pill has
   two — with one, .ffa-wrap a:hover wins and the whole card underlines.     */
.ffa-tw-item { position: relative; gap: 14px; padding: 28px 24px 64px; }
.ffa-tw-meets .ffa-tw-item, .ffa-tw-meets .ffa-tw-item:hover { color: var(--ink); text-decoration: none; }
.ffa-tw-item-top { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.ffa-tw-item-no { flex: none; font-size: 15px; font-weight: 600; color: var(--accent); }
.ffa-tw-item-t { font-size: 22px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; color: var(--accent); }
.ffa-tw-item-m { font-size: 16px; }
.ffa-tw-item-hearing { display: flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 600; color: var(--ink-soft); }
.ffa-tw-item-hearing::before { content: ""; flex: none; width: 10px; height: 10px; border-radius: 50%; background: var(--terracotta-light); }
.ffa-tw-item-go { position: absolute; right: 24px; bottom: 24px; display: grid; place-items: center; width: 36px; height: 36px; border-radius: 50%; background: var(--sand); }
.ffa-tw-item-go svg { width: 8px; height: 14px; stroke: var(--ink); fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.ffa-tw-item:hover .ffa-tw-item-go { background: var(--sand-dark); }

/* 4. "N more items on this agenda." opens the rest in place (the owner's ruling
   R1). A plain button: the circled chevron is the affordance, and .is-open
   turns it over; js/ffa.js toggles [hidden] on the grid its aria-controls
   names. The [hidden] rule is NOT redundant: .ffa-grid-3 above sets display:
   grid, which outranks the browser's own [hidden] { display: none } — without
   it every agenda would render open and the button would do nothing.        */
.ffa-tw-more { display: inline-flex; align-items: center; gap: 14px; align-self: flex-start; margin: 0; padding: 0; border: 0; background: none; font: inherit; font-size: 15px; color: var(--ink-soft); cursor: pointer; }
.ffa-tw-more:hover { color: var(--ink); }
.ffa-tw-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 999px; }
.ffa-tw-more-ico { display: grid; place-items: center; flex: none; width: 36px; height: 36px; border-radius: 50%; background: rgba(44, 36, 24, .08); }
.ffa-tw-more-ico svg { width: 14px; height: 8px; stroke: var(--ink); fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.ffa-tw-more.is-open .ffa-tw-more-ico { transform: rotate(180deg); }
.ffa-tw-more-t { text-align: left; }
.ffa-tw-rest[hidden] { display: none; }

/* The category chip on an item card. The five categories the importer can
   write, in the artboard's own four chip colours plus one neutral: a category
   we have no colour for reads as "an agenda item", never as another topic.  */
.ffa-chip { align-self: flex-start; }
.ffa-chip--zoning { background: rgba(160, 203, 224, .35); color: #33607C; }
.ffa-chip--water  { background: var(--navy-soft); color: var(--navy); }
.ffa-chip--air    { background: rgba(196, 101, 74, .15); color: var(--brick); }
.ffa-chip--money  { background: rgba(232, 201, 106, .35); color: #7C6420; }
.ffa-chip--other  { background: rgba(44, 36, 24, .08); color: var(--ink-soft); }

/* 5. Where — the shared pin_map module (js/issue-modules.js): streets tiles,
   numbered teardrops, zoom, beside a numbered list whose rows share the pins'
   numbers. The meeting page's grid (.ffa-am-where-grid), hung from the top.
   The canvas has its OWN height rule — the meeting page's is 440px — and
   keeps the :not(…--fallback) guard for the reason given over that page's
   rule below. Every pin is the accent (the spec's A2) — on every module map
   since week and maps (2026-09-27), so the recolouring rule that stood here
   retired with the disc it recoloured (the pin is .ff-pin, in "Meeting").  */
.ffa-tw-where { padding: 96px 0 120px; }
.ffa-tw-where-inner { display: grid; grid-template-columns: 420px minmax(0, 1fr); gap: 48px; align-items: start; }
.ffa-tw-where-copy { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
.ffa-tw-where-note { font-size: 16px; }
.ffa-tw-sites { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.ffa-tw-site { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 16px; padding: 16px 20px; background: #FFFFFF; border: 1px solid rgba(44, 36, 24, .1); border-radius: 20px; }
.ffa-tw-sites .ffa-tw-site, .ffa-tw-sites .ffa-tw-site:hover { color: var(--ink); text-decoration: none; }
/* The row and pin tie (js/ffa.js ffa_this_week): hovering a pin lifts its row,
   and hovering a row lifts the row and its pin — one rule for both halves.  */
.ffa-tw-site:hover, .ffa-tw-site--hi { background: var(--sand); }
/* The row's number is the map's own pin (week and maps, R9): the template
   draws the module's teardrop — .ff-pin, its SVG and its .ff-pin-n label, in
   "Meeting" below — so the list and the map read as one key. Only its place
   in the row's grid is this rule's.                                         */
.ffa-tw-site-n { justify-self: center; }
.ffa-tw-site-t { font-size: 16px; line-height: 1.35; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden; }
.ffa-tw-site .ffa-chev { stroke: var(--ink-soft); }
.ffa-tw-map { min-width: 0; }
.ffa-tw-map .am-map-canvas:not(.issue-map-canvas--fallback) { height: 520px; border-radius: 32px; border: 1px solid rgba(44, 36, 24, .12); }

/* ── Crumbs ────────────────────────────────────────────
   The breadcrumb row a deep screen opens on. Shared vocabulary, not the
   meeting page's own: /item/{date}/{body}/{lid} opens on the same row,
   and a second spelling of it is two breadcrumbs that will one day sit
   at different sizes. The mockups draw it as one muted 15px line
   (src/meeting-body.html:12, src/agendadesk-body.html:12).             */

.ffa-crumbs { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; font-size: 15px; color: var(--color-text-tertiary); }
.ffa-crumbs a { color: var(--color-text-tertiary); }
.ffa-crumbs a:hover { color: var(--ink); }
/* "You are here", one step darker than the row: a current crumb that
   matched the links would read as a link that does not work.           */
.ffa-crumbs-here { color: var(--ink-soft); }

/* ── Meeting ───────────────────────────────────────────
   src/meeting-body.html — one meeting's agenda (page.agenda-meeting.php).
   Hero, the four-number glance row, the agenda as rows, the Leaflet map
   of the located items, the documents grid and the public-comment band.

   The `ffa-am-` namespace is "agenda meeting" in the new vocabulary. The
   retired `.am-*` block in style.css was the OLD screen and is deleted
   with this slice; the only `.am-*` rules that remain are the ones
   js/issue-modules.js writes for EVERY module map on the site
   (.am-map-canvas, .am-legend, .am-legend-item), which the issue and
   case pages draw too and which this page's map still uses.            */

.ffa-am-intro { display: flex; flex-direction: column; align-items: flex-start; gap: 22px; padding: 72px 0 64px; }
/* The artboard prints the body's name one notch under the 92px hero
   (src/meeting-body.html:13): it is a page title, not a headline.      */
.ffa-am-h { font-size: 72px; }
.ffa-am-blurb { max-width: 720px; }
.ffa-am-status { display: flex; flex-wrap: wrap; gap: 8px; }
.ffa-pill--upcoming { background: rgba(61, 107, 133, .12); color: var(--accent); }
.ffa-pill--held { background: rgba(44, 36, 24, .08); color: var(--ink-soft); }

/* The four numbers — src/meeting-body.html:19-26. auto-fit rather than
   the artboard's repeat(4): three of the four cells are evidence-gated,
   so a meeting with no rezoning and no staff report renders two, and
   two equal columns look intentional where two orphans in a four-track
   grid look broken.                                                    */
.ffa-am-glance-sec { padding-bottom: 96px; }
.ffa-glance { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 20px; }
.ffa-glance-cell { background: var(--sand); box-shadow: none; gap: 6px; padding: 28px 30px; }
.ffa-glance-n { font-size: 56px; font-weight: 700; letter-spacing: -.04em; line-height: 1; }
.ffa-glance .ffa-stat-l { font-size: 17px; }
/* Each tile is now an <a> to the section it counts, so it must not take
   the accent colour or the hover underline from the base rule at the top
   of this file — which is one class and one type, so two classes is what
   it takes to outrank it. Same arithmetic .ffa-ai-docs .ffa-doc-main and
   .ffa-group .ffa-mt-row do, and the same reason: a card that IS a link
   still has to read as a card. The hover ring is .ffa-item-row's, the
   other card-shaped link on this page — the tile has no box-shadow to
   lose, so the ring is the whole affordance.                           */
.ffa-glance .ffa-glance-cell, .ffa-glance .ffa-glance-cell:hover { color: var(--ink); text-decoration: none; }
.ffa-glance .ffa-glance-cell:hover { box-shadow: 0 0 0 2px var(--accent); }

/* The agenda — src/meeting-body.html:28-41. Number, title and its line,
   staff chip, place. The whole row is the link.                        */
.ffa-am-items { padding: 96px 0; }
.ffa-am-items-inner { display: flex; flex-direction: column; gap: 32px; }
.ffa-am-rows { display: flex; flex-direction: column; gap: 10px; }

/* The mockup's grid is 70px / 1fr / 200px / 200px with 24px gaps. The map
   cell (below) took its width out of the title column — the wrap is 980px
   at every desktop size, so 120px more of columns left the title 234px
   wide and a Legistar case title on four lines. Rebalanced (2026-09-22):
   the number's column to 56px (a two-digit 26px number is 32px), the place
   column to 150px (a street name at 14px), the gaps to 20px, the map to
   108px — the title column comes back to 326px, 28px short of what it had.
   The chip column keeps its 200px: "Staff recommends: approve with
   conditions" already wraps in it, and "Staff recommends: approve" would
   start to at 180.

   align-items: start, not center (owner, 2026-09-22): on a long row — a
   five-line title over a summary — a centred number, map and chip floated
   at mid-height with air above and below, and the chip sat alone far
   right. Everything now hangs from the row's first line, beside the
   title; the number gets a padding-top below so its caps sit level with
   the title's, and the place turns out to need none.                   */
.ffa-item-row { display: grid; grid-template-columns: 56px 108px minmax(0, 1fr) 200px 150px; gap: 20px; align-items: start; padding: 22px 30px; }
.ffa-item-row, .ffa-item-row:hover { color: var(--ink); text-decoration: none; }
/* The small map of the site, column two (owner, 2026-09-22): one Mapbox
   static image per located row, 4:3 in a 108px cell, the site-plan
   thumbnail's hairline and radius. The cell is always there — an empty
   108px on an unlocated row, so the titles line up down the list — and
   the image hides itself until js/callbacks.js gives it a src, the same
   :not([src]) the home's week cards use, so a row never shows a broken
   picture while the script has not run or the site has no token.       */
.ffa-item-thumb { min-width: 0; }
.ffa-item-thumb-img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 12px; border: 1px solid var(--sand-dark); background: var(--warmwhite); }
.ffa-item-thumb-img:not([src]) { display: none; }
/* The row↔pin tie (js/callbacks.js): hovering a pin lifts its row and
   hovering a row lifts its pin. One rule for both, so the two halves of
   the same gesture can never drift apart.                              */
.ffa-item-row:hover, .ffa-item-row--hi { box-shadow: 0 0 0 2px var(--accent); }
/* The number sits on the title's first line. line-height 1, so its line
   box is its own 26px; then 2px down, because the two cap lines are not
   where the two line boxes start. DM Sans is 0.992 up and 0.310 down with
   caps at 0.700, so the caps start (0.992 - 0.700) = 0.292em below the
   content area's top, and a browser centres that 1.302em content area in
   the line box. Title: 19px at 1.3 is a 24.7px line box round a 24.74px
   content area, so the caps start at (24.7 - 24.74) / 2 + 0.292 * 19 =
   5.5px. Number: 26px at 1 is a 26px box round a 33.85px content area, so
   its caps start at (26 - 33.85) / 2 + 0.292 * 26 = 3.7px. 5.5 - 3.7 =
   1.8px, rounded to 2.                                                 */
.ffa-item-n { font-size: 26px; font-weight: 700; letter-spacing: -.03em; line-height: 1; padding-top: 2px; color: var(--color-text-tertiary); }
.ffa-item-row:hover .ffa-item-n, .ffa-item-row--hi .ffa-item-n { color: var(--accent); }
.ffa-item-main { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.ffa-item-t { font-size: 19px; font-weight: 600; letter-spacing: -.01em; line-height: 1.3; }
/* The address, straight under the title — the tail am_title_short() cuts
   off the officialese, given a line of its own. It sits BETWEEN the title
   and the summary in weight as well as in order: the summary's size, the
   title's ink, and a half step of weight, because on a list of six plats
   the street number is the thing a reader came to find and it must not
   read as the first words of the sentence under it.                     */
.ffa-item-loc { font-size: 15px; line-height: 1.4; font-weight: 500; color: var(--ink); }
.ffa-item-l { font-size: 15px; }
.ffa-item-rec { min-width: 0; display: flex; }
.ffa-item-row .ffa-pill { align-self: flex-start; text-align:center; }
/* The place, on the title's first line too. The same arithmetic as the
   number's, at 14px on the body's 1.65: a 23.1px line box round an 18.23px
   content area puts its caps at (23.1 - 18.23) / 2 + 0.292 * 14 = 6.5px,
   already 1px BELOW the title's 5.5px — so the padding-top this column
   would need is negative, and it gets none. A pixel low beside a 19px
   title is level to the eye; a pixel high is not.                      */
.ffa-item-area { min-width: 0; font-size: 14px; color: var(--color-text-tertiary); }

/* The issue and tract chips, on one line under the title — on the agenda row
   and on the This Week card both, which is why this rule is not named after
   either of them. It used to collapse itself with :empty, because js/page.js
   REMOVES an element whose data-show_if fails and a row with neither an issue
   nor a tract was left holding an empty wrapper — a gap in a flex column that
   the reader reads as a missing line. :empty matches only a wrapper with
   NOTHING left inside it, a newline included, so that rule made a stylesheet
   out of a whitespace convention: the two chip tags had to be written with no
   space between them, in two templates, and a paragraph of comment in each one
   was all that held the convention up. Both loaders answer has_chips now and
   the wrapper is gated on it like everything else here, so the whitespace is a
   formatting choice again.

   The tract chip is the sky pairing — the same ground and ink the issue guide
   spells --chip-sky-bg / --chip-sky-ink (css/style.css:999). Written out here
   rather than referenced: those custom properties are declared on .issue-guide
   and are not in scope on any of these pages, and the chip rules around this
   one are literals for the same reason. The issue chip is NOT redefined here:
   .ffa-pill--issue is further down this file, it has been on the item page
   since that page shipped, and repainting a chip a reader already knows is not
   what this pass was asked to do. */
.ffa-chiprow { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.ffa-pill--tract { background: rgba(160, 203, 224, .35); color: #33607C; }

/* The three recommendations a published staff report can carry, in the
   artboard's own chip colours. There is no fourth: "none" and anything
   the enum does not know render no chip at all.                        */
.ffa-pill--rec-approve    { background: rgba(164, 196, 150, .3); color: #4A6B3F; }
.ffa-pill--rec-conditions { background: rgba(232, 201, 106, .35); color: #7C6420; }
.ffa-pill--rec-deny       { background: rgba(196, 101, 74, .15); color: var(--brick); }

/* "Staff recommendations: 1 approve · 1 deny" — the whole agenda's
   breakdown, between the heading and the rows it summarises. Quiet, like
   the note at the foot of the same list: it is a count of the chips in
   column three, not a finding of its own.                               */
.ffa-am-staffrec { font-size: 15px; color: var(--color-text-tertiary); }
.ffa-am-note { font-size: 15px; color: var(--color-text-tertiary); }
.ffa-am-quiet { padding: 0 0 96px; }

/* Where these items are — src/meeting-body.html:56-65. Copy in a 420px
   column, the map beside it. The map itself is the Leaflet pin map
   js/issue-modules.js has always drawn; only this shell is new.

   :not(.issue-map-canvas--fallback) is load-bearing. style.css:3154
   says the Leaflet-unreachable fallback list must outrank every canvas
   height, and a bare `.ffa-am-map .am-map-canvas` here would out-rank it
   from a later file and trap the fallback rows in a 440px box.         */
.ffa-am-where { padding: 96px 0; }
/* Under the four numbers since 2026-09-22 (owner), and on the SAND ground
   since the same day: the band is .ffa-sand in the template now, so it
   keeps its own 96px top like every band that opens on a new ground. (For
   a few hours it was a warm band after a warm one and a sibling rule here
   dropped its top padding; that rule went with the warm ground.)       */
.ffa-am-where-grid { display: grid; grid-template-columns: 420px minmax(0, 1fr); gap: 48px; align-items: center; }
.ffa-am-where-copy { display: flex; flex-direction: column; gap: 18px; }
.ffa-am-map { min-width: 0; }
.ffa-am-map .am-map-canvas:not(.issue-map-canvas--fallback) { height: 440px; border-radius: 32px; border: 1px solid rgba(44, 36, 24, .12);}
.ffa-tw-map .am-legend, .ffa-am-map .am-legend { margin-top: 14px; }
/* The pin and venue tooltips on THIS map only (owner, 2026-09-22): the
   venue's permanent label, "THORMAN CONFERENCE ROOM, 801 TEXAS AVE,
   BASEMENT", was a narrow translucent box over the colourful streets
   tiles — style.css:1210 paints every module map's tooltip a see-through
   warm white at .72rem in a 220px box (:2529), which the issue guides
   keep for their one label (on streets tiles too since the owner's R7,
   2026-09-27). Scoped under .ffa-am-map so the
   issue guides and the item page keep theirs; (0,4,0) in this later file
   outranks style.css's (0,3,0). Solid white, the card shadow, wider, and
   at 14px, the place column's size (semibold stays, from style.css's font
   shorthand). Leaflet's own opacity .9 is set inline, so the pin_map
   module passes opacity 1 (js/issue-modules.js).

   width: max-content is what actually makes it wider. The tooltip is
   absolutely positioned inside the map pane, and a shrink-to-fit box
   there is only as wide as the room between the pin and the pane's right
   edge — a pin near the edge got a 96px box and "4 · 11412 MONTANA AVE"
   on three lines whatever max-width said (local review, 2026-09-22).
   max-content ignores that edge; the 300px cap still wraps a long one.
   /this-week's Where map shares both rules since its design pass
   (2026-09-27), its selector PREPENDED: ffa/t23 pins this rule's text from
   `.ffa-am-map` on, and a selector appended after it would break that.  */
.ffa-tw-map .am-map-canvas .leaflet-tooltip.map-marker-label, .ffa-am-map .am-map-canvas .leaflet-tooltip.map-marker-label { width: max-content; max-width: 300px; background: #FFFFFF; color: var(--ink); border: 1px solid var(--sand-dark); box-shadow: 0 2px 14px rgba(44, 36, 24, .14); padding: 8px 12px; border-radius: 10px; font-size: 14px; line-height: 1.35; }

/* The pin — every pin_map map on the site: this page, /this-week and the
   case-study page (week and maps, owner 2026-09-27, R8; spec docs/superpowers/
   specs/2026-09-27-week-and-maps-design.md §4.2). The neighborhood around-
   map's teardrop, numbered, in the accent; the venue the brick #B8562E with a
   white ★. MOVED from css/style.css, where it was a 26px navy disc in a 30x30
   box anchored at its centre; the class names stayed, so the hover wiring in
   js/ffa.js and js/callbacks.js (.ff-pin-wrap--hi) is untouched. The divIcon
   is 30x38 and anchored at the POINT, 15,37 (js/issue-modules.js), and the SVG
   is the sprite's path (viewBox 0 0 24 30) at 1.25x, so the head is 25px
   across and centred 14px down (11/30 of the height). The label sits in it:
   13px for one character, 11px for two ("22", "4a"), 9px for three or more.
   Lit, it grows 1.2x from the point, as .ffa-around-pin--lit does, so the
   point stays on the place. The legend's glyph is the same teardrop at 16x20,
   with no label.                                                            */
.ff-pin-wrap { background: none; border: none; }
.ff-pin { position: relative; display: block; width: 30px; height: 38px; color: var(--accent); transform-origin: 50% 100%; transition: transform .12s ease; }
.ff-pin svg { display: block; width: 30px; height: 38px; fill: currentColor; stroke: #FFFFFF; stroke-width: 1.5; filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .25)); }
.ff-pin-n { position: absolute; top: 2px; left: 0; width: 30px; height: 24px; line-height: 24px; text-align: center; color: #FFFFFF; font-size: 13px; font-weight: 700; letter-spacing: -.02em; }
.ff-pin-n--2 { font-size: 11px; }
.ff-pin-n--3 { font-size: 9px; }
.ff-pin--venue { color: #B8562E; }
.ff-pin-wrap--hi .ff-pin { transform: scale(1.2); }
.ff-pin--legend { display: inline-block; flex: 0 0 16px; width: 16px; height: 20px; vertical-align: middle; }
.ff-pin--legend svg { width: 16px; height: 20px; }

/* Documents — src/meeting-body.html:67-76. */
.ffa-am-docs { padding: 96px 0; }
.ffa-am-docs-inner { display: flex; flex-direction: column; gap: 28px; }
.ffa-doc-row { flex-direction: row; align-items: center; gap: 16px; padding: 20px 26px; }
.ffa-doc-tag { flex: none; font-size: 12px; font-weight: 700; color: var(--color-text-tertiary); border: 1px solid rgba(44, 36, 24, .2); border-radius: 6px; padding: 3px 7px; }
.ffa-doc-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ffa-doc-t { font-size: 17px; font-weight: 600; line-height: 1.3; }
.ffa-doc-m { font-size: 14px; }
.ffa-doc-open { flex: none; font-size: 15px; }
.ffa-am-more > summary { cursor: pointer; font-size: 15px; color: var(--accent); }
.ffa-am-more-grid { margin-top: 14px; }

/* Public comment — src/meeting-body.html:78-85. */
.ffa-am-comment { padding: 120px 0; }
.ffa-am-comment-inner { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 22px; }
.ffa-am-comment-h { max-width: 860px; }
.ffa-am-comment-lead { max-width: 640px; }
.ffa-am-comment-links { justify-content: center; }

/* Where this page came from, and what it says when there is no meeting:
   .ffa-prov and .ffa-missing, in "Shared bands" at the foot of this file.
   The meeting page and the item page each had a rule of its own with the
   same four declarations in it.                                         */

/* ── Agenda item ───────────────────────────────────────
   src/agendadesk-body.html (desktop) and src/agenda-body.html (the phone
   artboard, which governs <= 600px and is where the vote card comes from)
   — one agenda item, page.agenda-item.php. Hero, the staff report's front
   page as a facts strip, the vote, "from the staff report", the half mile
   around it, the public-input band, documents and the related items.

   The `ffa-ai-` namespace is "agenda item" in the new vocabulary. The
   `.ai-*` block in style.css is the OLD screen and stays where it is: it
   is not this slice's to delete — page/page.case.php borrows it on
   purpose (see its comment at :218-219) and page/page.meeting-transcript
   .php builds on it too. This namespace is never `class="ai-` and never
   ' ai-', so the retired-prefix grep can tell the two apart.          */

.ffa-ai-intro { display: flex; flex-direction: column; align-items: flex-start; gap: 18px; padding: 72px 0 56px; }
/* The artboard prints the item's title at 76px with a 1000px measure
   (src/agendadesk-body.html:14): a page title one notch under the hero. */
.ffa-ai-h { font-size: 76px; max-width: 1000px; }
/* The officialese as an H1 is a paragraph of capitals, not a headline —
   the same reason the old page had a --long variant.                  */
.ffa-ai-h--long { font-size: 40px; letter-spacing: -.02em; }
.ffa-ai-lead { max-width: 760px; }
.ffa-ai-official { max-width: 760px; font-size: 15px; color: var(--color-text-tertiary); }
.ffa-ai-when { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; font-size: 15px; color: var(--color-text-tertiary); }
.ffa-ai-status { background: rgba(61, 107, 133, .12); color: var(--accent); }
.ffa-pill--issue { background: var(--navy-soft); color: var(--navy); }
.ffa-ai-when a.ffa-pill--issue:hover { text-decoration: none; }

/* The facts strip — src/agendadesk-body.html:19-27. The artboard draws a
   fixed 3x2 grid with a border under the first row; the page clones one
   cell per fact, so the border belongs to the CELL and the strip only
   owns the line above the first row. Two facts then read as one row with
   a rule under it, which is what the artboard's row looks like.       */
.ffa-ai-facts-sec { padding-bottom: 96px; }
.ffa-facts-strip { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid rgba(44, 36, 24, .12); }
.ffa-fact { display: flex; flex-direction: column; gap: 4px; padding: 22px 0; border-bottom: 1px solid rgba(44, 36, 24, .12); }
.ffa-fact-v { font-size: 17px; font-weight: 600; line-height: 1.35; }

/* The vote — src/agenda-body.html:14-30. On the warm-white ground with
   the two sections above it, because the section under it is the sand
   one and two sand bands in a row would read as one band with a seam. */
.ffa-ai-vote { display: flex; flex-direction: column; gap: 18px; padding-bottom: 96px; }
.ffa-vote-card { gap: 14px; max-width: 560px; padding: 28px 32px; }
.ffa-vote-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.ffa-vote-tally { font-size: 34px; font-weight: 700; letter-spacing: -.03em; line-height: 1; font-variant-numeric: tabular-nums; }
.ffa-vote-dash { color: #B5AC9C; font-weight: 500; }
/* One segment per vote, so the bar is drawn by the data and not by a
   flex ratio typed into a style attribute. gap + overflow give the
   artboard's hairline-separated pill.                                 */
.ffa-vote-bar { display: flex; gap: 3px; height: 14px; border-radius: 999px; overflow: hidden; }
.ffa-vote-seg { flex: 1 1 0; min-width: 0; }
.ffa-vote-seg--yes { background: #7A9A6D; }
.ffa-vote-seg--no { background: #C4654A; }
.ffa-vote-seg--other { background: #B9AF9E; }
.ffa-vote-counts { display: flex; justify-content: space-between; gap: 16px; font-size: 13px; color: var(--color-text-tertiary); }
.ffa-vote-motion { font-size: 16px; }
.ffa-vote-meta { display: flex; flex-wrap: wrap; gap: 14px; font-size: 13px; color: var(--color-text-tertiary); }
/* The outcomes a recorded motion can carry, in the artboard's own badge
   colours. A motion to DENY that passes is coloured as a denial: the
   colour follows what happened to the item, not to the motion. The
   NEUTRAL badge is the site's ochre chip pairing, and it is what a
   deferral, a tabling, a continuance or a referral with no
   recommendation wears — the meeting acted, the item is still open, and
   neither green nor red would be true. The grey --vote-other stays: it
   is the roll's badge for a member who abstained, recused or was absent,
   which is a different fact from the motion's own outcome.            */
.ffa-pill--vote-yes, .ffa-badge--vote-yes { background: rgba(164, 196, 150, .35); color: #4A6B3F; }
.ffa-pill--vote-no, .ffa-badge--vote-no { background: rgba(196, 101, 74, .18); color: #A8342A; }
.ffa-pill--vote-neutral, .ffa-badge--vote-neutral { background: rgba(232, 201, 106, .25); color: #7C6420; }
.ffa-pill--vote-other, .ffa-badge--vote-other { background: rgba(44, 36, 24, .08); color: var(--ink-soft); }

.ffa-ai-roll { display: flex; flex-direction: column; gap: 12px; max-width: 560px; }
.ffa-ai-roll-h { font-size: 22px; letter-spacing: -.01em; }
.ffa-vote-row { justify-content: space-between; }
.ffa-vote-name { flex: 1; min-width: 0; }

/* From the staff report — src/agendadesk-body.html:29-48.            */
.ffa-ai-report { padding: 96px 0; }
.ffa-ai-report-grid { gap: 64px; align-items: start; }
.ffa-ai-report-copy, .ffa-ai-means { display: flex; flex-direction: column; gap: 22px; }
.ffa-ai-draft { align-self: flex-start; }
.ffa-ai-note { font-size: 13px; line-height: 1.6; color: var(--color-text-tertiary); }
.ffa-ai-siteplan-h { font-size: 15px; font-weight: 600; color: var(--ink-soft); margin-bottom: 10px; }
.ffa-siteplan { display: flex; flex-direction: column; }
.ffa-siteplan-link { display: block; }
.ffa-siteplan-canvas { display: block; max-width: 100%; border-radius: 14px; border: 1px solid var(--sand-dark); background: var(--warmwhite); }
/* "What this could mean for you" / "In plain words": the artboard's
   bordered list (:38-44), one line per row, the ink of body copy rather
   than the muted grey — these sentences are the point of the section. */
.ffa-ai-lines { display: flex; flex-direction: column; border-top: 1px solid rgba(44, 36, 24, .12); margin-top: 12px; }
.ffa-ai-line { font-size: 17px; color: var(--ink); padding: 18px 0; border-bottom: 1px solid rgba(44, 36, 24, .12); }

/* The half mile around it — src/agendadesk-body.html:50-66. Copy on
   the left, the map on the right, and since 2026-09-22 the tract's
   numbers in a full-width row under both: the cards are the
   neighborhood page's measure cards — the same .ffa-card
   .ffa-measure-card markup, so every rule that card has (the tone, the
   rail, the band, the ring, the labels, the phone sizes) draws them —
   and they sit the way .ffa-nb-measures sits them: .ffa-grid-3 at 20px,
   one column at <= 900px, two at <= 600px. The national median is the
   one line that card has not; it reads like the labels under the bar.

   :not(.issue-map-canvas--fallback) is load-bearing. style.css:1223
   says the Leaflet-unreachable fallback list must outrank every canvas
   height, and a bare `.ffa-ai-map .issue-map-canvas` here would outrank
   it from a later file and trap the fallback rows in its fixed box.  */
/* Top padding since 2026-09-22 (owner): after the sand staff-report band
   the map's top edge sat on the band's edge. The sections above that are
   the same warm white end on their own padding, so after one of them this
   one starts at 0, as it always did. js/page.js REMOVES a gated section, so
   the + finds whichever section really is above.                        */
.ffa-ai-data { padding: 120px 0; }
:is(.ffa-ai-intro, .ffa-ai-facts-sec, .ffa-ai-vote) + .ffa-ai-data { padding-top: 0; }
.ffa-ai-data-grid { display: grid; grid-template-columns: minmax(0, 1fr) 520px; gap: 48px 64px; align-items: center; }
.ffa-ai-data-copy { display: flex; flex-direction: column; gap: 18px; }
.ffa-ai-numbers { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 18px; }
.ffa-ai-cards { gap: 20px; }
.ffa-ai-natl { margin-top: 6px; font-size: 13px; line-height: 1.3; color: var(--color-text-tertiary); font-variant-numeric: tabular-nums; }
.ffa-ai-source { line-height: 1.5; }
.ffa-ai-map { min-width: 0; }
/* The neighborhood hero map's box since 2026-09-22 (owner): .ffa-nb-map's
   400px, 32px radius and ink-at-12% hairline, 320px at <= 900px and 240px
   at <= 600px, and its Leaflet type — the site's font, not Leaflet's
   Helvetica. Only the box: the tiles are js/issue-modules.js's, shared
   with the issue pages. */
.ffa-ai-map .issue-map-canvas:not(.issue-map-canvas--fallback) { height: 400px; border-radius: 32px; border: 1px solid rgba(44, 36, 24, .12); box-sizing: border-box; }
.ffa-ai-map .leaflet-container { font: inherit; font-size: 13px; }
.ffa-ai-map .leaflet-control-attribution { font-size: 10px; }

/* Public input — src/agendadesk-body.html:68-80.                      */
.ffa-ai-input { padding: 120px 0; }
.ffa-ai-input-grid { gap: 64px; align-items: center; }
.ffa-ai-input-copy { display: flex; flex-direction: column; gap: 22px; }
.ffa-ai-input-card { gap: 8px; }
.ffa-ai-input-v { font-size: 20px; font-weight: 700; letter-spacing: -.015em; line-height: 1.25; }
.ffa-ai-input-v--place { font-size: 16px; font-weight: 500; color: #B9AF9E; }
/* The two pills of the artboard's dark card (:78): one filled in the
   warm sand, one the translucent ghost beside it. On the dark ground
   they must not take `.ffa-dark a`'s sky-blue, so both name their own
   colour — two classes, because that rule is one class and one type.  */
.ffa-ai-input-links { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }
.ffa-ai-input-links .ffa-pill { font-size: 15px; padding: 12px 20px; }
.ffa-dark .ffa-pill--light, .ffa-dark .ffa-pill--light:hover { background: var(--sand); color: var(--ffa-ink-dark); text-decoration: none; }
.ffa-dark .ffa-pill--ghost, .ffa-dark .ffa-pill--ghost:hover { background: rgba(245, 240, 232, .12); color: var(--sand); text-decoration: none; }

/* Documents — src/agendadesk-body.html:82-90. The same .ffa-doc-row the
   meeting page uses, and now the same shape: the row is a card, and the
   two things a reader can open — our mirrored copy and the city's own
   page — are two links inside it. .ffa-doc-main is the one that carries
   the row, so it takes the flex and it is the one that must not wear the
   link colour or the hover underline from the base rule at the top of
   this file — one class and one type, so two classes is what it takes to
   outrank it. .ffa-doc-orig is the opposite case: it IS a second target
   and has to look like one, so it takes nothing but its size — the
   shared `.ffa-card a` rule above gives it the accent colour and the
   hover underline every other link on the site has, which is the same
   treatment the meeting page's "(city original)" already wears.       */
.ffa-ai-docs { padding: 96px 0; }
.ffa-ai-docs-inner { display: flex; flex-direction: column; gap: 24px; }
.ffa-ai-docs .ffa-doc-main, .ffa-ai-docs .ffa-doc-main:hover { color: var(--ink); text-decoration: none; }
/* Stacked since 2026-09-22 (owner): the meeting page lays .ffa-doc-row out
   as a row in a two-column grid, and so did this page in a THREE-column
   one, which left the name a one-word-wide column between the tag and
   "(city original)". Here the tag sits on top, the name under it, and the
   city's link at the foot of the card (the name takes the slack, so the
   links line up across a row of cards). The meeting page is untouched.  */
.ffa-ai-docs .ffa-doc-row { flex-direction: column; align-items: flex-start; gap: 10px; }
.ffa-doc-orig { flex: none; font-size: 14px; }

/* Related items, and the page's last two lines.                       */
/* Top padding since 2026-09-22 (owner), for the .ffa-ai-data reason: after
   the sand documents band (or the dark public-input one) the heading sat on
   the band's edge; after the warm-white data section it starts at 0.
   The rows are /meetings rows: the short title with the date and status
   under it, the chevron at the end, the same hover, and the group lifted
   off the warm-white ground by the shadow it wears on sand.             */
.ffa-ai-related { display: flex; flex-direction: column; gap: 14px; padding: 96px 0; }
:is(.ffa-ai-intro, .ffa-ai-facts-sec, .ffa-ai-vote, .ffa-ai-data) + .ffa-ai-related { padding-top: 0; }
.ffa-ai-related-h { font-size: 22px; letter-spacing: -.01em; }
.ffa-ai-related .ffa-group { box-shadow: 0 2px 14px rgba(44, 36, 24, .06); }
.ffa-ai-rel { gap: 16px; }
.ffa-ai-related .ffa-ai-rel, .ffa-ai-related .ffa-ai-rel:hover { color: var(--ink); text-decoration: none; }
.ffa-ai-related .ffa-ai-rel:hover { background: rgba(44, 36, 24, .045); }
.ffa-ai-rel-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }

/* ── The meetings index ────────────────────────────────
   src/meetings-body.html, which is a PHONE artboard and the only
   reference in this slice with no desktop drawing beside it. The plan's
   ruling is a 680px centred column (.ffa-wrap--narrow above), so the
   page is that artboard widened to a reading measure: the same grouped
   lists, the same search field, the same one dark card, and only the
   rhythm around them changes with the viewport. Its .tabbar and .screen
   are deliberately not ported (spec §3: the site has neither).        */

/* 1. The title, on the warm-white ground. */
.ffa-mt-intro { display: flex; flex-direction: column; gap: 20px; padding: 96px 0 56px; }
.ffa-mt-lead { max-width: 560px; }

/* 2. Everything else, on sand — house rule 8's "grouped white lists on
      sand", which is the one ground a white .ffa-group can sit on and
      still read as a card.                                             */
.ffa-mt-list { padding: 56px 0 96px; }
.ffa-mt-inner { display: flex; flex-direction: column; gap: 14px; }

/* The search field. A label, not a form: with script off it is hidden
   (.ffa-hide, taken off by js/ffa.js), and a stray Enter must never
   reload the page to no effect.                                        */
.ffa-mt-search { padding: 12px 16px; cursor: text; }
.ffa-mt-search input { flex: 1; min-width: 0; border: 0; background: none; padding: 0;
    font: inherit; font-size: 17px; color: var(--ink); }
.ffa-mt-search input::placeholder { color: var(--color-text-tertiary); opacity: 1; }
.ffa-mt-search input:focus { outline: none; }
.ffa-mt-search:focus-within { box-shadow: 0 0 0 2px var(--accent); }

/* The body chips. The same segmented control /this-week filters with,
   wrapping, because the number of bodies is the import's business and
   a control that cannot wrap would push the fourth one off a phone.
   The cloned chips share one parent (the view container), so that
   parent is a wrapping flex row of its own rather than display:
   contents — which would work, and would also drop the element out of
   the accessibility tree on the browsers that shipped it first.       */
.ffa-mt-filters { flex-wrap: wrap; align-self: flex-start; max-width: 100%; }
.ffa-mt-chips { display: flex; flex-wrap: wrap; min-width: 0; }
/* A body whose every meeting is older than the listing's 24-month floor
   keeps its chip — we hold those meetings and each one still has its
   page — and the chip says so before it is clicked, one step quieter
   than the rest of the row. Scoped inside the segmented control on
   purpose: the .ffa-chip--* family above is the item card's category
   pill, and this modifier is the body chip's. It comes after
   .ffa-seg a[aria-current="page"] and carries the same weight, so the
   colour stays quiet on the active chip too — the white pill is what
   marks that one, and "nothing in two years" is still true of it.    */
.ffa-seg a.ffa-chip--past { color: var(--color-text-tertiary); }

/* 3. The one dark card — house rule 8, "one dark card for the thing
      that matters this week". It carries its own ground because it sits
      INSIDE a sand section, where neither .ffa-dark .ffa-card nor the
      white .ffa-card default is what the artboard draws.               */
.ffa-mt-week { background: var(--ffa-ink-dark); border-radius: 22px; padding: 24px 26px; gap: 14px; box-shadow: none; margin: 4px 0 10px; }
.ffa-mt-week-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.ffa-mt-week-eyebrow { font-size: 12px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: #B9AF9E; }
.ffa-mt-week-badge { background: var(--terracotta); color: var(--warmwhite); }
.ffa-mt-week-h { font-size: 22px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; }
.ffa-mt-week-days { display: flex; flex-wrap: wrap; gap: 8px 14px; font-size: 13px; }
.ffa-dark .ffa-mt-week-day, .ffa-dark .ffa-mt-week-day:hover { color: #B9AF9E; }
/*    A chip whose day has been held. week[] is the whole Monday–Sunday
      window, so by Friday most of these chips are meetings nobody can
      attend any more; struck through and a shade back, they read as the
      record they are instead of as an invitation. Scoped under .ffa-dark
      and carrying :hover for the same reason the line above does — the
      colour it overrides is two classes, so a bare modifier would lose
      to the thing it modifies.                                          */
.ffa-dark .ffa-mt-week-day--held, .ffa-dark .ffa-mt-week-day--held:hover { color: #7E766A; text-decoration: line-through; }
.ffa-mt-week-links { font-size: 15px; }

/* 4. The month groups: two sections (ahead, then held), each a heading
      over one white group per month. The month caption is quieter than
      the section heading on purpose — two uppercase labels in a row
      would read as two sections, not a section and its months.        */
.ffa-mt-groups { display: flex; flex-direction: column; gap: 30px; padding-top: 6px; }
.ffa-mt-block { display: flex; flex-direction: column; gap: 10px; }
.ffa-mt-months { display: flex; flex-direction: column; gap: 16px; }
.ffa-mt-group { display: flex; flex-direction: column; gap: 4px; }
.ffa-mt-month { padding: 0 16px; }
.ffa-mt-empty { padding: 8px 16px; }
/* The whole row is the link, so there is no second target to miss. Two
   classes, because `.ffa-group a` above is one class and one type — the
   same arithmetic .ffa-ai-docs .ffa-doc-main does.                     */
.ffa-group .ffa-mt-row, .ffa-group .ffa-mt-row:hover { color: var(--ink); text-decoration: none; }
.ffa-group .ffa-mt-row:hover { background: rgba(44, 36, 24, .045); }
.ffa-mt-day { flex: none; width: 44px; display: flex; flex-direction: column; align-items: center; line-height: 1; }
.ffa-mt-day-d { font-size: 11px; font-weight: 600; text-transform: uppercase; color: var(--terracotta); }
.ffa-mt-day-n { font-size: 22px; font-weight: 700; letter-spacing: -.02em; }
/* A meeting that has been held is greyed, not hidden: the archive is the
   point of the second group, and the colour is what says which is which. */
.ffa-mt-row--held .ffa-mt-day-d, .ffa-mt-row--held .ffa-mt-day-n { color: var(--color-text-tertiary); }
/* A column, not a bare box: .ffa-row-s's 2px top margin needs its line to
   be a block, and the two spans inside the row are spans because the row
   itself is an <a>.                                                    */
.ffa-mt-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* 5. The lines that say there is nothing to show, and where the record
      starts. Never a bare heading over an empty list (evidence gating). */
.ffa-mt-quiet { padding: 8px 0 0; }
.ffa-mt-foot { padding: 18px 0 0; font-size: 14px; line-height: 1.6; color: var(--color-text-tertiary); }
.ffa-mt-foot a { margin-left: 6px; }

/* ── The issues index ──────────────────────────────────
   src/issues-body.html — /issues (page.issues.php). Hero, then one section
   per non-empty group with the grounds alternating, then the dark ask band.

   The `ffa-ix-` namespace is the issues INDEX; `.ffa-issue*` above is the
   Home band's card and is a different screen. The retired `.issues-index*`
   block in style.css is the OLD index and is deleted with this slice.

   ONE ROW TEMPLATE, FOUR LAYOUTS. The view engine clones one section per
   group and one card per row, so a group cannot choose its own markup: the
   mockup's four shapes — the full-width lead card, the 2-up cards, the 3-up
   sand cards, the compact resolved list — are all attribute selectors on
   [data-key], which is the group's own key rendered into the clone. Layout
   by position and by key, never by a display flag in the loader
   (page/page.issues.php records the three decisions in full).             */

.ffa-ix-intro { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 22px; padding: 112px 0 80px; }
.ffa-ix-h { max-width: 900px; }
.ffa-ix-lead { max-width: 640px; }
.ffa-ix-empty { padding: 0 0 96px; text-align: center; }

/* House rule 3: the band change IS the section break. Every cloned section
   carries .ffa-sand and the ODD ones give it back, because the mockup opens
   on warm white and the view engine clones one template row — which ground a
   section lands on is a question about its position, not about its data.
   The shape /this-week's meeting sections had until its 2026-09-27 design pass. */
.ffa-ix-group { padding: 96px 0; }
.ffa-ix-groups > .ffa-ix-group:nth-child(odd) { background: transparent; }

.ffa-ix-inner { display: flex; flex-direction: column; gap: 28px; }
.ffa-ix-head { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; }
/* The group pill is a size up from the card chips it shares a class with. */
.ffa-ix-head .ffa-pill { font-size: 14px; }
/* The mockup's four group colours. They are the pills' own, not the status
   chip's: a group says where a reader stands with an issue, which is the
   question this page is sorted by.                                       */
.ffa-pill--open       { background: rgba(232, 201, 106, .35); color: #7C6420; }
.ffa-pill--deciding   { background: rgba(160, 203, 224, .35); color: #33607C; }
.ffa-pill--monitoring { background: rgba(164, 196, 150, .35); color: #4A6B3F; }
.ffa-pill--resolved   { background: var(--navy-soft); color: var(--navy); }

/* 2-up is the default because "being decided" is the group the mockup draws
   that way; open inherits it for its second and later cards, and the two
   groups that differ say so.                                             */
.ffa-ix-cards { display: grid; gap: 24px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ffa-ix-group[data-key="monitoring"] .ffa-ix-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ffa-ix-group[data-key="resolved"] .ffa-ix-cards { grid-template-columns: minmax(0, 1fr); gap: 0; }

/* The card is the whole link, so it must not take the link colour or the
   hover underline from the base rule at the top of this file — which is one
   class and one type, so two classes here is what it takes to outrank it. */
.ffa-ix-card { padding: 0; overflow: hidden; gap: 0; }
.ffa-ix-cards .ffa-ix-card, .ffa-ix-cards .ffa-ix-card:hover { color: var(--ink); text-decoration: none; }
.ffa-ix-media { display: block; }
.ffa-ix-img { display: block; width: 100%; height: 300px; object-fit: cover; }
.ffa-ix-ph { height: 300px; border: 0; border-radius: 0; }
.ffa-ix-body { display: flex; flex-direction: column; gap: 10px; padding: 32px 36px 36px; }
.ffa-ix-title { font-size: 30px; font-weight: 700; letter-spacing: -.025em; line-height: 1.1; }
.ffa-ix-draft { align-self: flex-start; }
.ffa-ix-line { font-size: 17px; }
.ffa-ix-status { font-size: 15px; font-weight: 600; color: var(--navy); }
/* An open window is the one thing on this page with a clock on it, so its
   line is the terracotta the mockup gives it and not the navy of a date
   somebody else is keeping.                                              */
.ffa-ix-group[data-key="open"] .ffa-ix-status { color: var(--terracotta); }

/* THE LEAD CARD — src/issues-body.html:18-27. The first card of the first
   section, 560px of picture beside its text, which is the loader's `lead`:
   "the first open issue, else the first being decided" is the first row of
   the first section, because an empty group renders no section and open
   sorts before deciding. Scoped to those two keys so a page whose first
   section is Monitoring does not blow a watching item up to full width.  */
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child,
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 560px minmax(0, 1fr);
  align-items: stretch;
}
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child .ffa-ix-img,
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child .ffa-ix-img { height: 100%; min-height: 380px; }
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child .ffa-ix-ph,
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child .ffa-ix-ph { height: 100%; min-height: 380px; }
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child .ffa-ix-body,
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child .ffa-ix-body { padding: 44px 48px; justify-content: center; gap: 14px; }
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child .ffa-ix-title,
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child .ffa-ix-title { font-size: 36px; }
/* "Read the guide ›" belongs to the lead card alone — on a 2-up card the
   sentence would be three words under three more, and the whole card is
   already the link. The chevron is CSS here for the same reason it is on
   .ffa-links a: a string that carries its own arrow prints two.          */
.ffa-ix-more { display: none; font-size: 17px; font-weight: 500; color: var(--accent); }
.ffa-ix-more::after { content: " \203A"; }
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child .ffa-ix-more,
.ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child .ffa-ix-more { display: block; }

/* Monitoring — src/issues-body.html:56-60: three sand cards with no shadow
   and no picture, because there is no clock on them. On a sand ground they
   invert to white, which is the same law the meeting sections follow: the
   card is always the other colour from what it sits on.                  */
.ffa-ix-group[data-key="monitoring"] .ffa-ix-media,
.ffa-ix-group[data-key="monitoring"] .ffa-ix-ph { display: none; }
.ffa-ix-group[data-key="monitoring"] .ffa-ix-body { padding: 32px 34px; }
.ffa-ix-group[data-key="monitoring"] .ffa-ix-title { font-size: 24px; letter-spacing: -.02em; line-height: 1.15; }
.ffa-ix-group[data-key="monitoring"] .ffa-ix-line { font-size: 16px; }
.ffa-ix-groups > .ffa-ix-group:nth-child(odd)[data-key="monitoring"] .ffa-ix-card { background: var(--sand); box-shadow: none; }

/* Resolved — no artboard draws it, because the mockup's page has nothing
   resolved on it. A settled issue is still worth finding, and it is worth
   less room than one a reader can still change: the compact list is the
   grouped-list vocabulary's row, one per line, no picture.               */
.ffa-ix-group[data-key="resolved"] .ffa-ix-card { background: transparent; box-shadow: none; border-radius: 0; border-top: 1px solid rgba(44, 36, 24, .12); }
.ffa-ix-group[data-key="resolved"] .ffa-ix-media,
.ffa-ix-group[data-key="resolved"] .ffa-ix-ph { display: none; }
.ffa-ix-group[data-key="resolved"] .ffa-ix-body { padding: 18px 2px; gap: 4px; }
.ffa-ix-group[data-key="resolved"] .ffa-ix-title { font-size: 20px; letter-spacing: -.015em; }
.ffa-ix-group[data-key="resolved"] .ffa-ix-line { font-size: 15px; }

/* The ask band — src/issues-body.html:65-72. */
.ffa-ix-ask { padding: 120px 0; }
.ffa-ix-ask-inner { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 22px; }
.ffa-ix-ask-lead { max-width: 600px; }
/* The one black-on-sand pill this page spends (house rule 5). It is an <a>
   on the dark ground, so it restates its colour over `.ffa-dark a`, which
   is one class and would otherwise leave sky blue on sand.               */
.ffa-pill--ask, .ffa-dark .ffa-pill--ask, .ffa-dark .ffa-pill--ask:hover { background: var(--sand); color: var(--ffa-ink-dark); font-size: 16px; padding: 14px 24px; text-decoration: none; }

/* ── The issue guide ──────────────────────────────────
   src/issue-body.html — /issue/{slug} (page.issue-v3.php). Dark opener with
   a full-bleed photograph, one number per viewport, the sand "where it
   stands" section with the stage rail, the compare rows, the dark "who
   decides" band with the take-part card, the record, the shelf.

   The `ffa-ig-` namespace is the issue GUIDE; `ffa-ix-` above is the issues
   INDEX and `.ffa-issue*` is the Home band's card — three screens about the
   same rows and three sets of rules on purpose. The retired `.iv3-*` block
   in style.css is this page's old dress and is deleted with this slice; the
   `.iv2-*` block STAYS, because page.issue-std.php still renders it (owner
   ruling 2026-07-28) and page.about.php still reuses its form atoms.

   SIX NAMES IN THIS BLOCK ARE NOT PREFIXED ffa-ig-, because they are the
   slice's own vocabulary rather than this page's furniture and the plan
   names them: .ffa-stage-rail, .ffa-stage, .ffa-stage.is-now,
   .ffa-compare-row, .ffa-updates-row and .ffa-issue-lead-card.          */

/* Every module zone collapses when its module did not render, so a heading
   never survives above nothing (the evidence-gating law). :empty reaches
   these divs because js/page.js leaves them empty until FFModules fills
   them.
   A `band` is a section that is NOTHING BUT one module zone — intro,
   levers, main, outcomes. Its rhythm is carried by the zone and not by the
   section, so a zone that did not render takes its own padding away with
   it and the two bands either side of it do not leave 192px of nothing
   between them. The alternative is :has() on the section, which would be
   one selector instead of two but is newer than this stylesheet's floor. */
.ffa-ig-zone:empty { display: none; }
.ffa-ig-band > .ffa-wrap > .ffa-ig-zone { padding: 96px 0; }

/* THE QUESTION SPINE, in the vocabulary's voice. js/issue-modules.js emits
   <h2 class="issue-question"> into every zone it fills, and css/style.css
   dresses that class in the serif the old guide used. Inside the Apple-way
   guide the questions are the page's own section headings and take .ffa-h3's
   type. SCOPED TO .ffa-ig, which is this page's wrapper: page.issue-std.php
   renders the same module output and must keep the serif it was built for.
   Two classes, so it outranks style.css's one-class rule whichever file the
   header loads first.                                                    */
.ffa-ig .issue-question { font-family: inherit; font-size: 40px; line-height: 1.08; letter-spacing: -.03em; font-weight: 700; color: var(--ink); margin: 0 0 24px; }
.ffa-dark .issue-question { color: var(--sand); }

/* Anchored jumps land clear of the fixed nav — the opener's two links, and
   any link a module writes to the record.                                */
.ffa-ig-stands, .ffa-ig-action, .ffa-ig-record { scroll-margin-top: calc(var(--nav-h) + 16px); }

/* 1. The dark opener — src/issue-body.html:12-24. */
.ffa-ig-open { padding: 120px 0 0; }
.ffa-ig-open-inner { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 22px; padding-bottom: 72px; }
.ffa-ig-h { max-width: 980px; }
.ffa-ig-lead { max-width: 680px; }
.ffa-ig-links { justify-content: center; }
/* The picture's height. Since the 2026-09-26 header pass it sits in the wide
   column as a rounded card ("Header pass" below), no longer full-bleed. */
.ffa-ig-hero-img { width: 100%; height: 760px; object-fit: cover; }
.ffa-ig-hero-cap { margin: 0; padding: 14px 4px 0; font-size: 14px; line-height: 1.45; color: #B9AF9E; }
.ffa-ig-hero-ph { height: 760px; border: 0; border-radius: 0; background: var(--ffa-card-dark); border-color: #4A443B; color: #B9AF9E; }
.ffa-ig-hero-ph .ffa-ph-tag { background: var(--ffa-ink-dark); color: #B9AF9E; }

/* 3. One number per viewport — src/issue-body.html:26-33. House rule 2, and
      the one place on the site where .ffa-stat goes past its 120px: the
      artboard sets this number at 200, because it is the whole section.  */
.ffa-ig-number { padding: 160px 0 140px; }
.ffa-ig-number-inner { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 20px; }
.ffa-ig-stat { font-size: 200px; }
.ffa-ig-stat-l { max-width: 760px; }
.ffa-ig-stat-sub { max-width: 600px; margin-top: 8px; }

/* The strip sentence, between the number and the section it belongs to. */
.ffa-ig-strip-band { padding: 0 0 48px; }
.ffa-ig-strip .issue-strip-line { font-size: 22px; line-height: 1.4; color: var(--ink-soft); max-width: 720px; }

/* 4. Where it stands — src/issue-body.html:35-70, on sand. */
.ffa-ig-stands { padding: 120px 0; }
.ffa-ig-stands-inner { display: flex; flex-direction: column; gap: 56px; }
.ffa-ig-stands-head { display: flex; flex-direction: column; gap: 18px; max-width: 720px; }
.ffa-ig-clock { display: flex; flex-direction: column; gap: 8px; margin-top: -24px; }
.ffa-ig-clock-next { font-weight: 600; color: var(--ink); }
.ffa-ig-clock-date { font-size: 32px; font-weight: 700; letter-spacing: -.025em; line-height: 1.1; }

/* THE STAGE RAIL. One column per step of THIS shape's ladder, never five:
   --steps is the loader's stage_count, rendered into the style attribute,
   and the fallback is the four steps a `case` has so the rail is never a
   single column if the key ever goes missing. The bar above each step is
   the state, said in colour; the caption under it says it in words, so the
   rail is not colour-only.                                              */
.ffa-stage-rail { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(var(--steps, 4), minmax(0, 1fr)); gap: 12px; }
.ffa-stage { display: flex; flex-direction: column; gap: 14px; }
.ffa-stage-bar { height: 6px; border-radius: 999px; background: var(--sand-dark); }
.ffa-stage-step { font-size: 13px; font-weight: 600; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: .08em; }
.ffa-stage-name { font-size: 20px; font-weight: 700; letter-spacing: -.015em; color: var(--color-text-tertiary); }
.ffa-stage-note { font-size: 15px; color: var(--ink-soft); line-height: 1.4; }
/* A step already taken: the bar is the accent and the name comes back to
   full ink, because it is a fact about the record.                      */
.ffa-stage.is-done .ffa-stage-bar { background: var(--accent); }
.ffa-stage.is-done .ffa-stage-name { color: var(--ink); }
/* The step the issue is AT — the one thing on this page a reader can act
   on, so it takes the terracotta the mockup gives it.                   */
.ffa-stage.is-now .ffa-stage-bar { background: var(--terracotta); }
.ffa-stage.is-now .ffa-stage-step { color: var(--terracotta); }
.ffa-stage.is-now .ffa-stage-name { color: var(--ink); }

/* The guardrail note: its own full-width block, never folded into another. */
.ffa-ig-guardrail { padding: 72px 0 0; }
.ffa-ig-guardrail-inner { display: flex; flex-direction: column; gap: 10px; max-width: 720px; }

/* 6. What the numbers say — src/issue-body.html:72-88. The compare rows are
      a two-column list with a rule under each, which is the mockup's table
      without a table: one row is one <div>, cloned per panel_facts entry. */
.ffa-ig-numbers { padding: 140px 0; }
.ffa-ig-numbers-inner { display: flex; flex-direction: column; gap: 22px; }
.ffa-ig-compare { display: flex; flex-direction: column; margin-top: 12px; border-top: 1px solid rgba(44, 36, 24, .12); max-width: 720px; }
.ffa-compare-row { display: flex; justify-content: space-between; align-items: baseline; gap: 24px; padding: 18px 0; border-bottom: 1px solid rgba(44, 36, 24, .12); }
.ffa-compare-l { font-size: 17px; }
.ffa-compare-v { font-size: 26px; font-weight: 700; letter-spacing: -.02em; text-align: right; }

/* 7. Who decides, and the take-part card — src/issue-body.html:90-104. */
.ffa-ig-decide { padding: 120px 0; }
.ffa-ig-decide-grid { gap: 64px; align-items: start; }
.ffa-ig-decide-copy { display: flex; flex-direction: column; gap: 22px; }
.ffa-ig-who { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.ffa-ig-who-row { display: flex; flex-direction: column; gap: 4px; }
.ffa-ig-who-l { font-size: 18px; font-weight: 700; letter-spacing: -.015em; color: var(--sand); }
.ffa-dark .ffa-ig-who-d { font-size: 17px; }
/* THE TAKE-PART CARD. .ffa-card gives it the dark-ground card background;
   this adds the numbered discs and the pill at its foot.                */
.ffa-issue-lead-card { gap: 24px; }
.ffa-issue-lead-h { font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; color: var(--sand); }
.ffa-ig-steps { display: flex; flex-direction: column; gap: 16px; }
.ffa-ig-step { display: flex; gap: 16px; align-items: flex-start; }
/* flex: none, which the artboard can leave out and a page cannot: a 32px
   flex item still shrinks, and a shrunken disc unaligns the three rows. */
.ffa-ig-step-n { flex: none; width: 32px; height: 32px; border-radius: 999px; background: var(--accent); color: var(--warmwhite); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 15px; }
.ffa-dark .ffa-ig-step-t { font-size: 17px; }
/* The one black-on-sand pill this page spends (house rule 5). */
.ffa-pill--take { background: var(--sand); color: var(--ffa-ink-dark); font-size: 15px; padding: 12px 22px; align-self: flex-start; line-height: 1.35; }

/* 8. Take part — the prose, the tiers, the follow form, the doors. Not in
      the mockup, which draws a guide and not a form; these are the page's
      live controls and they take the vocabulary's type, not its own.    */
.ffa-ig-action { padding: 120px 0; }
.ffa-ig-action-inner { display: flex; flex-direction: column; gap: 20px; max-width: 720px; }
.ffa-ig-primary a { font-weight: 600; }
.ffa-ig-sub { font-size: 19px; font-weight: 700; letter-spacing: -.015em; }
.ffa-ig-note { font-size: 16px; color: var(--ink-soft); line-height: 1.5; }
.ffa-ig-follow, .ffa-ig-acc { padding-top: 24px; border-top: 1px solid rgba(44, 36, 24, .12); display: flex; flex-direction: column; gap: 8px; }
.ffa-ig-field-row { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 8px; }
.ffa-ig-field-row input[type="email"] { flex: 1 1 14rem; min-width: 0; }
/* Tier 1 IS the follow form: js/callbacks.js MOVES it into the action_box's
   own slot, where its heading and its note would say what the tier's cost
   and label already say. Standalone (no tiers) it keeps both.           */
.ffa-ig-follow--embedded { padding-top: 0; border-top: 0; gap: 0; }
.ffa-ig-follow--embedded .ffa-ig-sub, .ffa-ig-follow--embedded .ffa-ig-note { display: none; }
.ffa-ig-follow--embedded .ffa-ig-field-row { margin-top: 0; }
.ffa-ig-follow--embedded .ffa-ig-field-row input[type="email"] { flex: 1 1 9rem; }
.ffa-ig-action input[type="email"], .ffa-ig-action input[type="text"], .ffa-ig-action textarea, .ffa-ig-action select {
  font-family: inherit; font-size: 16px; color: var(--ink); background: #FFFFFF;
  border: 1px solid rgba(44, 36, 24, .18); border-radius: 12px; padding: 11px 14px; width: 100%; box-sizing: border-box;
}
.ffa-ig-action button[type="submit"] { font-family: inherit; font-size: 15px; font-weight: 600; cursor: pointer; border: 0; border-radius: 999px; padding: 12px 22px; background: var(--ink); color: var(--warmwhite); }
.ffa-ig-action button[type="submit"]:disabled { opacity: .55; cursor: default; }
.ffa-ig-label { display: block; margin-top: 12px; font-size: 14px; font-weight: 600; color: var(--ink-soft); }
.ffa-ig-label input, .ffa-ig-label textarea, .ffa-ig-label select { margin-top: 5px; font-weight: 400; }
/* Off-screen, not display:none — a hidden honeypot a bot cannot see is a
   honeypot a bot does not fill in.                                      */
.ffa-ig-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.ffa-ig-form-msg:empty { display: none; }
.ffa-ig-form-msg { margin-top: 10px; font-size: 15px; font-weight: 600; }
.ffa-ig-form-msg.is-ok { color: #46603C; }
.ffa-ig-form-msg.is-error { color: var(--brick); }
/* The disclosure triangles. One marker rule for all four, the way the
   retired block had it: a summary that draws its own marker and the
   browser's as well prints two.                                         */
.ffa-ig-ask-summary, .ffa-ig-door-label, .ffa-ig-deeper-summary, .ffa-ig-more summary { cursor: pointer; list-style: none; font-weight: 600; }
.ffa-ig-ask-summary::-webkit-details-marker, .ffa-ig-door-label::-webkit-details-marker,
.ffa-ig-deeper-summary::-webkit-details-marker, .ffa-ig-more summary::-webkit-details-marker { display: none; }
.ffa-ig-ask-summary::before, .ffa-ig-door-label::before,
.ffa-ig-deeper-summary::before, .ffa-ig-more summary::before { content: '\25B8\00A0'; color: var(--accent); }
.ffa-ig-ask[open] > .ffa-ig-ask-summary::before, .ffa-ig-door[open] > .ffa-ig-door-label::before,
.ffa-ig-deeper[open] > .ffa-ig-deeper-summary::before, .ffa-ig-more[open] > summary::before { content: '\25BE\00A0'; }
.ffa-ig-doors { display: flex; flex-direction: column; }
.ffa-ig-door { padding: 12px 0; border-bottom: 1px solid rgba(44, 36, 24, .10); }
.ffa-ig-door-label { font-size: 17px; }
.ffa-ig-door-q { margin: 8px 0 0 28px; font-size: 17px; font-style: italic; color: var(--ink-soft); }
.ffa-ig-door-take { margin: 12px 0 0 28px; font-size: 16px; line-height: 1.5; }
.ffa-ig-door-link { display: inline-block; margin: 8px 0 12px 28px; font-size: 15px; font-weight: 600; }
.ffa-ig-ask { margin-top: 14px; }
.ffa-ig-ask-form { margin-top: 10px; }
.ffa-ig-ask-form button[type="submit"] { margin-top: 16px; align-self: flex-start; }

/* 11. Updates — src/issue-body.html:106-114. A 180px date column and a
       line. The toggle comes BEFORE the list in source order so a pure-CSS
       nth-child reveal can reach the hidden rows; `order` puts it back
       under the list, which is where a reader expects it.                */
.ffa-ig-record { padding: 120px 0; }
.ffa-ig-record-inner { display: flex; flex-direction: column; gap: 40px; }
.ffa-ig-record-h { order: 0; }
.ffa-ig-updates { order: 2; display: flex; flex-direction: column; border-top: 1px solid rgba(44, 36, 24, .12); }
.ffa-ig-more { order: 3; margin-top: -24px; font-size: 15px; }
.ffa-ig-feed { order: 4; display: flex; flex-direction: column; gap: 14px; }
.ffa-updates-row { display: grid; grid-template-columns: 180px minmax(0, 1fr); column-gap: 24px; row-gap: 6px; padding: 24px 0; border-bottom: 1px solid rgba(44, 36, 24, .12); }
.ffa-updates-date { font-size: 15px; color: var(--color-text-tertiary); }
.ffa-updates-body { grid-column: 2; }
.ffa-updates-link { grid-column: 2; font-size: 15px; font-weight: 600; }
.ffa-updates-link:empty { display: none; }
/* Three rows, then the rest behind the toggle. */
.ffa-ig-updates .ffa-updates-row:nth-child(n+4) { display: none; }
.ffa-ig-more[open] ~ .ffa-ig-updates .ffa-updates-row:nth-child(n+4) { display: grid; }
.ffa-ig-feed-list { list-style: none; margin: 0; padding: 0; }
.ffa-ig-feed-row { padding: 12px 0; border-top: 1px solid rgba(44, 36, 24, .12); font-size: 16px; }
.ffa-ig-feed-row a { text-decoration: none; }
.ffa-ig-feed-day { font-weight: 700; color: var(--accent); margin-right: 8px; }

/* 12. The shelf, and the doctrine line every guide ends on. */
.ffa-ig-deeper-band { padding: 0 0 96px; }
.ffa-ig-deeper { border-top: 1px solid rgba(44, 36, 24, .12); padding-top: 24px; }
.ffa-ig-deeper-summary { font-size: 17px; }
.ffa-ig-shelf { margin-top: 24px; display: flex; flex-direction: column; gap: 10px; }
.ffa-ig-source-group + .ffa-ig-source-group { margin-top: 18px; }
.ffa-ig-source-group-head { font-size: 15px; font-weight: 700; }
.ffa-ig-source-count { font-weight: 400; color: var(--color-text-tertiary); }
.ffa-ig-source-count::before { content: '('; }
.ffa-ig-source-count::after { content: ')'; }
.ffa-ig-sources, .ffa-ig-stories { list-style: none; margin: 0; padding: 0; }
.ffa-ig-source, .ffa-ig-story { padding: 5px 0; font-size: 16px; }
.ffa-ig-metrics { display: flex; flex-wrap: wrap; gap: 8px; }
.ffa-ig-metric { border: 1px solid rgba(44, 36, 24, .18); border-radius: 999px; padding: 6px 14px; font-size: 14px; font-weight: 600; text-decoration: none; }
.ffa-ig-disclaimer { margin-top: 24px; font-size: 14px; color: var(--color-text-tertiary); line-height: 1.6; }
.ffa-ig-doctrine { padding: 0 0 96px; font-size: 15px; line-height: 1.6; color: var(--ink-soft); max-width: 720px; }
.ffa-ig-doctrine a { margin-left: 8px; font-weight: 600; white-space: nowrap; }

/* ── Issue guide refresh (2026-09-24, Meta data center) ─────────────────
   Five blocks. A and C–E are scoped to .ffa-ig so page.issue-std.php (v2,
   which the same modules also render into) keeps css/style.css's dress
   untouched; B's .path-* names belong to approval_path alone, which only
   the v3 template has a zone for.
   The vocabulary is the neighborhood page's: white cards on sand with the
   28px radius, a 13px uppercase caption over a value, and one terracotta
   mark for the one thing still open. Reference: the owner's loose mockup
   of 2026-09-24 (thread attachment), read against the Apple-way rules —
   one idea per section, alternating grounds.                          */

/* A. Where it stands — the clock becomes the mockup's card on the right of
      the heading; the rail spans both columns under them. The column is
      auto-width so an issue with no clock keeps a full-width heading.   */
.ffa-ig-stands-inner { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 48px; row-gap: 48px; align-items: start; }
.ffa-ig-stands-inner > .ffa-stage-rail { grid-column: 1 / -1; }
.ffa-ig-clock { margin-top: 0; background: #FFFFFF; border-radius: 22px; padding: 24px 28px; min-width: 260px; max-width: 340px; box-shadow: 0 2px 14px rgba(44,36,24,.06); }

/* B. When can the public weigh in? — the approval_path module. The early
      callout is a dark card beside a ruled timeline; each stage is a date
      column, a dot on a line, and a body. The dot's fill says whether the
      public had a say (sage = yes, ochre = limited, hollow = no), and the
      words in the "Public say" row say it again, so colour is never the
      only signal. An open stage takes the terracotta rail mark.         */
.ffa-ig-path { background: var(--sand); }
.path-intro { font-size: 19px; line-height: 1.5; color: var(--ink-soft); max-width: 720px; margin: -8px 0 40px; }
.path-grid { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 48px; align-items: start; }
.path-early { position: sticky; top: calc(var(--nav-h, 64px) + 24px); background: var(--ffa-ink-dark); color: var(--sand); border-radius: var(--ffa-radius-card); padding: 32px 28px; display: flex; flex-direction: column; gap: 12px; }
.path-early-n { font-size: clamp(48px, 6vw, 64px); white-space: nowrap; font-weight: 700; letter-spacing: -.045em; line-height: .95; }
.path-early-l { font-size: 19px; font-weight: 700; line-height: 1.3; letter-spacing: -.01em; }
.path-early-note { font-size: 16px; line-height: 1.5; color: #D9D1C3; }
.path-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.path-stage { position: relative; display: grid; grid-template-columns: 120px 24px minmax(0, 1fr); column-gap: 16px; padding-bottom: 16px; }
/* The line: drawn per stage from its dot down, so the last stage ends on
   its own dot and never trails a line into nothing.                    */
.path-stage::before { content: ''; position: absolute; left: calc(120px + 16px + 11px); top: 22px; bottom: -24px; width: 2px; background: var(--sand-dark); }
.path-stage:last-child::before { display: none; }
.path-date { font-size: 14px; font-weight: 600; color: var(--ink-soft); padding-top: 18px; text-align: right; }
.path-dot { width: 16px; height: 16px; margin: 20px 0 0 4px; border-radius: 999px; background: #FFFFFF; border: 2px solid var(--color-text-tertiary); box-sizing: border-box; position: relative; z-index: 1; }
.path-say--yes .path-dot { background: var(--sage); border-color: var(--sage); }
.path-say--limited .path-dot { background: var(--ochre-light); border-color: var(--ochre); }
.path-body { background: #FFFFFF; border-radius: 22px; padding: 16px 22px; display: flex; flex-direction: column; gap: 6px; box-shadow: 0 2px 14px rgba(44,36,24,.05); }
.path-stage--open .path-body { box-shadow: inset 4px 0 0 var(--terracotta), 0 2px 14px rgba(44,36,24,.05); }
.path-top { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.path-title { font-size: 19px; font-weight: 700; letter-spacing: -.015em; line-height: 1.25; margin: 0; }
.path-state { flex: none; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-soft); }
.path-stage--open .path-state { color: #9E4A33; }   /* terracotta darkened to 5.6:1 on white; the stock one is 4.0:1 */
.path-desc { font-size: 16px; line-height: 1.5; color: var(--ink); margin: 0; }
.path-slot { margin: 0; font-size: 15px; line-height: 1.45; display: grid; grid-template-columns: 120px minmax(0, 1fr); gap: 12px; }
.path-k { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-soft); padding-top: 2px; }
.path-v { color: var(--ink-soft); }
.path-say--yes .path-slot--say .path-v { color: #46603C; }
.path-say--no .path-slot--say .path-v { color: var(--ink-soft); }
.path-links { display: flex; flex-wrap: wrap; gap: 6px 20px; margin: 2px 0 0; font-size: 14px; font-weight: 600; }
.path-how { color: #9E4A33; }
.path-note { font-size: 15px; line-height: 1.55; color: var(--ink-soft); max-width: 720px; margin-top: 16px; }

/* C. What is still being decided? — the open_decisions cards as the
      mockup's white cards, with Who / When / Can you speak as a caption
      column beside each value instead of a bold run-in.               */
.ffa-ig .od-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }
.ffa-ig .od-card { background: #FFFFFF; border: 0; border-radius: var(--ffa-radius-card); padding: 32px; box-shadow: 0 2px 14px rgba(44,36,24,.06); display: flex; flex-direction: column; gap: 10px; }
.ffa-ig .od-title { font-size: 24px; letter-spacing: -.02em; margin: 0; }
.ffa-ig .od-what { font-size: 17px; margin: 0 0 6px; }
.ffa-ig .od-slot { display: grid; grid-template-columns: 128px minmax(0, 1fr); gap: 12px; margin: 0; padding: 12px 0 0; border-top: 1px solid rgba(44, 36, 24, .10); font-size: 16px; }
.ffa-ig .od-k { font-size: 12px; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-soft); padding-top: 3px; }
.ffa-ig .od-k::after { content: ''; }
.ffa-ig .od-slot--say .od-v { color: #46603C; font-weight: 600; }
.ffa-ig .od-help { margin-top: 24px; font-size: 16px; }

/* D. The facts grid — v3 never dressed stat_grid (its rules in style.css
      are scoped to v1's .issue-guide), so five cards squeezed into one
      row of bare text. Here they are the neighborhood page's "The
      numbers." cards: white, 28px radius, the number at 44px, the note
      and its source under a rule.                                      */
.ffa-ig .stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 20px; }
.ffa-ig .stat-card { background: #FFFFFF; border-radius: var(--ffa-radius-card); padding: 28px; box-shadow: 0 2px 14px rgba(44,36,24,.06); display: flex; flex-direction: column; gap: 8px; }
.ffa-ig .stat-icon { color: var(--accent); font-size: 26px; line-height: 1; }
.ffa-ig .stat-number { font-size: 44px; font-weight: 700; letter-spacing: -.035em; line-height: 1; color: var(--ink); overflow-wrap: anywhere; }
.ffa-ig .stat-label { font-size: 17px; font-weight: 700; line-height: 1.3; }
.ffa-ig .stat-sub { font-size: 15px; color: var(--ink-soft); }
.ffa-ig .stat-note { font-size: 15px; line-height: 1.5; color: var(--ink-soft); }
.ffa-ig .stat-attribution { margin-top: auto; padding-top: 12px; border-top: 1px solid rgba(44, 36, 24, .10); font-size: 13px; line-height: 1.45; color: var(--color-text-tertiary); }
.ffa-ig .stat-attribution a { color: var(--color-text-tertiary); text-decoration: underline; }
.ffa-ig-numbers { background: var(--sand); }

/* E. The water meter. Its fill is var(--issue-accent), which css/style.css
      defines only inside the v1 and v2 wrappers — so on v3 the fill was
      transparent and the 480,000 bar never showed, only the 2.5 million
      track. The variable is defined here for the v3 wrapper too (same value
      as --accent), and the meter sits in the same white card as the grid. */
.ffa-ig { --issue-accent: var(--accent); }
.ffa-ig .ff-meter { background: #FFFFFF; border-radius: var(--ffa-radius-card); padding: 28px; box-shadow: 0 2px 14px rgba(44,36,24,.06); margin: 20px 0 0; }
.ffa-ig .meter-head { font-size: 19px; font-weight: 700; letter-spacing: -.015em; margin: 0 0 16px; }
.ffa-ig .meter-track { height: 28px; border-radius: 0 8px 8px 0; }
.ffa-ig .meter-fill { border-radius: 0 8px 8px 0; }
.ffa-ig .meter-note { font-size: 15px; line-height: 1.5; color: var(--ink-soft); margin-top: 14px; }

/* ── Issue guide, the owner's mockups (2026-09-25) ────────────────────────
   Seven mockups from the owner, read under his five rules: current copy
   wins over the mockup's wording; icons neutral where colour carries no
   meaning; each section keeps its own ground so no two neighbours share
   one; real logos for public bodies; patterns that don't make sense are
   fixed, not copied. Every rule is scoped to .ffa-ig (page.issue-std.php,
   v2, renders the same modules and keeps style.css's dress) except the
   .path-* names, which only this template has a zone for.
   The grounds, top to bottom: dark opener · white number · sand "where it
   stands" · white guardrail · sand timeline · white decisions · sand
   numbers · dark who-decides · white take part · sand hearing · white
   updates.
   Its phone and tablet rules sit in the file's one 900px and one 600px
   blocks, under the same heading; nine suites cut the file on them.    */

/* The shared icon disc: a neutral glyph on a sand circle. Colour is kept
   for the places where it means something (the public-say icon, which
   repeats the dot beside it). */
.ffa-ig .ui-icon, .ffa-ig-icon { flex: none; display: inline-flex; align-items: center; justify-content: center; color: var(--ink-soft); line-height: 1; }
.ffa-ig-icon { width: 48px; height: 48px; border-radius: 999px; background: var(--sand); font-size: 20px; }

/* 1. The opener. No photograph on file: the 760px "Photo" block said
      nothing, so it is no longer drawn. An issue with a photograph keeps
      it full-bleed exactly as before; the choice of photo stays the
      owner's. A rendering is never shown as the site: it carries a
      caption that says it is a drawing, printed under it here and on the
      Home card (.ffa-hm-credit). */
.ffa-ig-hero-ph { display: none; }

/* 3. The number, set left in a reading column as the mockup draws it. */
.ffa-ig-number { padding: 120px 0 72px; }
.ffa-ig-number-inner { align-items: flex-start; text-align: left; max-width: 760px; margin: 0 auto; gap: 14px; }
.ffa-ig-stat { font-size: 168px; line-height: .9; letter-spacing: -.05em; }
.ffa-ig-stat-l { font-size: 34px; font-weight: 700; letter-spacing: -.025em; color: var(--ink); }
.ffa-ig-stat-sub { margin-top: 0; }
/* The strip: one line with its calendar, centred under the number. */
.ffa-ig-strip-band { padding: 0 0 96px; }
.ffa-ig-strip .issue-strip-line { display: flex; align-items: center; gap: 14px; max-width: 760px; margin: 0 auto; font-size: 20px; color: var(--ink); }
.ffa-ig .issue-strip-icon { font-size: 24px; }

/* 4. Where it stands. The clock is a white card with its calendar disc;
      the rail becomes the mockup's line of nodes — a filled accent disc
      with a check for a step taken, a terracotta ring for the step the
      issue is at — with the step and its name centred under each node.
      The caption under every node still says the state in words.       */
.ffa-ig-clock { flex-direction: row; gap: 18px; align-items: flex-start; }
.ffa-ig-clock .ffa-ig-icon { background: var(--sand); }
.ffa-ig-clock-text { display: flex; flex-direction: column; gap: 6px; }
.ffa-ig .ffa-stage-rail { gap: 0; }
.ffa-ig .ffa-stage { align-items: center; text-align: center; gap: 10px; position: relative; }
.ffa-ig .ffa-stage .ffa-stage-bar, .ffa-ig .ffa-stage.is-done .ffa-stage-bar, .ffa-ig .ffa-stage.is-now .ffa-stage-bar { position: relative; width: 100%; height: 34px; background: none; border-radius: 0; }
/* The line between nodes: from this node's centre to the next one's. */
.ffa-ig .ffa-stage-bar::before { content: ''; position: absolute; left: 50%; right: -50%; top: 50%; height: 4px; margin-top: -2px; border-radius: 999px; background: var(--sand-dark); }
.ffa-ig .ffa-stage:last-child .ffa-stage-bar::before { display: none; }
.ffa-ig .ffa-stage.is-done .ffa-stage-bar::before { background: var(--accent); }
/* Into the step we are at: solid to halfway, then the terracotta dots of a
   road not yet travelled. */
.ffa-ig .ffa-stage.is-done:has(+ .ffa-stage.is-now) .ffa-stage-bar::before { background: linear-gradient(90deg, var(--accent) 0 50%, transparent 50%), repeating-linear-gradient(90deg, var(--terracotta) 0 4px, transparent 4px 9px); }
/* The node. */
.ffa-ig .ffa-stage-bar::after { content: ''; position: absolute; left: 50%; top: 0; width: 34px; height: 34px; margin-left: -17px; border-radius: 999px; box-sizing: border-box; background: #FFFFFF; border: 3px solid var(--sand-dark); z-index: 1; }
.ffa-ig .ffa-stage.is-done .ffa-stage-bar::after { background: var(--accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='%23fff' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 16px no-repeat; border-color: var(--accent); }
.ffa-ig .ffa-stage.is-now .ffa-stage-bar::after { border-color: var(--terracotta); background: #FFFFFF; }
.ffa-ig .ffa-stage-name { font-size: 19px; }

/* The guardrail: its own card with an info disc. Since 2026-09-26 the
   section is .ffa-sand, the same ground as "Where it stands" above it, so
   the two read as one block (owner ask); the card turns white to stay a
   card, and the gap between them closes to the guardrail's own padding. */
.ffa-ig-guardrail { padding: 72px 0; }
.ffa-ig-guardrail-inner { flex-direction: row; gap: 24px; align-items: flex-start; max-width: 880px; margin: 0 auto; background: var(--sand); border-radius: var(--ffa-radius-card); padding: 32px 36px; }
.ffa-ig-guardrail .ffa-ig-icon { background: #FFFFFF; width: 56px; height: 56px; font-size: 24px; }
.ffa-ig-guardrail-text { display: flex; flex-direction: column; gap: 10px; }
.ffa-ig-guardrail .ffa-body { font-size: 17px; }
.ffa-ig-guardrail.ffa-sand .ffa-ig-guardrail-inner { background: #FFFFFF; }
.ffa-ig-guardrail.ffa-sand .ffa-ig-icon { background: var(--sand); }
.ffa-ig-stands:has(+ .ffa-ig-guardrail) { padding-bottom: 72px; }
.ffa-ig-stands + .ffa-ig-guardrail { padding-top: 0; }

/* 4b. The timeline. The why-early number is a light card now (the dark
       band is the who-decides section's; two dark blocks read as one),
       with the span it counts drawn under it, and the legend below it.
       Each stage card carries its number, the badge as a pill, who and
       public say side by side with their icons, and the links in their
       own column. */
.path-aside { display: flex; flex-direction: column; gap: 20px; }
/* The aside sticks only on a screen tall enough to show all of it. */
@media (min-height: 860px) { .path-aside { position: sticky; top: calc(var(--nav-h, 64px) + 24px); } }
/* No aside (no early card, no key): the list takes the full width. */
.path-grid > .path-list:first-child { grid-column: 1 / -1; }
.path-early { position: static; background: #FFFFFF; color: var(--ink); box-shadow: 0 2px 14px rgba(44,36,24,.06); }
.path-early-note { color: var(--ink-soft); }
.path-span { position: relative; display: flex; justify-content: space-between; gap: 12px; margin-top: 10px; padding: 18px 16px 14px; background: var(--sand); border-radius: 16px; }
.path-span-end { display: flex; flex-direction: column; gap: 2px; max-width: 42%; font-size: 13px; line-height: 1.3; color: var(--ink-soft); padding-top: 26px; position: relative; }
.path-span-end strong { font-size: 15px; color: var(--ink); }
.path-span-end::before { content: ''; position: absolute; top: 0; width: 14px; height: 14px; border-radius: 999px; background: var(--ink-soft); }
.path-span-end--from::before { left: 0; }
.path-span-end--to { text-align: right; align-items: flex-end; }
.path-span-end--to::before { right: 0; }
/* The line runs dot to dot across the top; the number sits on it. */
.path-span-bar { position: absolute; left: 30px; right: 30px; top: 24px; height: 2px; background: var(--ink-soft); }
.path-span-n { position: absolute; left: 50%; top: -10px; transform: translateX(-50%); padding: 0 8px; background: var(--sand); font-size: 15px; font-weight: 700; line-height: 20px; color: var(--ink); white-space: nowrap; }
.path-legend { background: #FFFFFF; border-radius: 22px; padding: 22px 24px; display: flex; flex-direction: column; gap: 12px; box-shadow: 0 2px 14px rgba(44,36,24,.05); }
.path-legend-h { font-size: 16px; font-weight: 700; color: var(--ink); }
.path-legend-row { display: flex; align-items: center; gap: 12px; font-size: 15px; line-height: 1.35; color: var(--ink-soft); }
.path-legend-dot { flex: none; width: 16px; height: 16px; border-radius: 999px; box-sizing: border-box; border: 2px solid var(--color-text-tertiary); background: #FFFFFF; }
.path-legend-row--yes .path-legend-dot { background: var(--sage); border-color: var(--sage); }
.path-legend-row--limited .path-legend-dot { background: var(--ochre-light); border-color: var(--ochre); }
.path-legend-row--open .path-legend-dot { width: 22px; height: 12px; border-radius: 4px; border: 0; background: #F6E3DC; box-shadow: inset 3px 0 0 var(--terracotta); }
/* "No" gets its own mark: the mockup's point that a step with no public
   comment period is different from one nobody has reached. */
.path-body { display: grid; grid-template-columns: 40px minmax(0, 1fr); column-gap: 18px; align-items: start; padding: 22px 24px; }
.path-n { width: 36px; height: 36px; border-radius: 999px; background: var(--sand); color: var(--ink); font-size: 16px; font-weight: 700; display: flex; align-items: center; justify-content: center; }
.path-main { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.path-state { padding: 5px 12px; border-radius: 999px; background: var(--sand); color: var(--ink-soft); letter-spacing: .06em; }
.path-stage--open .path-state { background: #F6E3DC; color: #9E4A33; }
.path-meta { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin-top: 6px; padding-top: 14px; border-top: 1px solid rgba(44, 36, 24, .08); }
.path-slot { display: flex; gap: 12px; align-items: flex-start; grid-template-columns: none; }
.path-slot .path-slot-icon { width: 34px; height: 34px; border-radius: 999px; background: var(--sand); font-size: 15px; }
.path-say--yes .path-slot--say .path-slot-icon { color: #46603C; background: #E7EEE2; }
.path-say--limited .path-slot--say .path-slot-icon { color: #7A5B12; background: #F7EDCF; }
.path-say--no .path-slot--say .path-slot-icon { color: var(--ink-soft); background: var(--sand); }
.path-kv { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.path-k { text-transform: none; letter-spacing: 0; font-size: 14px; color: var(--ink); padding: 0; }
.path-links { grid-column: 2; flex-direction: row; justify-content: flex-end; gap: 6px 22px; margin: 0; padding-top: 12px; }
.path-note { display: flex; gap: 14px; align-items: flex-start; max-width: none; margin-top: 28px; padding: 18px 22px; border-radius: 18px; background: rgba(44, 36, 24, .05); }
.path-note .path-note-icon { font-size: 18px; margin-top: 2px; }

/* 5. What is still being decided — on white now, so the cards take the
      sand edge instead of a shadow. Each caption row gets its neutral
      disc; the reference is a small panel with its arrow; the offer of
      help is a banner. */
.ffa-ig-levers { background: var(--warmwhite); }
.ffa-ig .od-card { border: 1px solid var(--sand-dark); box-shadow: none; padding: 36px; gap: 14px; }
.ffa-ig .od-slot { display: flex; gap: 16px; align-items: flex-start; padding: 16px 0 0; }
.ffa-ig .od-icon { width: 44px; height: 44px; border-radius: 999px; background: var(--sand); font-size: 18px; }
.ffa-ig .od-kv { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ffa-ig .od-k { padding-top: 0; }
.ffa-ig .od-slot--say .od-v { font-weight: 400; color: var(--ink); }
.ffa-ig .od-ref { display: flex; align-items: center; gap: 14px; margin-top: auto; padding: 14px 18px; border-radius: 16px; background: var(--sand); font-size: 15px; color: var(--ink-soft); }
.ffa-ig .od-ref a { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; }
.ffa-ig .od-ref-icon { font-size: 18px; }
.ffa-ig .od-ref-arrow { color: inherit; font-size: 13px; }
.ffa-ig .od-help { display: flex; align-items: center; gap: 16px; margin-top: 20px; padding: 18px 24px; border-radius: 20px; background: #EAF1F5; font-size: 17px; font-weight: 600; }
.ffa-ig .od-help-icon { width: 44px; height: 44px; border-radius: 999px; background: #FFFFFF; color: var(--accent); font-size: 18px; }

/* 6. What the numbers say. The three facts become three columns with a
      rule between them; the figure cards get their neutral disc and let
      a short last row stretch rather than leave a hole; the source line
      gets its document mark; the meter reads left to right. */
.ffa-ig .ffa-ig-compare { flex-direction: row; flex-wrap: wrap; border-top: 0; max-width: none; margin: 4px 0 24px; gap: 0; }
.ffa-ig .ffa-compare-row { flex: 1 1 220px; flex-direction: column; align-items: flex-start; justify-content: flex-start; gap: 6px; padding: 4px 28px 4px 0; margin-right: 28px; border-bottom: 0; border-right: 1px solid rgba(44, 36, 24, .12); }
.ffa-ig .ffa-compare-row:last-child { border-right: 0; margin-right: 0; }
.ffa-ig .ffa-compare-l { font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-soft); }
.ffa-ig .ffa-compare-v { font-size: 22px; text-align: left; line-height: 1.25; }
/* Five across at full width, as the mockup draws them. */
.ffa-ig .stat-grid { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 16px; }
.ffa-ig .stat-card { padding: 26px 22px; }
.ffa-ig .stat-number { font-size: 40px; }
.ffa-ig .stat-icon { width: 56px; height: 56px; border-radius: 999px; background: var(--sand); color: var(--ink-soft); font-size: 22px; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; }
.ffa-ig .stat-attribution { display: flex; gap: 10px; align-items: flex-start; }
.ffa-ig .stat-attribution-icon { font-size: 15px; margin-top: 1px; color: var(--color-text-tertiary); }
/* A second card group in the same numbers zone (the Meta page's "The money", 2026-09-30) opens its own
   section: room above its heading, after the meter card. Only a page with two grids in one zone matches. */
.ffa-ig .ffa-ig-zone > .issue-module--stat_grid ~ .issue-module--stat_grid { margin-top: 40px; }
.ffa-ig .ff-meter { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); grid-template-areas: "head actual" "note track" "note limit"; column-gap: 48px; row-gap: 10px; align-items: start; padding: 36px; }
.ffa-ig .ff-meter .meter-head { grid-area: head; font-size: 24px; letter-spacing: -.02em; text-transform: none; }
.ffa-ig .ff-meter .meter-note { grid-area: note; margin-top: 0; font-size: 17px; }
.ffa-ig .ff-meter .meter-actual { grid-area: actual; align-self: end; }
.ffa-ig .ff-meter .meter-track { grid-area: track; }
.ffa-ig .ff-meter .meter-limit { grid-area: limit; }

/* 7. Who decides. Each body is a row card with its mark in a white disc —
      the body's own logo where one is on file, the neutral building
      otherwise. No chevrons: the rows go nowhere, and an arrow that goes
      nowhere is a promise. The take-part steps are light cards. */
.ffa-ig-who { gap: 12px; }
.ffa-ig-who-row { flex-direction: row; align-items: center; gap: 20px; padding: 18px 22px; border-radius: 20px; background: var(--ffa-card-dark); }
.ffa-ig-who-mark { flex: none; width: 60px; height: 60px; border-radius: 999px; background: #FFFFFF; display: flex; align-items: center; justify-content: center; overflow: hidden; color: var(--ink-soft); font-size: 24px; }
.ffa-ig-who-logo { width: 48px; height: 48px; object-fit: contain; }
.ffa-ig-who-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
/* The row's two badges (owner, 2026-09-26): has the body decided, and can
   the public speak to it. The decision badge borrows the opener status
   card's marks — decided is the accent fill, still deciding the terracotta
   ring — and the public badge the path timeline's say colours (sage, ochre,
   none). Every badge says its state in words; the colour only repeats it.
   The terracotta text is lightened for contrast on the dark card. */
.ffa-ig-who-badges { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.ffa-ig .ffa-ig-badge { display: inline-flex; align-items: center; gap: 7px; padding: 5px 12px; border: 1.5px solid transparent; border-radius: 999px; font-size: 14px; font-weight: 600; line-height: 1.3; }
.ffa-ig .ffa-ig-badge i { font-size: 12px; }
.ffa-ig .ffa-ig-badge--decided { background: var(--accent); color: #FFFFFF; }
.ffa-ig .ffa-ig-badge--deciding { border-color: var(--terracotta); color: #EBA48E; }
.ffa-ig .ffa-ig-badge--recommended { border-color: #5A5249; color: var(--sand); }
.ffa-ig .ffa-ig-badge--say-yes { background: #E7EEE2; color: #46603C; }
.ffa-ig .ffa-ig-badge--say-limited { background: #F7EDCF; color: #7A5B12; }
.ffa-ig .ffa-ig-badge--say-no { background: #3A352D; color: var(--sand); }
.ffa-ig .ffa-ig-steps { gap: 12px; }
.ffa-ig .ffa-ig-step { background: var(--warmwhite); border-radius: 20px; padding: 20px 22px; }
.ffa-ig.ffa-ig .ffa-dark .ffa-ig-step-t, .ffa-ig .ffa-ig-step-t { color: var(--ink); }
.ffa-ig-take-note { display: flex; align-items: center; gap: 14px; padding: 14px 18px; border-radius: 18px; background: rgba(245, 240, 232, .08); font-size: 16px; font-weight: 600; color: var(--sand); }
.ffa-ig-take-note .ffa-ig-icon { width: 36px; height: 36px; font-size: 16px; background: var(--sand); color: var(--ffa-ink-dark); }

/* 8. What can I actually do? — the heading in its own column, the three
      effort tiers as three cards beside it, and "Which of these is me?"
      as a row of cards. A card that is opened spans the row, so what it
      opens reads at full width. */
.ffa-ig-action-inner { max-width: none; display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 1fr); column-gap: 48px; row-gap: 32px; align-items: start; }
.ffa-ig-action-inner > * { grid-column: 1 / -1; }
.ffa-ig-action-inner > .ffa-ig-action-h { grid-column: 1; }
.ffa-ig-action-inner > .ffa-ig-tiers { grid-column: 2; }
.ffa-ig-action-inner > .ffa-ig-primary { grid-column: 1; grid-row: 2; }
/* No effort cards (an issue without an action_box): one column, so the
   heading is not stranded beside an empty half. */
.ffa-ig-action-inner:not(:has(.ab-tier)) { grid-template-columns: minmax(0, 1fr); }
.ffa-ig .ffa-ig-tiers:not(:empty) { display: block; }
/* The zone's child is the module wrapper; the tiers are its children. */
.ffa-ig .ffa-ig-tiers .issue-module--action_box { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; }
.ffa-ig .ffa-ig-tiers .issue-module--action_box > :not(.ab-tier) { grid-column: 1 / -1; }
.ffa-ig .ab-tier { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; margin: 0; padding: 28px 26px; border: 0; border-radius: 24px; background: var(--sand); }
.ffa-ig .ab-tier--formal { border: 0; }
.ffa-ig .ab-cost { font-family: inherit; font-size: 12px; letter-spacing: .1em; padding: 6px 12px; border-radius: 999px; background: #FFFFFF; color: var(--ink-soft); }
.ffa-ig .ab-tier-icon { width: 64px; height: 64px; border-radius: 999px; background: #FFFFFF; font-size: 26px; }
.ffa-ig .ab-tier-label { font-size: 21px; letter-spacing: -.015em; line-height: 1.25; }
.ffa-ig .ab-tier-help { font-size: 16px; line-height: 1.5; margin-top: 8px; }
.ffa-ig .ab-tier--follow .ab-tier-formslot { width: 100%; margin-top: auto; }
.ffa-ig .ab-tier .ffa-ig-field-row { flex-direction: column; }
.ffa-ig .ab-tier .ffa-ig-field-row input[type="email"] { flex: none; }
.ffa-ig .ab-tier button[type="submit"] { width: 100%; padding: 14px 22px; font-size: 16px; }
.ffa-ig-acc { border-top: 0; padding-top: 8px; gap: 16px; }
.ffa-ig-acc > .ffa-ig-sub { font-size: 32px; letter-spacing: -.025em; }
.ffa-ig-door-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 14px; align-items: stretch; }
.ffa-ig-door-grid > .ffa-ig-doors { display: contents; }
.ffa-ig-door, .ffa-ig-ask { margin: 0; padding: 0; border: 1px solid var(--sand-dark); border-bottom: 1px solid var(--sand-dark); border-radius: 20px; background: #FFFFFF; }
.ffa-ig-door[open], .ffa-ig-ask[open] { grid-column: 1 / -1; padding-bottom: 18px; }
.ffa-ig-door-label, .ffa-ig-ask-summary { display: flex; align-items: center; gap: 16px; padding: 18px 20px; font-size: 17px; line-height: 1.35; }
.ffa-ig-door-label::before, .ffa-ig-ask-summary::before { content: none !important; }
.ffa-ig-door-label::after, .ffa-ig-ask-summary::after { content: '\203A'; content: '\203A' / ''; margin-left: auto; font-size: 26px; line-height: 1; color: var(--color-text-tertiary); transition: transform .15s; }
.ffa-ig-door[open] > .ffa-ig-door-label::after, .ffa-ig-ask[open] > .ffa-ig-ask-summary::after { transform: rotate(90deg); }
.ffa-ig-door-icon { width: 52px; height: 52px; font-size: 22px; }
.ffa-ig-door-q, .ffa-ig-door-take, .ffa-ig-door-link { margin-left: 88px; margin-right: 20px; }
.ffa-ig-ask-form { margin: 0 20px; }

/* 9. How does a hearing like this work? — on sand, white step cards, the
      icon in a disc above each title, the step we are at in a pale
      accent card. The done steps keep full ink (they are the record) and
      lose the loose check glyph: the sage number already says done. */
.ffa-ig-main { background: var(--sand); }
.ffa-ig .process-steps { gap: 14px; }
.ffa-ig .process-step { background: #FFFFFF; border: 1px solid transparent; border-radius: 20px; padding: 22px 20px; gap: 10px; }
.ffa-ig .process-icon { width: 64px; height: 64px; border-radius: 999px; background: var(--sand); display: flex; align-items: center; justify-content: center; font-size: 26px; line-height: 1; align-self: center; margin: 4px 0 6px; }
.ffa-ig .process-icon i { font-size: 26px; padding: 0; }
.ffa-ig .pstep--done .process-icon::after { content: none; }
.ffa-ig .pstep--done .process-title { color: var(--ink); }
.ffa-ig .pstep--done .process-desc { color: var(--ink-soft); }
.ffa-ig .pstep--upcoming { opacity: 1; }
.ffa-ig .process-num { width: 30px; height: 30px; font-size: 14px; }
.ffa-ig .process-title { font-size: 19px; letter-spacing: -.015em; }
.ffa-ig .process-desc { font-size: 15px; }
.ffa-ig .pstep--current { background: #F1F6F9; border-color: var(--accent); box-shadow: none; }
.ffa-ig .pstep-here { font-size: 12px; padding: 5px 12px; }
.ffa-ig .process-arrow { right: -12px; background: none; color: var(--ink-soft); }
.ffa-ig .process-note { display: flex; gap: 14px; align-items: center; margin-top: 20px; padding: 18px 22px; border-radius: 18px; background: #EAF1F5; font-size: 16px; font-style: normal; color: var(--ink); }
.ffa-ig .process-note-icon { color: var(--accent); font-size: 18px; }

/* 11. Updates — "All updates" is a button at the heading's right. The
       mockup's bold first sentence was dropped: it bolded some rows and
       not others. */
.ffa-ig-record-inner { display: grid; grid-template-columns: minmax(0, 1fr) auto; row-gap: 32px; align-items: center; }
.ffa-ig-record-inner > * { grid-column: 1 / -1; }
.ffa-ig-record-h { grid-column: 1; grid-row: 1; font-size: 40px; letter-spacing: -.03em; }
.ffa-ig-more { grid-column: 2; grid-row: 1; margin: 0; }
.ffa-ig-more summary { display: inline-flex; align-items: center; gap: 8px; padding: 10px 20px; border: 1px solid var(--sand-dark); border-radius: 999px; font-size: 16px; }
.ffa-ig-more summary::before { content: none !important; }
.ffa-ig-more summary::after { content: '\203A'; content: '\203A' / ''; font-size: 20px; line-height: 1; }
.ffa-ig-more[open] summary::after { transform: rotate(90deg); }
.ffa-updates-date { text-transform: uppercase; letter-spacing: .06em; font-size: 13px; padding-top: 4px; color: var(--ink-soft); }


/* ── Issue guide, the header pass (2026-09-26) ────────────────────────────
   The owner's second mockup, for the top of the page, read under the same
   rules as the pass above. What was taken, and how it degrades:
   1. The opener: the copy on the left and a status card on the right, when
      the issue has a `status_list` module (placement 'status'). Without
      one, or in a browser without :has(), it is the centred column it was.
   2. The two links become buttons: the first filled, the second outlined.
   3. The picture sits inside the band as a rounded card, with ONE caption
      under it (the mockup drew it twice, once on the picture).
   4. With a map in the intro zone (a site map), the hoisted number rides
      beside it as a card and the one-number section steps aside. A gallery
      in that zone (Marathon, water) keeps the full width and the number
      its own section, as does a browser without :has().
   5. The "Next:" sentence becomes a card with its calendar disc, on every
      v3 issue, and, when the module gives one, an arrow to the section it
      is about.
   Its phone rules sit in the file's one 900px and one 600px blocks.      */
.ffa-ig-open-copy { display: flex; flex-direction: column; align-items: center; gap: 22px; }
.ffa-ig-open-inner:has(> .ffa-ig-status:not(:empty)) { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); column-gap: 72px; align-items: center; text-align: left; }
.ffa-ig-open-inner:has(> .ffa-ig-status:not(:empty)) .ffa-ig-open-copy { align-items: flex-start; }
.ffa-ig-open-inner:has(> .ffa-ig-status:not(:empty)) .ffa-ig-links { justify-content: flex-start; }
.ffa-ig-open-inner:has(> .ffa-ig-status:not(:empty)) .ffa-ig-h { font-size: 88px; }
.ffa-ig-status { width: 100%; max-width: 680px; margin-top: 18px; text-align: left; }
.ffa-ig-open-inner:has(> .ffa-ig-status:not(:empty)) > .ffa-ig-status { max-width: none; margin-top: 0; }
.ffa-ig-status .status-list { list-style: none; margin: 0; padding: 6px 28px; border: 1px solid #3A352D; border-radius: 24px; background: var(--ffa-card-dark); }
.ffa-ig-status .status-row { display: flex; align-items: center; gap: 18px; padding: 22px 0; }
.ffa-ig-status .status-row + .status-row { border-top: 1px solid #3A352D; }
.ffa-ig-status .status-icon { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 52px; height: 52px; border-radius: 999px; background: #3A352D; color: var(--sand); font-size: 22px; }
.ffa-ig-status .status-text { flex: 1; min-width: 0; font-size: 17px; line-height: 1.4; color: var(--sand); }
.ffa-ig-status .status-mark { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: 999px; font-size: 16px; box-sizing: border-box; }
.ffa-ig-status .is-done .status-mark { background: var(--accent); color: #fff; }
.ffa-ig-status .is-open .status-mark { border: 2px solid var(--terracotta); color: var(--terracotta); }

.ffa-ig .ffa-ig-links { gap: 16px; flex-wrap: wrap; }
.ffa-ig .ffa-ig-links a { display: inline-flex; align-items: center; gap: 12px; min-height: 56px; padding: 0 28px; border: 1.5px solid var(--sand); border-radius: 999px; font-size: 18px; font-weight: 700; color: var(--sand); text-decoration: none; }
.ffa-ig .ffa-ig-links a:first-child { background: var(--sand); color: var(--ffa-ink-dark); }
.ffa-ig .ffa-ig-links a::after { content: "\2192"; content: "\2192" / ""; font-size: 22px; line-height: 1; position: relative; top: -2px; }
.ffa-ig .ffa-ig-links a:hover { color: var(--sand); text-decoration: none; background: #3A352D; }
.ffa-ig .ffa-ig-links a:first-child:hover { color: var(--ffa-ink-dark); background: #fff; }

.ffa-ig-hero { padding-bottom: 64px; }
.ffa-ig-hero-img { display: block; height: 560px; border-radius: 24px; }

.ffa-ig-site-stat { display: none; }
/* The band keeps the 980px column its gallery always had; only the map row widens. */
.ffa-ig-site { width: min(980px, calc(100% - 48px)); }
.ffa-ig-site:has(> .ffa-ig-zone > .issue-module--map) { width: min(1200px, calc(100% - 48px)); display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); gap: 28px; align-items: stretch; padding-block: 96px; }
.ffa-ig-site:has(> .ffa-ig-zone > .issue-module--map) > .ffa-ig-zone { padding: 0; }
.ffa-ig-site:has(> .ffa-ig-zone > .issue-module--map) > .ffa-ig-site-stat { display: flex; flex-direction: column; justify-content: center; gap: 12px; margin-top: 72px; padding: 40px 36px; border-radius: 24px; background: var(--sand); box-shadow: none; }
/* margin-top: the map's own heading (44px, line-height 1.1, 24px under it), so the card starts level with the map. */
.ffa-ig:has(.ffa-ig-site > .ffa-ig-zone > .issue-module--map) .ffa-ig-number { display: none; }
.ffa-ig-site-stat-n { font-size: 104px; line-height: .9; letter-spacing: -.05em; }
.ffa-ig-site-stat-l { font-size: 24px; font-weight: 700; letter-spacing: -.02em; color: var(--ink); }
.ffa-ig-site-stat-sub { margin: 0; font-size: 17px; line-height: 1.5; color: var(--ink-soft); }
.ffa-ig-intro .map-head { font-size: 44px; line-height: 1.1; letter-spacing: -.03em; text-transform: none; margin: 0 0 24px; }
.ffa-ig-intro .issue-map-canvas:not(.issue-map-canvas--fallback) { height: 420px; border-radius: 24px; border: 1px solid rgba(44, 36, 24, .12); box-sizing: border-box; }

.ffa-ig-strip .issue-strip-line { max-width: none; gap: 24px; padding: 28px 32px; border-radius: 24px; background: var(--sand); font-size: 22px; line-height: 1.4; }
.ffa-ig-strip .issue-strip-line > span:not(.ui-icon) { flex: 1; min-width: 0; }
.ffa-ig .ffa-ig-strip .issue-strip-icon { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 72px; height: 72px; border-radius: 999px; background: var(--sand-dark); font-size: 28px; }
.ffa-ig .issue-strip-link { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 56px; height: 56px; border-radius: 999px; background: #fff; color: var(--ink); font-size: 20px; text-decoration: none; }
.ffa-ig .issue-strip-link:hover { color: var(--ink); background: var(--sand-dark); text-decoration: none; }

/* ── About ─────────────────────────────────────────────
   /about, slice 6 — page/page.about.php against
   docs/design/apple/src/about-body.html. Every number below is that
   file's; the classes are its classes under the spec's §3 names.

   The page is server copy end to end (no loader, no .load-data), so
   nothing here has a loading or an error state to draw.               */

/* 1. The hero — src/about-body.html:16-20, and the owner's mockup of
      2026-09-27: the headline block on the left, a sand tagline card in
      a 360px column on the right. The card follows the lead in the DOM,
      so a phone reads it after the lead; the grid places it beside the
      headline. The h1 keeps house rule 4's 92px, and the column is its
      limit now: the old 1000px cap went with the centred layout.       */
.ffa-ab-intro { display: grid; grid-template-columns: minmax(0, 1fr) 360px; gap: 64px; align-items: center; padding: 112px 0 96px; }
.ffa-ab-intro-copy { display: flex; flex-direction: column; gap: 22px; }
.ffa-ab-lead { max-width: 640px; }
/* The tagline card is a card on the warm-white hero, not a second
   ground. Its spaced capitals end in a short terracotta rule. Its
   lines are 20px: at 22px "A more informed community." is wider than
   the card's 280px and breaks, where the mockup draws three lines.    */
.ffa-ab-tag { background: var(--sand); border-radius: var(--ffa-radius-card); padding: 40px; display: flex; flex-direction: column; gap: 28px; }
.ffa-ab-tag-k { font-size: 12px; font-weight: 600; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-soft); line-height: 1.7; }
.ffa-ab-tag-k::after { content: ""; display: block; width: 36px; height: 2px; background: var(--terracotta); margin-top: 14px; }
.ffa-ab-tag-l { font-size: 20px; line-height: 1.4; letter-spacing: -.01em; color: var(--ink); }

/* 2. What we do — src/about-body.html:22-28. Three numbered cards on
      sand. The card's own 18px gap comes down to the mockup's 14px, and
      the body text down to 17px: three cards side by side are a narrower
      measure than the 19px .ffa-body was written for. Since 2026-09-27
      each card opens on an icon disc, and its disc and number share one
      of three tints, which the process discs in section 4 repeat.     */
.ffa-ab-what { padding: 96px 0; }
.ffa-ab-card { gap: 14px; }
.ffa-ab-n { font-size: 44px; font-weight: 700; letter-spacing: -.04em; line-height: 1; }
.ffa-ab-card-h { font-size: 24px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; }
.ffa-ab-card-b { font-size: 17px; }
/* The icon disc: the home doors' stroke idiom (.ffa-hm-ico) on a tinted
   circle, so the site keeps one way of drawing an icon. The process
   callout in section 4 reuses it at 64px.                              */
.ffa-ab-disc { width: 72px; height: 72px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; flex: none; }
.ffa-ab-disc svg { width: 30px; height: 30px; stroke: currentColor; fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ffa-ab-card .ffa-ab-disc { margin-bottom: 6px; }
/* The three tints are the vocabulary's own pill tints, value for value:
   blue is the tract pill's, warm the deny pill's, sage the vote-yes
   pill's. Every numeral set in them is large text and passes 3:1.     */
.ffa-ab-disc--blue, .ffa-ab-step-n--blue { background: rgba(160, 203, 224, .35); color: var(--accent); }
.ffa-ab-disc--warm, .ffa-ab-step-n--warm { background: rgba(196, 101, 74, .15); color: var(--terracotta); }
.ffa-ab-disc--sage, .ffa-ab-step-n--sage { background: rgba(164, 196, 150, .35); color: #4A6B3F; }
.ffa-ab-n--blue { color: var(--accent); }
.ffa-ab-n--warm { color: var(--terracotta); }
.ffa-ab-n--sage { color: #4A6B3F; }

/* 3. The doctrine — src/about-body.html:30-36, in two columns since the
      owner's mockup of 2026-09-27: the headline on the left, the three
      "No" lines on the right as a list, the closing line centred under
      both. The divider is the list's own left border, a hairline at 18%
      warm white, so on one column it turns into a line above the list
      and nothing is left floating.                                     */
.ffa-ab-never { padding: 120px 0; }
.ffa-ab-never-inner { display: flex; flex-direction: column; gap: 56px; }
.ffa-ab-never-grid { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 64px; align-items: center; }
.ffa-ab-never-copy { display: flex; flex-direction: column; gap: 22px; }
.ffa-ab-never-h { max-width: 620px; }
.ffa-ab-nos { list-style: none; margin: 0; padding: 0 0 0 64px; border-left: 1px solid rgba(253, 251, 247, .18); display: flex; flex-direction: column; gap: 28px; }
.ffa-ab-no { display: flex; align-items: center; gap: 20px; font-size: 22px; line-height: 1.3; letter-spacing: -.01em; color: var(--sand); }
.ffa-ab-no-i { width: 34px; height: 34px; flex: none; color: var(--terracotta-light); }
.ffa-ab-no-i svg { display: block; width: 34px; height: 34px; stroke: currentColor; fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ffa-ab-never-close { text-align: center; max-width: 680px; margin: 0 auto; }

/* 4. How a public meeting works — src/about-body.html:38-47. Copy left,
      the four steps right. The site nav is sticky, so the anchor four
      other templates link to carries a scroll-margin or its own eyebrow
      lands under the bar (same value as the issue guide's anchored
      zones). page/partial.process.php prints this section on /about and
      on /meetings/why, so every rule below draws both pages.           */
.ffa-ab-process { padding: 120px 0; scroll-margin-top: calc(var(--nav-h) + 16px); }
.ffa-ab-process-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 64px; align-items: start; }
.ffa-ab-process-copy { display: flex; flex-direction: column; gap: 22px; }
/* The callout under the lead (2026-09-27): a sand card holding the
   people disc and two lines. On /meetings/why the section sits on warm
   white between two sand bands, so it reads as a card there too.       */
.ffa-ab-voice { margin-top: 20px; background: var(--sand); border-radius: 24px; padding: 28px; display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: 22px; align-items: center; }
.ffa-ab-voice .ffa-ab-disc { width: 64px; height: 64px; }
.ffa-ab-voice-main { display: flex; flex-direction: column; gap: 6px; }
.ffa-ab-voice-h { font-size: 20px; font-weight: 700; letter-spacing: -.015em; line-height: 1.25; color: var(--ink); }
.ffa-ab-voice-b { font-size: 16px; line-height: 1.5; color: var(--ink-soft); }
/* The list's own marker is off: the numbers are drawn as elements, and a
   marker as well would print each step twice (the precedent is
   .ffa-speak-steps). Since 2026-09-27 each number is a tinted disc in
   the three tints of section 2, a dashed line joins the discs through
   the 20px gap between steps, and each step sits on a white card: the
   vocabulary's soft shadow and no border, tighter than .ffa-card.      */
.ffa-ab-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 20px; }
.ffa-ab-step { position: relative; display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 24px; padding: 0; align-items: start; }
.ffa-ab-step::after { content: ""; position: absolute; left: 27px; top: 56px; bottom: -20px; border-left: 2px dashed rgba(44, 36, 24, .18); }
.ffa-ab-step:last-child::after { display: none; }
.ffa-ab-step-n { position: relative; z-index: 1; width: 56px; height: 56px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 24px; font-weight: 700; letter-spacing: -.02em; line-height: 1; }
.ffa-ab-step-main { background: #FFFFFF; border-radius: 20px; padding: 22px 26px; box-shadow: 0 2px 14px rgba(44, 36, 24, .06); display: flex; flex-direction: column; gap: 6px; }
.ffa-ab-step-h { font-size: 20px; font-weight: 700; letter-spacing: -.015em; line-height: 1.25; }
.ffa-ab-step-b { font-size: 16px; }

/* 5. Ask us for something — src/about-body.html:49-60. Copy left, the
      form as the mockup's 520px card. Same scroll-margin as #process:
      /issues links straight at this section.                           */
.ffa-ab-ask { padding: 120px 0; scroll-margin-top: calc(var(--nav-h) + 16px); }
.ffa-ab-ask-grid { display: grid; grid-template-columns: minmax(0, 1fr) 520px; gap: 64px; align-items: center; }
.ffa-ab-ask-copy { display: flex; flex-direction: column; gap: 22px; }

/* 6. Who runs it — src/about-body.html:62-70. Hidden until the owner
      fills $who, so these rules draw nothing on the page as it ships.  */
.ffa-ab-who { padding: 120px 0; }
.ffa-ab-who-grid { gap: 64px; align-items: center; }
.ffa-ab-who-copy { display: flex; flex-direction: column; gap: 22px; }
.ffa-ab-who-ph { height: 380px; border-radius: 32px; }
/* The admin's reminder, in the place the block would have stood.       */
.ffa-ab-todo { padding: 96px 0; }

/* THE ASK FORM. Prefixed .ffa-form and not .ffa-ab-, because it is the
   vocabulary's form and not About's: the atoms are the mockup's field
   (14px radius, a hairline border, 16px type) and its black pill, and the
   next page that needs a form takes them as they are. It replaces the
   .iv2-* atoms page.about.php borrowed from the v2 issue template, which
   stay in css/style.css for page.issue-std.php.                        */
.ffa-form { gap: 14px; }
.ffa-form-label { display: block; font-size: 14px; font-weight: 600; color: var(--ink-soft); }
.ffa-form-label input, .ffa-form-label textarea, .ffa-form-label select { margin-top: 6px; font-weight: 400; }
.ffa-form input[type="text"], .ffa-form input[type="email"], .ffa-form textarea, .ffa-form select {
  font-family: inherit; font-size: 16px; color: var(--ink); background: #FFFFFF;
  border: 1px solid rgba(44, 36, 24, .16); border-radius: 14px; padding: 14px 16px; width: 100%; box-sizing: border-box;
}
.ffa-form textarea { height: 110px; resize: vertical; }
.ffa-form-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 16px; }
/* The one black pill this page spends (house rule 5). A <button>, so it
   needs the three properties a pill on an <a> never asks for.          */
.ffa-pill--send { background: var(--ink); color: var(--warmwhite); font-size: 15px; padding: 13px 22px; border: 0; font-family: inherit; cursor: pointer; }
.ffa-pill--send:disabled { opacity: .55; cursor: default; }
/* Off-screen, not display:none — a hidden honeypot a bot cannot see is a
   honeypot a bot does not fill in.                                     */
.ffa-form-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.ffa-form-msg:empty { display: none; }
.ffa-form-msg { font-size: 15px; font-weight: 600; }
.ffa-form-msg.is-ok { color: #46603C; }
.ffa-form-msg.is-error { color: var(--brick); }

/* ── Sources ───────────────────────────────────────────
   /sources, slice 6 — page/page.sources.php against
   docs/design/apple/src/sources-body.html. Every number below is that
   file's; the classes are its classes under the spec's §3 names.

   This page's rules were never in css/style.css: the 2026-08-07 layout
   carried them as an inline <style> block at the top of the template,
   page-scoped on .sources-* / .source-*, and the rewrite drops that
   block whole. So there is nothing for the runbook's css/style.css step
   to delete for Sources — the deletion ships inside the template.

   The cards ARE loader rows (.view-sources clones one per data source),
   so unlike /about above, everything from .ffa-source-card down is drawn
   against markup this file never sees written out.                    */

/* 1. The hero — src/sources-body.html:11-15. */
.ffa-src-intro { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 22px; padding: 112px 0 96px; }
.ffa-src-h { max-width: 1000px; }
.ffa-src-lead { max-width: 640px; }

/* 2. The sources — src/sources-body.html:17-26. Two-up cards on sand,
      at the mockup's 20px rather than .ffa-grid-2's 24px. The count
      sentence over them is the loader's three numbers in one line
      (house rule 2 does not want a row of stats), set at the card's
      17px so it reads as a caption to the grid and not as a lead.   */
.ffa-src-band { padding: 96px 0; }
.ffa-src-count { font-size: 17px; margin-bottom: 28px; }
.ffa-src-grid { gap: 20px; }
.ffa-source-card { gap: 10px; }
/* The kicker is .ffa-label one step up: the mockup sets this one at
   13px, where the micro-label elsewhere in this file is 12.         */
.ffa-source-kicker { font-size: 13px; }
.ffa-source-name { font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; }
.ffa-source-b { font-size: 16px; }
/* margin-top: auto, which the artboard can leave out and a page cannot:
   the six cards it draws all carry the same three lines, and real rows
   do not — a source with no mapped measures has one line less, and its
   link would otherwise sit halfway up a card whose neighbour's sits at
   the bottom. Grid items stretch, so pushing the foot down aligns every
   link in the row.                                                    */
.ffa-source-foot { margin-top: auto; padding-top: 6px; display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 10px 20px; }
.ffa-source-meta { display: flex; flex-wrap: wrap; font-size: 13px; line-height: 1.6; color: var(--color-text-tertiary); }
/* The separator is drawn BETWEEN items rather than after each, because
   any of the three can be removed by data-show_if and a trailing dot
   would then end the line.                                            */
.ffa-source-meta-i + .ffa-source-meta-i::before { content: "\00B7"; margin: 0 8px; }
.ffa-source-link { font-size: 15px; }

/* 3. Three rules — src/sources-body.html:29-40. Copy left, the three
      rules right as a ruled list. Same shape as /about's four steps,
      and deliberately not the same classes: these are not steps, they
      have no order and no numbers.                                    */
.ffa-src-rules { padding: 120px 0; }
.ffa-src-rules-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 64px; align-items: start; }
.ffa-src-rules-copy { display: flex; flex-direction: column; gap: 22px; }
.ffa-src-credit { margin-top: 16px; color: var(--color-text-tertiary); }
.ffa-rules-list { display: flex; flex-direction: column; border-top: 1px solid rgba(44, 36, 24, .12); }
.ffa-rule { display: flex; flex-direction: column; gap: 6px; padding: 22px 0; border-bottom: 1px solid rgba(44, 36, 24, .12); }
.ffa-rule-h { font-size: 20px; font-weight: 700; letter-spacing: -.015em; line-height: 1.25; }
.ffa-rule-b { font-size: 16px; }

/* 4. The index — src/sources-body.html:43-52. Copy left, the art
      placeholder right, on the dark ground. The placeholder takes the
      dark ground's own card colour and border, which is the one place
      in this file .ffa-ph is not the warm dashed block.               */
.ffa-src-index { padding: 120px 0; }
.ffa-src-index-grid { gap: 64px; align-items: center; }
.ffa-src-index-copy { display: flex; flex-direction: column; gap: 22px; }
.ffa-src-index-ph { height: 380px; border-radius: 32px; background: var(--ffa-card-dark); border-color: #4A443B; color: #B9AF9E; }
.ffa-src-index-ph .ffa-ph-tag { background: var(--ffa-ink-dark); color: #B9AF9E; }
.ffa-src-index-ph .ffa-ph-cap { color: #B9AF9E; }

/* ── Index methodology ─────────────────────────────────
   /indices/{slug}/methodology — page/page.index_methodology.php. Spec:
   docs/superpowers/specs/2026-09-24-chipi-methodology-page-design.md §6.
   There is no artboard: the grounds are /sources' (warm white, sand,
   warm white, dark), and each part card is /neighborhood's .ffa-part
   head over a table re-cut from .ffa-why-tbl — whose weight column is
   never hidden here, because on this page the share IS the row (D4).  */

/* 1. The hero. /sources' padding, left-aligned. The h1 is set at the
      60px step (D9) on desktop only: at ≤900px .ffa-h1 is 60px anyway,
      and at ≤600px .ffa-h1's 40px outranks this rule by source order —
      which is why it is not restated in either breakpoint below.      */
.ffa-mx-intro { display: flex; flex-direction: column; align-items: flex-start; gap: 22px; padding: 112px 0 96px; }
.ffa-mx-h { font-size: 60px; line-height: 1.04; letter-spacing: -.035em; max-width: 900px; }
.ffa-mx-ver { margin-top: -8px; }
.ffa-mx-lead { max-width: 640px; }

/* 2. The sand band: the question, the method, the three parts. */
.ffa-mx-band { padding: 96px 0; }
.ffa-mx-band-inner { display: flex; flex-direction: column; gap: 56px; }
.ffa-mx-q { gap: 12px; }
.ffa-mx-q-t { color: var(--ink); }
.ffa-mx-how { display: flex; flex-direction: column; gap: 18px; max-width: 760px; }
.ffa-mx-count { color: var(--ink); font-weight: 600; }
.ffa-mx-tech { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.ffa-mx-tech-t { font-size: 16px; color: var(--color-text-tertiary); }
.ffa-mx-parts { display: flex; flex-direction: column; gap: 24px; }
/* The card's head is .ffa-part's stack — glyph, name, weight sentence —
   in the part card's one neutral colour (D2): the glyph is currentColor. */
.ffa-mx-part { gap: 16px; }
.ffa-mx-part-head { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; color: var(--ink-soft); }
.ffa-mx-part-d { font-size: 16px; }
/* .ffa-why-tbl's rules, re-cut. The column widths are fixed so the three
   cards' tables line up under one another, whatever each row holds.  */
.ffa-mx-tbl { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: 15px; }
.ffa-mx-tbl th:nth-child(1) { width: 46%; }
.ffa-mx-tbl th:nth-child(2) { width: 16%; }
.ffa-mx-tbl th:nth-child(3) { width: 26%; }
.ffa-mx-tbl th:nth-child(4) { width: 12%; }
.ffa-mx-tbl th { text-align: left; font-size: 13px; font-weight: 600; color: var(--color-text-tertiary); padding: 0 16px 8px 0; border-bottom: 1px solid rgba(44, 36, 24, .12); }
.ffa-mx-tbl td { padding: 11px 16px 11px 0; border-bottom: 1px solid rgba(44, 36, 24, .06); vertical-align: top; }
.ffa-mx-tbl tr > *:last-child { padding-right: 0; }
.ffa-mx-c-name { display: block; font-weight: 600; color: var(--ink); }
.ffa-mx-c-why { display: block; margin-top: 2px; font-size: 15px; color: var(--color-text-tertiary); }
.ffa-mx-c-inv { display: block; margin-top: 2px; font-size: 14px; font-style: italic; color: var(--color-text-tertiary); }
.ffa-mx-c-w { white-space: nowrap; color: var(--ink); }
.ffa-mx-c-src, .ffa-mx-c-yr { color: var(--color-text-tertiary); }

/* 3. References: a ruled list at 15px. The <ol> needs its own left
      padding — css/style.css:37 resets every element's padding to 0, and
      an unpadded list hangs its numbers outside the column.           */
.ffa-mx-refs { display: flex; flex-direction: column; gap: 22px; padding: 96px 0; }
.ffa-mx-ref-list { padding-left: 1.6em; font-size: 15px; line-height: 1.5; color: var(--ink-soft); }
.ffa-mx-ref { padding: 12px 0 12px 6px; border-bottom: 1px solid rgba(44, 36, 24, .12); }
.ffa-mx-ref::marker { color: var(--color-text-tertiary); }

/* 4. The map, on the dark ground, as /sources closes. Two links wrap
      on a narrow screen instead of running off it.                     */
.ffa-mx-map { padding: 120px 0; }
.ffa-mx-map-inner { display: flex; flex-direction: column; gap: 22px; }
.ffa-mx-map-lead { max-width: 640px; }
.ffa-mx-map-links { flex-wrap: wrap; row-gap: 10px; }

/* The fallback: the shared .ffa-missing carries the sentence. */
.ffa-mx-missing-l { display: flex; margin-top: 10px; font-size: 19px; }

/* ── Why go ────────────────────────────────────────────
   /meetings/why, launch slice L2 — page/page.meetings-why.php. There is no
   mockup for this page: it is the About page's vocabulary (a left-aligned
   intro, numbered-card type, the process partial) on the meetings screens'
   grounds. White intro with its three cards, sand "who decides", the white
   process partial, a sand week line, the dark speak band (house rule 3).  */
.ffa-mw-intro { display: flex; flex-direction: column; gap: 22px; padding: 96px 0 96px; }
.ffa-mw-h { max-width: 900px; }
.ffa-mw-lead { max-width: 640px; }
.ffa-mw-kinds { margin-top: 26px; }
/* Cards on a white ground: the sand fill and no shadow — the look /this-week's
   even meetings had until its 2026-09-27 design pass.                      */
.ffa-mw-kinds .ffa-card { background: var(--sand); box-shadow: none; }
.ffa-mw-card { gap: 14px; }
.ffa-mw-card-h { font-size: 24px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; }
.ffa-mw-card-b { font-size: 17px; }
.ffa-mw-card-when { font-size: 15px; font-weight: 600; color: var(--ink-soft); }
.ffa-mw-bodies { padding: 96px 0; }
.ffa-mw-band-head { display: flex; flex-direction: column; gap: 14px; margin-bottom: 40px; max-width: 640px; }
.ffa-mw-src { margin-top: 32px; font-size: 14px; line-height: 1.6; color: var(--color-text-tertiary); }
.ffa-mw-src a { color: inherit; text-decoration: underline; }
.ffa-mw-week { padding: 64px 0; }
.ffa-mw-week-inner { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 20px; }
.ffa-mw-week-n { font-size: 28px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; margin-top: 8px; }

/* ── What's next and Get updates ───────────────────────
   /whats-next (page/page.whats-next.php) and the email sign-up band
   (page/partial.signup.php) that ends it, /get-updates and an issue guide.
   Spec docs/superpowers/specs/2026-09-26-whats-next-and-signup-design.md
   §3.2 and §5.1. There is no mockup: the hero is /meetings/why's intro,
   the two lists are the grouped lists below (.ffa-group, .ffa-row,
   .ffa-chev) in /meetings' 680px column, and the band is the near-black
   ground with the vocabulary's field and one pill. .ffa-updates-* is the
   issue guide's record and is not these rules' business.               */
.ffa-wn-hero { display: flex; flex-direction: column; gap: 22px; padding: 96px 0; }
.ffa-wn-h { max-width: 900px; }
.ffa-wn-lead { max-width: 640px; }
.ffa-wn-live, .ffa-wn-building { padding: 72px 0; }
.ffa-wn-group-h { margin: 0; }
/* A white list on the warm white ground needs the lift the sand one gets
   from `.ffa-sand .ffa-group`.                                          */
.ffa-wn-building .ffa-group { box-shadow: 0 2px 14px rgba(44, 36, 24, .06); }
a.ffa-wn-row { color: inherit; text-decoration: none; }
.ffa-wn-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.ffa-wn-status { flex: none; background: var(--sand); color: var(--ink-soft); }
.ffa-su { padding: 120px 0; }
.ffa-su-inner { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 64px; align-items: start; }
.ffa-su-copy { display: flex; flex-direction: column; gap: 22px; }
.ffa-su-form { display: flex; flex-direction: column; gap: 18px; }
.ffa-su-email { display: flex; flex-direction: column; gap: 8px; }
.ffa-su-email input { font-family: inherit; font-size: 16px; color: var(--ink); background: #FFFFFF; border: 1px solid rgba(44, 36, 24, .16); border-radius: 14px; padding: 14px 16px; width: 100%; box-sizing: border-box; }
.ffa-su-topics { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
/* A grid, not a wrapping flex row: a long label (the ES ones at 390px)
   wraps beside its box, and "coming soon" sits under the label.        */
.ffa-su-topic { display: grid; grid-template-columns: 18px minmax(0, 1fr); column-gap: 12px; row-gap: 2px; align-items: start; font-size: 17px; line-height: 1.35; color: var(--sand); cursor: pointer; }
.ffa-su-topic input { width: 18px; height: 18px; margin: 2px 0 0; accent-color: var(--terracotta-light); }
.ffa-su-soon { grid-column: 2; font-size: 13px; color: #B9AF9E; }
/* No `display` here: the [hidden] attribute is what js/signup.js turns off. */
.ffa-su-msg { font-size: 15px; font-weight: 600; color: var(--terracotta-light); }
/* The one pill (house rule 5). .ffa-pill--go is near-black, so on this
   ground it takes the sand fill instead.                                 */
.ffa-dark .ffa-su-go { align-self: flex-start; background: var(--sand); color: var(--ink); }
.ffa-su-note { font-size: 13px; line-height: 1.5; color: #B9AF9E; }
.ffa-su-state { display: flex; flex-direction: column; gap: 22px; padding: 96px 0 72px; }
.ffa-su-thanks { font-weight: 600; color: var(--ink); }

/* ── Privacy and Terms ─────────────────────────────────
   /privacy and /terms (page/page.privacy.php, page/page.terms.php), slice
   L4a: spec docs/superpowers/specs/2026-09-28-open-finished-pages-design.md
   §6.1. There is no mockup: the intro is /meetings/why's, the short version
   is the vocabulary's three white cards on sand, and the detail is the ruled
   list /sources draws (.ffa-rules-list) in /meetings' 680px reading column.
   Three things the vocabulary does not have: the band paddings (every page
   sets its own; .ffa-wrap carries none), a list inside a ruled section (the
   `*` reset leaves a <ul> no padding, so its bullets would hang outside the
   column), and the anchor offset — /privacy#delete must land below the
   sticky bar, not under it.                                              */
.ffa-lg-intro { display: flex; flex-direction: column; gap: 22px; padding: 96px 0; }
.ffa-lg-h { max-width: 900px; }
.ffa-lg-lead { max-width: 640px; }
.ffa-lg-updated { font-size: 15px; color: var(--color-text-tertiary); }
.ffa-lg-es { font-size: 17px; font-weight: 600; color: var(--ink); }
.ffa-lg-short { padding: 96px 0; }
.ffa-lg-short-h { margin-bottom: 32px; }
.ffa-lg-card-h { font-size: 24px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; }
.ffa-lg-card-b { font-size: 17px; }
.ffa-lg-detail { padding: 96px 0 120px; }
.ffa-lg-detail .ffa-rule { gap: 12px; scroll-margin-top: calc(var(--nav-h) + 16px); }
.ffa-lg-ul { margin: 0; padding: 0 0 0 22px; list-style: disc; display: flex; flex-direction: column; gap: 4px; font-size: 16px; line-height: 1.5; color: var(--ink-soft); }
.ffa-lg-close { display: flex; flex-direction: column; gap: 14px; margin-top: 40px; }

/* ── Neighborhood ──────────────────────────────────────
   /neighborhood/{geoid}, slice 6 — page/page.neighborhood.php against
   docs/design/apple/src/tractdesk-body.html (desktop) and
   src/tract-body.html (phone). Every number below is one of those two
   files'; the classes are their classes under the spec's §3 names.

   This page is the one route in this slice with BOTH artboards drawn, so
   it is also the clearest case of the spec's responsive rule: the phone
   artboard is the same page at <= 600px and not a second template. No
   .screen, no tab bar — the site nav collapses instead — and the phone
   block at the foot of this file restyles these same elements rather
   than hiding them and drawing new ones.

   Almost everything here is loader rows: the six measure cards, the
   nearby list and the decision cards are all cloned from data this file
   never sees written out, so their rules have to hold for a card whose
   neighbour has one line more.                                        */

/* 1. The hero — src/tractdesk-body.html:12-27. The copy left, the index
      ring in the mockup's 360px column at the right.                  */
.ffa-nb-intro { display: grid; grid-template-columns: minmax(0, 1fr) 520px; gap: 64px; align-items: center; padding: 96px 0 80px; }
.ffa-nb-intro-copy { display: flex; flex-direction: column; gap: 22px; }
/* The two halves of the lead are separate elements because either can be
   removed by data-show_if, so the space between them belongs to the
   second one and disappears with it.                                  */
.ffa-nb-lead > span + span { margin-left: .35em; }
/* The share control is a <button> — it copies, it does not open — so it
   has to be un-buttoned by hand and then told to look like the link
   beside it. It is NOT given .ffa-links' chevron for the same reason.  */
.ffa-nb-share { font: inherit; color: var(--accent); background: none; border: 0; padding: 0; cursor: pointer; display: inline-flex; align-items: center; gap: 8px; }
.ffa-nb-share:hover { color: var(--navy); text-decoration: underline; }

/* Slice 6f — icons. One sprite in the page, one colour: currentColor.     */
.ffa-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.ffa-ic { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
/* Slice 6h — a FILLED glyph (the sparkle on the two AI notes). CSS cannot
   reach a <use> target and .ffa-ic is stroke-only, so the <svg> carries the
   fill on a class of its own. Directly after .ffa-ic on purpose: the two
   rules have the same specificity, so ORDER is what lets this one win.  */
.ffa-ic--fill { fill: currentColor; stroke: none; }

/* The hero's two actions. The pill is the page's ONE (house rule 5): .ffa-pill
   is the shape, --go the ink ground; it takes a pin and NO chevron. Both
   glyphs are masks on ::before because neither control may hold a child —
   t7 pins both tags, and the Share script sets textContent.              */
.ffa-nb-links { align-items: center; gap: 16px 24px; flex-wrap: wrap; }
.ffa-nb-links a.ffa-nb-go, .ffa-nb-links a.ffa-nb-go:hover { color: var(--warmwhite); text-decoration: none; white-space: nowrap; }
.ffa-nb-links a.ffa-nb-go::after { content: none; }
.ffa-nb-go::before, .ffa-nb-share::before { content: ""; width: 18px; height: 18px; flex: none; background: currentColor; -webkit-mask: var(--ffa-m) center / contain no-repeat; mask: var(--ffa-m) center / contain no-repeat; }
.ffa-nb-go::before { --ffa-m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 22s7-6.2 7-12a7 7 0 0 0-14 0c0 5.8 7 12 7 12z'/%3E%3Ccircle cx='12' cy='10' r='2.5'/%3E%3C/svg%3E"); }
.ffa-nb-share::before { --ffa-m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 15V3'/%3E%3Cpath d='M8 7l4-4 4 4'/%3E%3Cpath d='M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-7'/%3E%3C/svg%3E"); }

/* The index ring. The circle geometry is the mockup's (r=44 in a 104
   viewBox, rotated -90° so the arc opens at twelve o'clock), which is
   what load.neighborhood.php's ring_dash counts against: it returns
   "<n> 276", the 276 being that circle's circumference. The score text
   is sized in USER units, not pixels — it scales with the svg, which is
   how the same markup carries a 260px ring here and a 92px one on a
   phone.                                                              */
.ffa-nb-index { display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
.ffa-index-ring { width: 260px; height: 260px; flex: none; }
.ffa-index-ring-t { fill: none; stroke: #EDE7DA; stroke-width: 10; }
.ffa-index-ring-v { fill: none; stroke: var(--accent); stroke-width: 10; stroke-linecap: round; }
.ffa-index-ring-n { font-size: 30px; font-weight: 700; fill: var(--ink); letter-spacing: -1.5px; }
.ffa-nb-index-copy { display: flex; flex-direction: column; gap: 6px; }
.ffa-index-name { font-size: 17px; font-weight: 700; letter-spacing: -.01em; line-height: 1.2; }
/* The catalog's short name, for the phone card that cannot hold the long
   one. Both are printed; the block below swaps which one is shown.     */
.ffa-index-name--short { display: none; }
.ffa-index-cap { font-size: 15px; }
/* Slice 6d: the ring sits LEFT of the breakdown's head, in one row. 220px is
   the ring's own 200px plus its stroke; the head takes the rest. Centred on
   the cross axis so the score lines up with the sentence about it.        */
.ffa-nb-why-top { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 48px; align-items: center; }
.ffa-nb-why-top .ffa-index-ring { width: 200px; height: 200px; }
.ffa-nb-why-head { display: flex; flex-direction: column; gap: 18px; }

/* 1b. How the score is built — the CHIPI breakdown, slice 6b. The section
      between the hero and "The numbers.", explaining the ring above it.

      WARM WHITE, WITH A HAIRLINE ABOVE. No band of its own and no sand:
      this page spends its one ground change on "The numbers." below
      (house rule 3), so the breakdown continues the hero's ground and is
      separated from it by a rule. The rule is on the INNER wrap and not
      on the section, so it stops at the page's gutters like everything
      else in this file rather than running edge to edge like a seam.

      THREE CARDS ON THAT WARM WHITE since slice 6g, one per part, on
      .ffa-grid-3 — the grid the six measures already sit on. Until 6g the
      parts were ruled rows that each opened on a table of measures; the
      table is the DIALOG's now (.ffa-part-more opens it, the .ffa-why-tbl
      rules below dress it), so what is left on the page is three things a
      reader holds one at a time — a name, a weight, a score — and that is
      a card's shape. The ground does not change for them: white cards on
      warm white, as the measures are white cards on sand.              */
.ffa-nb-why { padding: 0 0 96px; }
.ffa-nb-why-inner { display: flex; flex-direction: column; gap: 18px; padding-top: 56px; border-top: 1px solid rgba(44, 36, 24, .12); }
/* The head's h2 carries the index's NAME since 6g (the ring card beside it
   keeps only the score); the score is written out once more under it, at
   the size of a section heading.                                       */
.ffa-nb-why-h { max-width: 780px; }
.ffa-nb-why-score { font-size: 26px; font-weight: 700; letter-spacing: -.02em; }
.ffa-nb-why-lead { max-width: 680px; }
.ffa-nb-parts { gap: 20px; margin-top: 10px; }
/* The card: .ffa-card's white and radius, its 40px padding brought in to
   28px and its 18px gap to 8px — one name, one line and one number are
   not a story. The card's colour is the GLYPH's: one neutral ink-soft,
   because the three are not a palette. The name and the score are set in
   ink by their own rules below, so only the glyph and the weight line sit
   back.                                                                 */
.ffa-part { gap: 8px; padding: 28px; color: var(--ink-soft); }
.ffa-part-ic { width: 28px; height: 28px; }
.ffa-why-n { font-size: 20px; font-weight: 700; letter-spacing: -.015em; line-height: 1.25; color: var(--ink); }
.ffa-why-w { font-size: 15px; color: var(--color-text-tertiary); }
.ffa-why-s { font-size: 28px; font-weight: 700; letter-spacing: -.03em; line-height: 1.1; color: var(--ink); }
/* The part's 0-100 figure, drawn. A WIDTH from zero — this is a quantity
   and not a position on a range, which is why it looks nothing like the
   measure card's track below: that one is a rail with two marks on it,
   and confusing the two is the mistake this comment exists to prevent.  */
.ffa-why-bar { display: block; position: relative; height: 8px; margin-top: 8px; border-radius: 999px; background: rgba(44, 36, 24, .08); overflow: hidden; }
.ffa-why-bar-f { display: block; height: 100%; border-radius: 999px; background: var(--accent); }
/* Strain tags — slice 6i. A tag is the index's own aligned percentile, banded:
   low under 50, mid to under 80, high from 80 (the loader owns the cut points).
   The three colour pairs are the vote badges' above, VALUE FOR VALUE — hand-
   picked dark text on a tint. NOT var(--sage) / var(--ochre) as text: on white
   they are 3.2:1 and 2.2:1 and fail AA; these three are 4.9, 5.1 and 5.3.
   Colour never stands alone: every tag starts with the level glyph below, and
   carries words (in the dialog) or a name plus hidden words (on a card).
   A long name WRAPS inside its chip and is never cut — hence a 12px corner and
   not a pill's 999px, which turns a two-line chip into a lozenge.         */
.ffa-part-top-h { margin-top: 6px; font-size: 13px; font-weight: 600; color: var(--ink-soft); }
.ffa-part-top { display: flex; flex-wrap: wrap; gap: 6px; }
/* Slice 6k. The key to the tags, at the end of the why-lead: three of the
   tags' own chips, so the key cannot drift from what it explains. A wrapping
   flex row rather than the spec's display: block; the LABEL takes a line of
   its own (flex-basis: 100%, owner 2026-09-20) so the three chips share one
   line at desktop width and stack cleanly on a phone. And the "See the measures" button sits at the card's foot now
   that a card lists EVERY tagged measure and three cards' chip counts differ
   — .ffa-card is a flex column, so an auto top margin is all it takes. The
   shared .ffa-near-more, .ffa-part-more, .ffa-so-more rule below sets no
   margin-top, so this one-line rule does not have to come after it.      */
.ffa-strain-key { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 10px; }
.ffa-strain-key-l { flex-basis: 100%; font-size: 13px; color: var(--ink-soft); }
.ffa-part-more { margin-top: auto; }
.ffa-strain { position: relative; display: inline-flex; align-items: flex-start; gap: 6px; max-width: 100%; box-sizing: border-box; padding: 4px 10px; border-radius: 12px; font-size: 13px; font-weight: 600; line-height: 1.3; }
.ffa-strain--low { background: rgba(164, 196, 150, .35); color: #4A6B3F; }
.ffa-strain--mid { background: rgba(232, 201, 106, .25); color: #7C6420; }
.ffa-strain--high { background: rgba(196, 101, 74, .18); color: #A8342A; }
.ffa-strain-n { min-width: 0; overflow-wrap: anywhere; }
/* No level glyph since 2026-09-20 (owner): 6i's three small bars read as noise
   at 13px, and the colour carries the level. The words stand behind it — the
   key beside the lead, .ffa-sr on a card chip, the dialog's own column. */
/* "See the measures" is the 6f link-button: its rule is .ffa-near-more's in
   the Around section below, with .ffa-part-more added to that rule.     */

/* The part's measures — the DIALOG's table since 6g. openPart() builds it
   from data.domains with these classes, and the phone block at the foot
   of this file turns its five columns into two inside the sheet.        */
.ffa-why-d { font-size: 15px; color: var(--color-text-tertiary); max-width: 680px; }
.ffa-why-tbl { width: 100%; border-collapse: collapse; font-size: 15px; }
.ffa-why-tbl th { text-align: left; font-size: 13px; font-weight: 600; color: var(--color-text-tertiary); padding: 0 16px 8px 0; border-bottom: 1px solid rgba(44, 36, 24, .12); }
.ffa-why-tbl td { padding: 11px 16px 11px 0; border-bottom: 1px solid rgba(44, 36, 24, .06); vertical-align: top; }
.ffa-why-tbl tr > *:last-child { padding-right: 0; }
.ffa-why-c-n { font-weight: 600; }
.ffa-why-c-s, .ffa-why-c-w, .ffa-why-nodata { color: var(--color-text-tertiary); }
.ffa-why-c-w { white-space: nowrap; }
/* The fifth column since 6i, between "Where it stands" and the weight. The
   tag holds one line on a wide table; the <= 900px block lets it wrap. An
   EMPTY cell stays a cell here: hiding a <td> on a real table shifts every
   later cell one column left. Only the phone grid may drop it.            */
.ffa-why-c-strain .ffa-strain { white-space: nowrap; }
/* Slice 6h — a bar under each standing sentence in the dialog's table. The
   card rule's margin-top: auto means nothing in a table cell, so the space
   under the sentence is said here. At <= 600px .ffa-why-c-s already spans
   both columns, so the phone block needs no rule for this bar.          */
.ffa-why-tbl .ffa-measure-bar { margin-top: 6px; }
.ffa-nb-why-link { font-size: 17px; }

/* 3. The numbers — src/tractdesk-body.html:30-45. Six cards on sand at
      the mockup's 20px rather than .ffa-grid-3's 24px, each one number
      with its label, the county beside it, where the tract stands among
      the county's tracts, and the /map-2 sheet's bar under it.         */
.ffa-nb-numbers { padding: 96px 0; }
.ffa-nb-numbers-inner { display: flex; flex-direction: column; gap: 32px; }
.ffa-nb-measures { gap: 20px; }
.ffa-measure-card { gap: 8px; }
.ffa-measure-v { font-size: 52px; font-weight: 700; letter-spacing: -.04em; line-height: 1; }
.ffa-measure-l { font-size: 17px; font-weight: 600; line-height: 1.25; }
/* The rank sentence's line. One span since 6g — the county's figure moved
   under the bar — and still a flex row, so the template's whitespace round
   the span is never a space on the page.                                */
.ffa-measure-c { font-size: 15px; display: flex; flex-wrap: wrap; }
/* Slice 6h — under each bar, three labels at three FIXED places: the county's
   lowest tract, the middle tract under the tick, the highest. Each cell is
   PLACED, never auto-placed, so an empty end is an empty cell and a centre
   removed by its show_if leaves the high label at the right end and not in
   the middle. No accent blue on any label — the county's figure read as a
   link (owner, 2026-09-17); the blue lives on the small tick glyph before the
   word and nowhere else in the row. The size and colour sit on the CELLS, not
   on the row, so the solo county figure — a sibling of the row, on a card
   with no bar — needs one rule of its own and no more. That rule also
   sets text-align back to left: the solo span carries .ffa-bar-mid for its
   type, and the cell rule's centring is right inside the grid but wrong
   on a flex-column card, where a stretched span would centre the county
   figure under a left-aligned rank sentence (the 6h review). (6d's blue
   .ffa-measure-cty figure and its 6g twin left with the span they styled.) */
.ffa-bar-ends { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; column-gap: 6px; margin-top: 2px; font-variant-numeric: tabular-nums; }
.ffa-bar-end, .ffa-bar-mid { font-size: 13px; line-height: 1.3; color: var(--color-text-tertiary); white-space: nowrap; }
.ffa-bar-end { grid-column: 1; grid-row: 1; justify-self: start; }
.ffa-bar-mid { grid-column: 2; grid-row: 1; justify-self: center; text-align: center; }
.ffa-bar-end--hi { grid-column: 3; justify-self: end; text-align: right; }
.ffa-bar-mid--solo { margin-top: 6px; text-align: left; }
/* The bar's ring and its band, copied small for the key line. aria-hidden in
   the markup: the words carry the meaning.                              */
.ffa-key-mark { display: inline-block; width: 14px; height: 14px; box-sizing: border-box; border: 2px solid #FFFFFF; border-radius: 50%; background: var(--navy); vertical-align: -2px; margin-right: 6px; }
.ffa-key-band { display: inline-block; width: 24px; height: 14px; box-sizing: border-box; border: 1.5px solid #8A8275; border-radius: 4px; vertical-align: -2px; margin-right: 6px; }
/* margin-top: auto, which the artboard can leave out and a page cannot:
   a measure whose label runs to two lines would otherwise sit its bar
   lower than the card beside it. Grid items stretch, so pushing the bar
   down aligns every bar in the row — and it absorbs the mockup's extra
   6px over the card's own gap at the same time. Since 6h the label row
   (.ffa-bar-ends) is the card's LAST child, after the bar: the card is a
   flex column, so auto still takes all the slack above the bar, and the
   bar and the three labels under it move down together; the row is
   gated on the same has_bar as the bar, so a card with a bar has it.   */
.ffa-measure-bar { display: block; position: relative; margin-top: auto; height: 20px; }
/* Round 2 (2026-09-21): the home card's track (spec §7.1). The rail is the
   scale; the outlined band is the middle half of El Paso's tracts — on a
   percentile track that is 25%→75% by construction, so it is one fixed
   rule and no loader key; the ring above both is this tract.           */
.ffa-measure-rail { position: absolute; left: 0; right: 0; top: 7px; height: 6px; border-radius: 3px; background: #E6DDCC; }
.ffa-measure-band { position: absolute; top: 0; left: 25%; width: 50%; height: 20px; border: 1.5px solid #8A8275; border-radius: 6px; box-sizing: border-box; z-index: 2; pointer-events: none; }
/* The bar is the map sheet's bar in this page's vocabulary, the names ffa-.
   Since 6h the TRACK is the county's tracts in RANK order, 0 to 100; since
   round 2 it is the home card's: a 20px box, the rail inside it, the band
   over the rail, the ring over both. The loader sends ONE mark a `left` —
   this tract's percentile; the band's place is CSS's. The ring is centred
   on its own left (translate -50%) so 0% and 100% are the track's two ends,
   and on the track's middle (top 50%) whatever the width. Navy, not the
   accent: the accent left this card with the tick.                    */
.ffa-measure-bar-tract { position: absolute; top: 50%; width: 16px; height: 16px; box-sizing: content-box; border: 2px solid #FFFFFF; border-radius: 50%; background: var(--navy); transform: translate(-50%, -50%); pointer-events: none; z-index: 3; }
/* The MARK's colour is the measure's TONE, which load.neighborhood.php
   computes from the metric's polarity — not from the direction of the
   number, because more is worse on some measures and better on others.
   It moved here from the old fill with slice 6b: the track is the county
   and has no tone of its own, and the thing the tone is about is where
   this tract sits on it. 'even' keeps the navy the base rule gives.    */
.ffa-measure-card--worse .ffa-measure-bar-tract { background: var(--brick); }
.ffa-measure-card--better .ffa-measure-bar-tract { background: var(--sage); }
/* The key, once, in the numbers' head row beside the heading (under the
   grid until 6f). Tertiary and small: it is read once and then never
   again, which is the size the note below it already is.              */
.ffa-measure-key { font-size: 13px; color: var(--color-text-tertiary); }
/* The numbers' head: the key BEFORE the six things it explains.           */
.ffa-nb-numbers-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 24px; }
/* The rank sentence is brick on a `worse` card only. The words carry the
   fact; the colour only points at it.                                     */
.ffa-measure-card--worse .ffa-measure-vs { color: var(--brick); }
.ffa-nb-note { font-size: 14px; color: var(--color-text-tertiary); }
.ffa-nb-note-l { display: inline-flex; font-size: 14px; margin-left: 6px; }

/* 2. Around it — slice 6g. A head row, then a row of kind BUTTONS, then two
      columns: the selected kind's panel left, ONE map right. 6f drew every
      kind as a card of its own in a wrapping grid — a tract with a dozen
      kinds was a dozen cards and no map. Now one kind is read at a time,
      the map draws that kind's dots, and the county comparison sits beside
      them. The panels ship visible and stacked (no script: every kind in
      order, no map); the buttons ship hidden and the script reveals them. */
.ffa-nb-near { padding: 0 0 96px; }
.ffa-nb-near-inner { display: flex; flex-direction: column; gap: 28px; padding-top: 56px; border-top: 1px solid rgba(44, 36, 24, .12); }
.ffa-nb-near-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 32px; }
.ffa-nb-near-copy { display: flex; flex-direction: column; gap: 18px; }
.ffa-nb-near-lead { max-width: 620px; }
.ffa-nb-near-all { flex: none; font-size: 17px; }
/* The buttons: pills that WRAP (a row of actions wraps and the pill itself
   never does), 44px tall for a finger (house rule 8), the kind's tone on
   the glyph as the cards carried it, the label in ink, the count set
   back. font: inherit, because a <button> otherwise brings the browser's
   own face. Pressed is the ink pill with everything on it warm white — a
   state drawn with colour and not with weight, so the row does not shift
   when the selection moves.                                             */
.ffa-kinds { display: flex; flex-wrap: wrap; gap: 10px; }
.ffa-kind { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 8px 14px; border: 1px solid rgba(44, 36, 24, .14); border-radius: 999px; background: #FFFFFF; font: inherit; font-size: 15px; font-weight: 600; color: var(--accent); cursor: pointer; white-space: nowrap; }
.ffa-kind--watch { color: var(--brick); }
.ffa-kind-t { color: var(--ink); }
.ffa-kind-n { font-weight: 500; color: var(--color-text-tertiary); font-variant-numeric: tabular-nums; }
.ffa-kind[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--warmwhite); }
.ffa-kind[aria-pressed="true"] .ffa-kind-t, .ffa-kind[aria-pressed="true"] .ffa-kind-n { color: var(--warmwhite); }
/* A ring the keyboard can see, on every un-buttoned button in this section
   and the score's: the link-buttons have no border of their own to show. */
.ffa-kind:focus-visible, .ffa-part-more:focus-visible, .ffa-near-more:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
/* The two columns. minmax(0, 1fr), so a long explainer or a distance that
   will not break can never push the map off the page; 520px is the hero
   map's column too.                                                     */
.ffa-around { display: grid; grid-template-columns: minmax(0, 1fr) 520px; gap: 40px; align-items: start; }
/* The panels, one per kind, stacked until the script hides all but one.
   A panel's colour is its tone, and the heading's glyph and the bar's mark
   take it as currentColor: the same fact is the same colour on the
   button, in the panel and on the map's pins (slice 6m).                            */
.ffa-kind-panels { display: flex; flex-direction: column; gap: 32px; }
.ffa-kind-panel { display: flex; flex-direction: column; gap: 10px; color: var(--accent); background: #FFFFFF; border-radius: var(--ffa-radius-card); padding: 32px; box-shadow: 0 2px 14px rgba(44,36,24,.06); }
.ffa-kind-panel--watch { color: var(--brick); }
.ffa-kind-h { display: flex; align-items: center; gap: 10px; font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; margin: 0; }
.ffa-kind-h span { color: var(--ink); }
/* Slice 6m: the panel is the measure card's box (white, the card radius —
   the map box's 28px — the .ffa-card shadow, 32px in) and its head is the
   card's vocabulary: the count as .ffa-measure-v, the page's label as
   .ffa-measure-l, the rank sentence as .ffa-measure-vs. The panel's own
   colour is its TONE, for the glyph and the ring, so the three texts say
   ink here; the sentence turns brick on data-cmp="worse" alone — the
   loader's cmp_tone, 'worse' only for a watched kind with MORE here than
   most tracts, the measure card's --worse in the panel's terms.         */
.ffa-kind-panel .ffa-measure-v, .ffa-kind-panel .ffa-measure-l, .ffa-kind-panel .ffa-measure-vs { color: var(--ink); }
.ffa-kind-panel .ffa-measure-vs[data-cmp="worse"] { color: var(--brick); }
/* The county comparison: the sentence, the typical line where there is no
   bar, and the measure card's own bar under them, spanning the card as a
   card's does (6g's 420px cap left with 6m). The mark on it is the panel's
   tone and not the measure card's navy: here the tone is the kind's, and
   the tract is the thing being placed on the track.                     */
.ffa-kind-cmp { display: flex; flex-direction: column; gap: 6px; }
.ffa-kind-cmp-t { font-size: 15px; color: var(--ink-soft); }
.ffa-kind-cmp .ffa-measure-bar { margin-top: 8px; }
.ffa-kind-panel .ffa-measure-bar-tract { background: currentColor; }
.ffa-kind-viol { font-size: 15px; font-weight: 600; color: var(--ink); }
.ffa-kind-explain { font-size: 15px; line-height: 1.5; color: var(--ink-soft); max-width: 560px; }
/* The row: one place with its distance. Shared by the panels and by the
   dialog's full list; the panel and the dialog each restate its padding. */
.ffa-nearby-row { display: flex; justify-content: space-between; align-items: center; gap: 20px; padding: 16px 0; border-bottom: 1px solid rgba(44, 36, 24, .12); }
.ffa-nearby-t { font-size: 17px; font-weight: 600; line-height: 1.25; }
.ffa-nearby-s { font-size: 15px; text-align: right; }
/* A row's note — the EPA quarters line — on a line of its own under the
   label, in the watch tone, in the panel and in the dialog alike.       */
.ffa-nearby-note { display: block; font-size: 13px; font-weight: 500; color: var(--brick); }
/* The panel's rows: the 6f card's compact row, a notch larger now that it
   has a column to itself, ruled ABOVE so the first row's line sits under
   the text before it, and a distance that never breaks.                 */
.ffa-kind-panel .ffa-nearby-row { padding: 8px 0; border-bottom: 0; border-top: 1px solid rgba(44, 36, 24, .08); gap: 12px; align-items: baseline; }
.ffa-kind-panel .ffa-nearby-t { font-size: 15px; font-weight: 500; color: var(--ink); }
.ffa-kind-panel .ffa-nearby-s { font-size: 14px; white-space: nowrap; }
.ffa-near-nearest { font-size: 14px; color: var(--ink-soft); }
/* Slice 6m: once around() has drawn the map (data-ffa-mapped on .ffa-around)
   a row in the CARD's list points at its pin — a pointer, and a chevron on
   the distance span's ::after (a third flex item would spread the row's
   space-between). A page without a map keeps plain rows that promise
   nothing.                                                              */
.ffa-around[data-ffa-mapped="1"] .ffa-kind-panel .ffa-nearby-row { cursor: pointer; }
.ffa-around[data-ffa-mapped="1"] .ffa-kind-panel .ffa-nearby-s::after { content: " \203A"; color: var(--color-text-tertiary); }
/* The link-button, three times over: the panel's "and N more", the
   standout's "Read more", the part card's "See the measures" (1b above). */
.ffa-near-more, .ffa-part-more, .ffa-so-more { font: inherit; font-size: 14px; font-weight: 500; color: var(--accent); background: none; border: 0; padding: 0; cursor: pointer; text-align: left; align-self: flex-start; }
.ffa-near-more:hover, .ffa-part-more:hover, .ffa-so-more:hover { color: var(--navy); text-decoration: underline; }
.ffa-near-more::after, .ffa-part-more::after, .ffa-so-more::after { content: " \203A"; }
/* The map mount — the hero's pattern (.ffa-nb-map, below): the dashed
   placeholder fills it until Leaflet lands and stays if it never does.
   STICKY, so a long panel scrolls past a map that keeps its dots in view;
   a sticky box is a positioned one, which is all the placeholder's
   inset: 0 needs. height: auto on the placeholder for the reason
   .ffa-nb-map's rule gives — inset sets both ends.                      */
/* Slice 6m: the map and its key are ONE sticky column, so a long panel
   scrolls past a map that keeps its pins AND its key in view. The mount is
   position: relative — the placeholder inside it is absolute, and a mount
   that is merely static (the old <= 900 rule) did not anchor it.        */
.ffa-around-col { position: sticky; top: 24px; display: flex; flex-direction: column; gap: 12px; }
.ffa-around-map { position: relative; height: 420px; border-radius: 28px; overflow: hidden; border: 1px solid rgba(44, 36, 24, .12); box-sizing: border-box; }
.ffa-around-map .ffa-nb-map-ph { position: absolute; inset: 0; height: auto; border-radius: 28px; }
.ffa-around-map .leaflet-container { font: inherit; font-size: 13px; }
.ffa-around-map .leaflet-control-attribution { font-size: 10px; }
/* The key under the map, in the numbers' key's voice (13px tertiary): the
   pin in the selected kind's tone with that kind's name (the script fills
   it), the dashed half mile, the outlined tract with the outline's 0.06
   fill. The glyphs are aria-hidden in the markup: the words carry it.   */
.ffa-map-key { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 0; font-size: 13px; color: var(--color-text-tertiary); }
.ffa-map-key-t { font-weight: 600; color: var(--ink-soft); }
.ffa-map-key-i { display: inline-flex; align-items: center; gap: 6px; }
.ffa-key-pin { display: inline-block; width: 12px; height: 15px; color: var(--accent); }
.ffa-key-pin--watch { color: var(--brick); }
.ffa-key-pin svg { display: block; width: 12px; height: 15px; }
.ffa-key-circle { display: inline-block; width: 14px; height: 14px; box-sizing: border-box; border: 1.5px dashed var(--navy); border-radius: 50%; }
.ffa-key-tract { display: inline-block; width: 16px; height: 14px; box-sizing: border-box; border: 2px solid var(--navy); border-radius: 3px; background: rgba(42, 65, 89, .06); }
/* The pins on the around map (a Leaflet divIcon; the host div's width and
   height are Leaflet's inline 24x30): the filled sprite pin in the kind's
   tone, a soft drop shadow, and a lit state that grows from the TIP so the
   point stays on the place. Its own class, not the pin_map module's disc.   */
.ffa-around-pin { width: 24px; height: 30px; color: var(--accent); }
.ffa-around-pin--watch { color: var(--brick); }
.ffa-around-pin svg { display: block; width: 24px; height: 30px; filter: drop-shadow(0 1px 1px rgba(0,0,0,.25)); transform-origin: 50% 100%; transition: transform .12s ease; }
.ffa-around-pin--lit svg { transform: scale(1.2); }
/* What is missing: one quiet line under the two columns.                 */
.ffa-near-missing { font-size: 15px; color: var(--color-text-tertiary); }

/* The land — a row of its own since 6f. auto-fit, so a tract with a picture
   and no land cover (or the reverse) gets one full column, not a hole.    */
.ffa-nb-land { display: flex; flex-direction: column; gap: 22px; margin-top: 72px; }
.ffa-nb-land-head { display: flex; flex-direction: column; gap: 10px; }
.ffa-nb-visual-h { font-size: 40px; }
.ffa-nb-land-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 40px; align-items: center; }
.ffa-nb-sat-wrap { position: relative; }
.ffa-nb-sat { display: block; width: 100%; height: auto; border-radius: 24px; }
/* The whole picture is the click target once the magnifier is revealed. */
.ffa-nb-sat--zoom { cursor: zoom-in; }
.ffa-nb-sat-open { position: absolute; top: 14px; right: 14px; width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center; border: 0; border-radius: 12px; background: rgba(255, 255, 255, .92); color: var(--ink); cursor: pointer; box-shadow: 0 1px 6px rgba(44, 36, 24, .2); }
.ffa-lc { display: flex; flex-direction: column; gap: 12px; }
.ffa-lc-h { font-size: 13px; color: var(--color-text-tertiary); }
/* One labelled bar per part, biggest first. The fill is the STORED percent
   drawn on this tract's shared axis (lc_axis_max, since 6j); the colours are
   css/map.css's, by the same key.                                          */
.ffa-lc-list { display: flex; flex-direction: column; gap: 10px; }
.ffa-lc-row { display: grid; grid-template-columns: 150px minmax(0, 1fr) 48px; gap: 14px; align-items: center; font-size: 15px; }
.ffa-lc-track { display: block; position: relative; isolation: isolate; height: 10px; border-radius: 999px; background: rgba(44, 36, 24, .08); }
.ffa-lc-fill { display: block; position: relative; z-index: 1; height: 100%; min-width: 2px; border-radius: 999px; }
.ffa-lc-v { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
/* The county on the track — slice 6j, restyled in 6k. The band is where the
   middle half of El Paso tracts fall: an OUTLINED box, 20px on the 10px track
   and BEHIND the fill (z-index 0 under the fill's 1) — the owner's own ruling
   of 2026-09-20, after trying it in front: the bar stays whole, and the box
   shows above and below it and wherever the bar does not reach. Transparent,
   so the track's colour is never tinted. box-sizing keeps band_left / band_width meaning the
   box's outer edges; a band whose p25 equals its p75 draws as a 2px line —
   the middle half of the county sits on one number. The median tick left the
   chart in 6k (owner's restyle); tick_left stays in the payload, unprinted. */
.ffa-lc-band { position: absolute; top: 50%; z-index: 0; box-sizing: border-box; height: 20px; border: 1px solid #bbb; border-radius: 3px; background: transparent; transform: translateY(-50%); pointer-events: none; }
.ffa-lc-key { font-size: 12px; line-height: 1.5; color: var(--ink-soft); }
/* The swatch is the mark: the same outline, at a size that reads as a swatch. */
.ffa-lc-key-band { display: inline-block; box-sizing: border-box; width: 24px; height: 14px; margin-right: 6px; border: 1px solid #bbb; border-radius: 3px; background: transparent; vertical-align: -1px; }
/* The axis row sits on the row's own grid, so 0 and the end stand under the
   track's two ends. A full track is THIS tract's axis, not 100%. */
.ffa-lc-axis { display: grid; grid-template-columns: 150px minmax(0, 1fr) 48px; gap: 14px; font-size: 12px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.ffa-lc-axis span { grid-column: 2; grid-row: 1; }
/* Both spans share one cell: without this the zero's box stretches under the
   right-hand label. */
.ffa-lc-axis-0 { justify-self: start; }
.ffa-lc-axis-max { justify-self: end; }
/* The eight land-cover colours. Since 2026-09-20 (owner) HUE says the kind of
   surface and LIGHTNESS says which one: roofs are warm (umber, sand), asphalt is
   cool (charcoal, pale blue-grey), plants are green, bare soil is ochre. Until then
   dark rooftop, asphalt road and asphalt parking were three greys a step apart
   and could not be told apart in the waffle. css/map-2.css carries the SAME
   eight values for the map sidebar, and t9 / t10 hold the two files to each
   other. The LIVE css/map.css is frozen until the map cutover (t7 §24) and keeps
   the old greys till then; the cutover renames map-2.css over it. */
.ffa-lc-seg--pct_dark_rooftop     { background: #6E5A4B; }
.ffa-lc-seg--pct_light_rooftop    { background: #CBBFAE; }
.ffa-lc-seg--pct_asphalt_road     { background: #33383D; }
.ffa-lc-seg--pct_asphalt_parking  { background: #A9B7C6; }
.ffa-lc-seg--pct_tree_canopy      { background: #7A9A6D; }
.ffa-lc-seg--pct_grass_turf       { background: #98c87a; }
.ffa-lc-seg--pct_bare_soil        { background: #D4A843; }
.ffa-lc-seg--pct_other_impervious { background: #b85450; }
.ffa-lc-seg--rest { background: rgba(44, 36, 24, .08); }
/* The waffle — slice 6k (6j's square of strips until then). 100 cells, 10 by
   10, one for each 1% of the ground, in the bars' colours and order. The WRAP
   floats and holds the caption; the grid inside it is the view container. */
.ffa-lc-waffle-wrap { float: right; width: 168px; margin: 12px 0 12px 24px; }
.ffa-lc-waffle { display: grid; grid-template-columns: repeat(10, 1fr); gap: 2px; aspect-ratio: 1; }
.ffa-lc-cell { display: block; aspect-ratio: 1; border-radius: 2px; }
.ffa-lc-waffle-cap { margin-top: 8px; font-size: 12px; line-height: 1.4; color: var(--ink-soft); text-align: center; }

/* What this part of town is like — a reading column, not the wrap's width.
   A flow root since 6j, not a flex column: float does nothing on a flex item,
   and the waffle's wrap floats right of the paragraph. flow-root also
   contains the float when the paragraph is shorter than the waffle. The 12px
   gap became margins, which hold because css/style.css's `* { margin: 0 }` is
   outranked by any class selector. */
.ffa-nb-ctx { display: flow-root; margin-top: 72px; }
.ffa-nb-ctx > * + * { margin-top: 12px; }
.ffa-nb-ctx-h { font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; margin: 0; }
.ffa-nb-ctx-p { max-width: 680px; }
/* The note keeps only its column since 6h: its 13px tertiary type is
   .ffa-ai-note's, which the markup gives it beside this class.          */
.ffa-nb-ctx-note { max-width: 680px; }
/* Slice 6l — the written read over the six cards. The reading column of
   .ffa-nb-ctx-p, so the paragraph over "The numbers." is the same measure
   as the one over "What this part of town is like". The section is a flex
   column with a 32px gap, so 20px under the head row and 28px over the grid
   are these two negative margins.                                       */
.ffa-nb-num-note { max-width: 680px; margin: -12px 0 -4px; }
.ffa-nb-num-note > * + * { margin-top: 8px; }
/* Slice 6h — the two lines that say an AI wrote something share one look and
   one glyph: a generic four-point sparkle in the eyebrow's terracotta. */
/* .ffa-ai-note ALREADY EXISTS (css/ffa.css:734 — 13px, 1.6, tertiary) and styles page/page.agenda-item.php:402.
   It is NOT edited and NOT redefined: the two neighborhood notes reuse it for their type and take this
   modifier for the sparkle's layout. */
.ffa-ai-note--spark { display: flex; align-items: flex-start; gap: 6px; line-height: 1.45; }
.ffa-ai-note--spark .ffa-ic { width: 14px; height: 14px; margin-top: 2px; color: var(--terracotta); }
.ffa-nb-so-ai { max-width: 720px; }
/* The map mount, and the placeholder that lives inside it. Since slice 6b
   the Nearby map is a live Leaflet map; the dashed .ffa-ph block is what
   the reader sees while Leaflet is on its way from unpkg and what they
   keep if it never arrives, so the two share ONE box at every width and
   the page's rhythm does not change when the map resolves.
   `position: relative` is what lets the placeholder fill the mount;
   `overflow: hidden` is what puts the tiles inside the 32px radius. The
   hairline is the ink-at-12% the page rules its sections with.        */
.ffa-nb-map { position: relative; height: 400px; border-radius: 32px; overflow: hidden; border: 1px solid rgba(44, 36, 24, .12); box-sizing: border-box; }
.ffa-nb-map-ph { height: 400px; border-radius: 32px; }
/* `height: auto` is not decoration: `inset: 0` sets top AND bottom, and a
   placeholder still carrying the 400px of the rule above would keep its
   own height and overflow the 320px and 240px boxes below.          */
.ffa-nb-map .ffa-nb-map-ph { position: absolute; inset: 0; height: auto; }
/* Leaflet's stylesheet gives .leaflet-container its own Helvetica stack.
   One tooltip and one attribution line in it would be the only type on
   this page that is not the site's.                                  */
.ffa-nb-map .leaflet-container { font: inherit; font-size: 13px; }
.ffa-nb-map .leaflet-control-attribution { font-size: 10px; }

/* 4. Where this tract stands out — warm white between the sand and the
      dark band, like the breakdown: a hairline, not a ground of its own. */
.ffa-nb-standouts { padding: 96px 0; }
.ffa-nb-so-inner { display: flex; flex-direction: column; gap: 18px; }
.ffa-nb-so-lead { max-width: 720px; }
.ffa-nb-so-cards { gap: 20px; margin-top: 14px; }
.ffa-standout { gap: 10px; }
.ffa-standout-m { color: var(--accent); }
/* The standout's reason, clamped to four lines; the rest is the dialog's. */
.ffa-standout-r { font-size: 17px; font-weight: 600; line-height: 1.3; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; line-clamp: 4; overflow: hidden; }
.ffa-standout-l { margin-top: auto; font-size: 15px; align-items: baseline; gap: 20px; flex-wrap: wrap; }

/* The dialog. NO padding on the element itself — see the template.        */
.ffa-dialog { padding: 0; margin: auto; border: 0; border-radius: var(--ffa-radius-card); width: min(640px, calc(100% - 32px)); max-height: 80vh; background: #FFFFFF; color: var(--ink); box-shadow: 0 24px 80px rgba(44, 36, 24, .35); overflow: hidden; }
/* The wide variant, slice 6g: the picture and a part's measures table.
   Only the width. margin: auto is .ffa-dialog's — do not unset it
   (css/style.css resets every margin, and a modal's centring IS that
   margin). Before the phone block below, so its bottom sheet still wins
   there: same specificity, later wins.                                  */
.ffa-dialog--wide { width: min(1100px, calc(100% - 32px)); }
.ffa-dialog::backdrop { background: rgba(28, 24, 18, .55); }
.ffa-dialog-in { display: flex; flex-direction: column; gap: 16px; padding: 32px; max-height: 80vh; box-sizing: border-box; overflow-y: auto; }
.ffa-dialog-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; }
.ffa-dialog-h { font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; margin: 0; }
.ffa-dialog-x { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border: 0; border-radius: 50%; background: rgba(44, 36, 24, .07); color: var(--ink); cursor: pointer; flex: none; }
.ffa-dialog-body { display: flex; flex-direction: column; gap: 14px; }
.ffa-dialog-lede { font-size: 19px; font-weight: 600; line-height: 1.35; }
.ffa-dialog-p { font-size: 17px; }
.ffa-dialog-sub { font-size: 14px; color: var(--color-text-tertiary); }
.ffa-dialog-list { list-style: none; margin: 0; padding: 0; }
.ffa-dialog-list .ffa-nearby-row { padding: 12px 0; }
.ffa-dialog-img { display: block; width: 100%; height: auto; border-radius: 18px; }
.ffa-dialog-foot { font-size: 17px; }

/* 5. Decisions that touch this tract — src/tractdesk-body.html:66-77.
      The dark band, three cards, and the whole card is the link. The two
      colour rules are the price of that: the dark ground gives every
      anchor inside it the sky blue and an underline on hover, which on a
      card whose children are all spans would tint and underline the card
      itself. Two classes wide, because the rules they answer are.       */
.ffa-nb-decisions { padding: 120px 0; }
.ffa-nb-dec-inner { display: flex; flex-direction: column; gap: 32px; }
.ffa-nb-dec-head { display: flex; flex-direction: column; gap: 12px; }
.ffa-nb-dec-cards { gap: 20px; }
.ffa-nb-dec-cards .ffa-nb-dec, .ffa-nb-dec-cards .ffa-nb-dec:hover { color: var(--sand); text-decoration: none; }
.ffa-nb-dec { gap: 10px; }
.ffa-nb-dec-when { align-self: flex-start; background: rgba(160, 203, 224, .2); color: var(--sky-light); }
.ffa-nb-dec-t { font-size: 22px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; }
.ffa-nb-dec-l { font-size: 15px; }

/* 6. No such neighborhood. The shared .ffa-missing carries the sentence;
      this adds the way out on the line under it.                       */
.ffa-nb-missing-l { display: flex; margin-top: 10px; font-size: 19px; }

/* ── Grouped lists and stat cards, at every width ──────────────────
   The phone vocabulary's .ffa-group / .ffa-row / .ffa-badge / .ffa-cap
   and .ffa-stat-card were ported in slice 1 inside the <= 600px block
   (.ffa-stat-card is gone since 2026-09-22 — see below),
   which is where the artboards use them. The agenda item uses four of
   them on the DESKTOP artboard too — the tract's numbers are a card grid
   (src/agendadesk-body.html:56-61) and the roll is a list of rows — so
   the base sizes live here and the phone block below keeps overriding
   them at <= 600px, exactly as it did before.

   .ffa-group-h, .ffa-chev and .ffa-search joined them when /meetings was
   rewritten (slice 3, task 5): that page is the phone artboard at every
   width — a 680px column of grouped lists — so its group headings,
   chevrons and search field are needed above 600px too. They are MOVED,
   not copied: each reads the same at both sizes, and a second identical
   rule in the block below would be two places to change one number.
   .ffa-chev also picked up the stroke the artboard hangs on the path as
   presentation attributes, so a chevron in a template is markup only. */
.ffa-group { background: #FFFFFF; border-radius: 18px; overflow: hidden; display: flex; flex-direction: column; }
.ffa-sand .ffa-group { box-shadow: 0 2px 14px rgba(44, 36, 24, .06); }
.ffa-row { display: flex; align-items: center; gap: 12px; padding: 14px 20px; min-height: 44px; box-sizing: border-box; border-bottom: 1px solid rgba(44, 36, 24, .1); }
.ffa-row:last-child { border-bottom: 0; }
.ffa-row-t { font-size: 17px; letter-spacing: -.01em; line-height: 1.25; }
.ffa-row-s { font-size: 14px; color: var(--color-text-tertiary); margin-top: 2px; }
.ffa-cap { font-size: 13px; color: var(--color-text-tertiary); }
.ffa-group-h { font-size: 13px; font-weight: 600; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: .06em; padding: 0 16px 6px; }
.ffa-chev { flex: none; width: 8px; height: 14px; stroke: #B5AC9C; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.ffa-search { display: flex; align-items: center; gap: 8px; background: rgba(44,36,24,.07); border-radius: 12px; padding: 9px 12px; font-size: 17px; color: var(--color-text-tertiary); }
.ffa-search svg { width: 18px; height: 18px; stroke: var(--color-text-tertiary); fill: none; stroke-width: 2; stroke-linecap: round; }
.ffa-badge { display: inline-flex; align-items: center; border-radius: 999px; padding: 4px 10px; font-size: 12px; font-weight: 600; }
/* .ffa-stat-card left on 2026-09-22: its one reader, the agenda item's tract
   cards, wears .ffa-card .ffa-measure-card now (see "The half mile around
   it"). */

/* ── Small fixes ───────────────────────────────────────
   /fixes — page/page.fixes.php (spec docs/superpowers/specs/
   2026-09-26-city-fixes-ledger-design.md §5), the notes the same
   findings print on a CPC meeting page and a CPC item page (§6), and
   the /sources line (§6.3). No mockup: the page is this file's own
   vocabulary — the Why-go intro, a .ffa-stat band on sand, white cards,
   the dark closing band. The two new shapes are the three-step glance
   and the log list. The pills reuse the status colours above.        */

.ffa-fx-intro { display: flex; flex-direction: column; gap: 22px; padding: 96px 0; }
.ffa-fx-h { max-width: 900px; }
.ffa-fx-lead { max-width: 720px; }
.ffa-fx-empty { margin-top: 8px; }
.ffa-fx-audit { padding: 96px 0; }
.ffa-fx-audit-inner { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 12px; }
.ffa-fx-line { max-width: 640px; margin-top: 12px; }
.ffa-fx-list { display: flex; flex-direction: column; gap: 56px; padding: 96px 0 120px; }
.ffa-fx-group { display: flex; flex-direction: column; gap: 20px; }
.ffa-fx-card { padding: 0; gap: 0; }
.ffa-fx-sum { display: flex; flex-direction: column; gap: 14px; padding: 36px 40px; cursor: pointer; list-style: none; }
.ffa-fx-sum::-webkit-details-marker { display: none; }
.ffa-fx-pills { display: flex; flex-wrap: wrap; gap: 8px; }
.ffa-fx-pill--found { background: rgba(44, 36, 24, .08); color: var(--ink-soft); }
.ffa-fx-pill--raised { background: rgba(232, 201, 106, .35); color: #7C6420; }
.ffa-fx-pill--partly_fixed { background: var(--sky-light); color: var(--navy); }
.ffa-fx-pill--fixed { background: rgba(164, 196, 150, .35); color: #46603C; }
.ffa-fx-title { font-size: 28px; line-height: 1.15; letter-spacing: -.02em; font-weight: 700; margin: 0; color: var(--ink); }
.ffa-fx-missing { font-size: 17px; }
.ffa-fx-steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-top: 6px; }
.ffa-fx-step { display: flex; flex-direction: column; gap: 4px; padding: 12px 14px; border-radius: 14px; background: var(--sand); }
.ffa-fx-step-l { font-size: 12px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-tertiary); }
.ffa-fx-step-d { font-size: 15px; font-weight: 600; line-height: 1.3; color: var(--color-text-tertiary); }
.ffa-fx-step.is-done .ffa-fx-step-d { color: var(--ink); }
.ffa-fx-more { font-size: 17px; font-weight: 500; color: var(--accent); }
.ffa-fx-more::after { content: " \203A"; display: inline-block; margin-left: 4px; transition: transform .15s; }
.ffa-fx-card[open] .ffa-fx-more::after { transform: rotate(90deg); }
.ffa-fx-body { display: flex; flex-direction: column; gap: 22px; padding: 28px 40px 40px; border-top: 1px solid rgba(44, 36, 24, .1); }
.ffa-fx-sec { display: flex; flex-direction: column; gap: 6px; }
.ffa-fx-sec-h { font-size: 13px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-tertiary); margin: 0; }
.ffa-fx-sec-b { font-size: 17px; }
.ffa-fx-log, .ffa-fx-srcs { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; font-size: 17px; line-height: 1.5; color: var(--ink-soft); }
.ffa-fx-log li, .ffa-fx-srcs li { display: flex; flex-direction: column; gap: 2px; }
.ffa-fx-log-d { font-weight: 600; color: var(--ink); }
.ffa-fx-log a::after, .ffa-fx-srcs a::after { content: " \203A"; }
.ffa-fx-edited, .ffa-fx-checked { font-size: 13px; color: var(--color-text-tertiary); }
.ffa-fx-how { padding: 120px 0; }
.ffa-fx-how-inner { display: flex; flex-direction: column; gap: 22px; }
.ffa-fx-how-b { max-width: 760px; }

/* The ledger's notes: a CPC meeting page, above the provenance line; a CPC
   item page with no vote, where the vote card would be (spec §6). One
   quiet line each, the link a sentence with a chevron (house rule 5). */
.ffa-fixnotes { display: flex; flex-direction: column; gap: 8px; padding-top: 40px; }
.ffa-fixnote { font-size: 15px; line-height: 1.55; color: var(--ink-soft); }
.ffa-fixnote a { margin-left: 4px; font-weight: 500; white-space: nowrap; }
.ffa-fixnote a::after { content: " \203A"; }
/* On the item page the note stands where the vote card would, so it takes the vote
   section's rhythm: the intro's 56px above, the vote's 96px below — on a sparse item
   the next band is the dark speak band, and 8px left the line sitting on it.        */
.ffa-ai-fixnotes { padding-top: 0; padding-bottom: 96px; }

/* The /sources line under the cards (spec §6.3). */
.ffa-src-fixes { margin-top: 32px; font-size: 17px; }

/* ── Video spot ────────────────────────────────────────
   The block under a page's hero (page/partial.watch.php), the player
   sheet (js/watch.js) and the page /video/{slug} (page/page.video.php).
   Spec docs/superpowers/specs/2026-09-28-motion-graphics-program.md
   §4.3–§4.5, board 1 option B and board 2; plan
   docs/superpowers/plans/2026-09-28-video-spot.md. No mockup numbers:
   the vocabulary's own card, pill, segmented control and dialog, and
   the 4:5 poster of spec D1.

   The block is the intro section's LAST element, on that section's
   ground. The lead card is the house card (.ffa-card: white on a light
   ground, --ffa-card-dark on the dark issue hero) and the whole card is
   the link — never a pill. Most intros are .ffa-wrap, whose link rules
   would paint every word of a card-link blue and underline it on hover;
   the two .ffa-wt a rules below take that back, and win because they
   are written later at the same weight.                                */

.ffa-wt { display: flex; flex-direction: column; gap: 14px; margin-top: 12px; min-width: 0; max-width: 100%; }
.ffa-wt a, .ffa-wt a:hover { color: inherit; text-decoration: none; }
/* A full-width row under both columns where the intro is a grid: the
   home hero, the This Week hero and the case hero (css/style.css).     */
.ffa-hm-hero > .ffa-wt, .ffa-tw-intro > .ffa-wt { grid-column: 1 / -1; margin-top: -24px; }
.cs-hero > .ffa-wt { grid-column: 1 / -1; margin-top: 1rem; }
/* The issue hero is full-bleed; the page hands the block its wrap
   (ffa-wrap ffa-wrap--wide), and the band ends under it.              */
.ffa-ig-open > .ffa-wt { margin-top: 0; padding-bottom: 64px; }
/* A centred hero — the home page's solo state, an issue opener with no
   status card — centres the block too, and a card's own words always
   read from the left (the local review, plan C15).                    */
.ffa-hm-hero.is-solo > .ffa-wt, .ffa-ig-open-inner:not(:has(> .ffa-ig-status:not(:empty))) ~ .ffa-wt { align-items: center; }
.ffa-wt-lead, .ffa-wt-card { text-align: left; }

.ffa-wt-lead { flex-direction: row; align-items: center; gap: 20px; padding: 14px 28px 14px 14px; max-width: 560px; }
.ffa-wt-poster { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover; background: var(--sand); }
.ffa-wt-lead .ffa-wt-poster { flex: none; width: 112px; border-radius: 16px; }
.ffa-wt-lead-copy { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; min-width: 0; }
.ffa-wt-title { font-size: 22px; line-height: 1.2; letter-spacing: -.01em; font-weight: 700; color: var(--ink); }
.ffa-wt-meta { font-size: 15px; line-height: 1.4; color: var(--ink-soft); }
.ffa-wt-go { display: inline-flex; align-items: center; gap: 8px; margin-top: 4px; font-size: 17px; font-weight: 600; color: var(--accent); }
.ffa-wt-play { width: 14px; height: 14px; fill: currentColor; }
.ffa-wt a:hover .ffa-wt-title, .ffa-wt a:hover .ffa-wt-card-t { text-decoration: underline; }
.ffa-wt-more { font-size: 13px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-soft); margin-top: 4px; }
/* The shelf scrolls sideways and the next card peeks (spec §4.3).      */
.ffa-wt-shelf { list-style: none; margin: 0; padding: 0 0 6px; display: flex; gap: 14px; overflow-x: auto; scroll-snap-type: x proximity; max-width: 100%; }
.ffa-wt-slot { flex: none; width: 112px; scroll-snap-align: start; }
.ffa-wt-card { display: flex; flex-direction: column; gap: 6px; }
.ffa-wt-thumb { position: relative; display: block; }
.ffa-wt-card .ffa-wt-poster { border-radius: 14px; }
.ffa-wt-len { position: absolute; right: 6px; bottom: 6px; padding: 4px 6px; border-radius: 6px; background: rgba(29, 26, 22, .82); color: var(--sand); font-size: 13px; font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; }
.ffa-wt-card-t { font-size: 15px; line-height: 1.3; font-weight: 600; color: var(--ink); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.ffa-wt-draft { align-self: flex-start; }
/* The dark issue hero: the same block in the dark ground's colours.   */
.ffa-dark .ffa-wt-title, .ffa-dark .ffa-wt-card-t { color: var(--sand); }
.ffa-dark .ffa-wt-meta, .ffa-dark .ffa-wt-more { color: #B9AF9E; }
.ffa-dark .ffa-wt-go { color: var(--sky-light); }
.ffa-dark .ffa-wt-poster { background: var(--ffa-card-dark); }
.ffa-dark .ffa-wt-draft { background: rgba(245, 240, 232, .12); color: var(--sand); }

/* The sheet: a modal <dialog>. A centered window at 900px and up, video
   left and words right; under 900px it slides up from the bottom (the
   900px block below). No padding on the <dialog> itself: a click whose
   target IS the dialog is a click on the backdrop (.ffa-dialog's rule). */
.ffa-wt-sheet { padding: 0; margin: auto; border: 0; border-radius: var(--ffa-radius-card); width: min(1040px, calc(100% - 32px)); max-height: 90vh; background: #FFFFFF; color: var(--ink); box-shadow: 0 24px 80px rgba(44, 36, 24, .35); overflow: hidden; }
.ffa-wt-sheet::backdrop { background: rgba(28, 24, 18, .55); }
@keyframes ffa-wt-fade { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
@keyframes ffa-wt-up { from { transform: translateY(100%); } to { transform: none; } }
/* Motion only for a reader who has not asked for less: the 900px block
   swaps the keyframes through --ffa-wt-in, and sets nothing else, so a
   reduce-motion reader gets no animation at any width.               */
@media (prefers-reduced-motion: no-preference) {
  .ffa-wt-sheet[open] { animation: var(--ffa-wt-in, ffa-wt-fade) .24s ease-out; }
}
.ffa-wt-in { display: flex; flex-direction: column; gap: 16px; padding: 28px; max-height: 90vh; box-sizing: border-box; }
.ffa-wt-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; }
.ffa-wt-h { font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; margin: 0; }
.ffa-wt-x, .ffa-wt-pp, .ffa-wt-mute { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 40px; height: 40px; padding: 0; border: 0; border-radius: 50%; background: rgba(44, 36, 24, .07); color: var(--ink); cursor: pointer; }
.ffa-wt-ico { width: 16px; height: 16px; fill: currentColor; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.ffa-wt-x .ffa-wt-ico { fill: none; stroke-width: 1.8; }
.ffa-wt-switches { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px; }
/* .ffa-seg styles spans and links; the sheet's segments are buttons.  */
.ffa-wt-switches .ffa-seg button { padding: 8px 18px; border: 0; border-radius: 9px; background: none; font: inherit; color: var(--ink-soft); cursor: pointer; }
/* The pressed one keeps .ffa-seg .ffa-on's look, which the rule above
   out-ranks (0,2,1 over 0,2,0) and would otherwise hide.             */
.ffa-wt-switches .ffa-seg button.ffa-on { background: #FFFFFF; color: var(--ink); font-weight: 600; }
.ffa-wt-body { display: grid; grid-template-columns: minmax(0, 420px) minmax(0, 1fr); gap: 32px; min-height: 0; flex: 1; }
.ffa-wt-stage, .ffa-wt-side { min-height: 0; overflow-y: auto; }
.ffa-wt-status { font-size: 17px; line-height: 1.5; color: var(--ink-soft); padding: 24px 0; }
/* Empty, it takes no room but stays rendered: a role="status" region
   that is display: none when its words arrive is often not announced. */
.ffa-wt-status:empty { margin: 0; padding: 0; }
/* 4:5, the site frame (spec D1). The width follows the window's height
   so the whole frame fits on a short screen.                           */
.ffa-wt-frame { width: min(100%, calc((90vh - 230px) * .8)); aspect-ratio: 4 / 5; margin: 0 auto; border-radius: 18px; overflow: hidden; background: var(--ffa-ink-dark); }
/* Step through stacks its count, the words and Back / Next under the
   frame, about 150px more than Watch's bar, so its frame leaves room
   for them: Back / Next stay in view without scrolling the column
   (the local review). 200px is the floor on a very short screen.      */
.ffa-wt-step .ffa-wt-frame { width: min(100%, max(200px, calc((90vh - 400px) * .8))); }
.ffa-wt-video, .ffa-wt-clip, .ffa-wt-still { display: block; width: 100%; height: 100%; object-fit: contain; }
.ffa-wt-bar { display: flex; align-items: center; gap: 12px; margin-top: 12px; }
.ffa-wt-track { position: relative; flex: 1; display: flex; align-items: center; min-width: 0; }
.ffa-wt-seek { width: 100%; margin: 0; accent-color: var(--terracotta); }
/* A mark at each scene's start (spec §4.4), over the track.            */
.ffa-wt-marks { position: absolute; left: 0; right: 0; top: 50%; height: 12px; margin-top: -6px; pointer-events: none; }
.ffa-wt-mark { position: absolute; top: 0; width: 2px; height: 12px; margin-left: -1px; border-radius: 1px; background: var(--color-text-tertiary); }
.ffa-wt-time { font-size: 15px; color: var(--ink-soft); white-space: nowrap; font-variant-numeric: tabular-nums; }
.ffa-wt-step-top { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 10px; font-size: 15px; color: var(--ink-soft); }
.ffa-wt-replay { padding: 0; border: 0; background: none; font: inherit; font-weight: 600; color: var(--accent); cursor: pointer; }
.ffa-wt-say { font-size: 19px; line-height: 1.5; margin-top: 14px; }
.ffa-wt-src { font-size: 15px; line-height: 1.45; color: var(--ink-soft); margin-top: 6px; }
.ffa-wt-nav { display: flex; justify-content: space-between; gap: 12px; margin-top: 18px; }
.ffa-wt-nav button { padding: 10px 22px; border: 1px solid rgba(44, 36, 24, .2); border-radius: 999px; background: #FFFFFF; font: inherit; font-size: 17px; font-weight: 600; color: var(--ink); cursor: pointer; }
.ffa-wt-nav button:disabled { opacity: .4; cursor: default; }
.ffa-wt-sub { font-size: 13px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-soft); margin: 0 0 8px; }
.ffa-wt-lines { list-style: none; margin: 0 0 24px; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.ffa-wt-line { display: flex; gap: 12px; width: 100%; padding: 8px 10px; border: 0; border-radius: 10px; background: none; font: inherit; font-size: 16px; line-height: 1.45; text-align: left; color: var(--ink); cursor: pointer; }
.ffa-wt-line:hover { background: rgba(44, 36, 24, .05); }
.ffa-wt-line.is-now { background: var(--sand); }
.ffa-wt-line-t { flex: none; width: 40px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.ffa-wt-srcs { list-style: none; margin: 0 0 16px; padding: 0; display: flex; flex-direction: column; gap: 8px; font-size: 16px; line-height: 1.45; }
.ffa-wt-srcs a { color: var(--accent); }
.ffa-wt-asof { font-size: 15px; color: var(--ink-soft); }

/* /video/{slug} — the plain page (spec §4.5, D3): the whole thing with
   JavaScript off. The browser's own controls; the words beside it.     */
.ffa-vp { display: flex; flex-direction: column; align-items: flex-start; gap: 22px; padding: 72px 0 96px; }
.ffa-vp-h { font-size: 60px; }
.ffa-vp-meta { font-size: 17px; color: var(--ink-soft); }
.ffa-vp-grid { display: grid; grid-template-columns: minmax(0, 420px) minmax(0, 1fr); gap: 56px; align-items: start; width: 100%; margin-top: 12px; }
.ffa-vp-video { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; border-radius: var(--ffa-radius-card); background: var(--ffa-ink-dark); }
.ffa-vp-words { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.ffa-vp-sub { font-size: 13px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-soft); margin: 0; }
.ffa-vp-lines { list-style: none; margin: 0 0 18px; padding: 0; display: flex; flex-direction: column; gap: 12px; font-size: 17px; line-height: 1.5; }
.ffa-vp-lines li { display: flex; gap: 14px; }
.ffa-vp-t { flex: none; width: 40px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.ffa-vp-srcs { list-style: none; margin: 0 0 18px; padding: 0; display: flex; flex-direction: column; gap: 8px; font-size: 17px; line-height: 1.45; }
.ffa-vp-asof { font-size: 15px; color: var(--ink-soft); }

/* ── Shared bands ──────────────────────────────────────
   Bands that belong to no single page. page/partial.* renders them and
   more than one screen ends on them, so their rules live here rather
   than in any one page's section above.                                */

/* Where a page came from, and what it says when it has nothing to show.
   Both end the meeting page AND the item page, and both were written out
   twice — .ffa-am-prov / .ffa-ai-prov and .ffa-am-missing /
   .ffa-ai-missing, byte for byte the same four declarations under two
   names each. Two pages ending on one line is one rule.                */
.ffa-prov { padding: 48px 0 72px; font-size: 14px; line-height: 1.6; color: var(--color-text-tertiary); }
.ffa-prov a { margin-left: 14px; }
.ffa-missing { padding: 96px 0; font-size: 19px; line-height: 1.5; color: var(--ink-soft); }

/* How to speak at a meeting — src/thisweek-body.html:84-99, rendered by
   page/partial.speak.php on every meeting screen. Copy left, three
   numbered cards right, on the dark ground.                            */

.ffa-speak { padding: 120px 0; }
.ffa-speak-grid { align-items: center; gap: 64px; }
.ffa-speak-copy { display: flex; flex-direction: column; gap: 22px; }
/* The list's own marker is off: the numbers are drawn as elements so they
   can carry the mockup's 32px terracotta, and a marker as well would
   print each step twice.                                               */
.ffa-speak-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.ffa-speak-step { flex-direction: row; align-items: center; gap: 20px; padding: 24px 28px; }
/* flex: none, which the artboard can leave out and a page cannot: a flex
   item still shrinks, and a shrunken number column unaligns the three cards
   at exactly the widths where they matter most. Since the This Week design
   pass (2026-09-27) the number sits in a soft terracotta disc and each step
   carries its own icon — a document, a laptop, a person; the paths are
   page/partial.speak.php's $ffs_ico, the band every meeting screen draws.  */
.ffa-speak-n { flex: none; display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; background: rgba(196, 101, 74, .28); font-size: 22px; font-weight: 700; color: var(--terracotta-light); }
.ffa-speak-ico { flex: none; width: 28px; height: 28px; stroke: var(--sand); fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
/* The step text is the bright sand, not the dark ground's muted body
   colour — two classes, because `.ffa-dark .ffa-body` above is two.    */
.ffa-dark .ffa-speak-step-t { font-size: 18px; color: var(--sand); }

/* The three steps of a public meeting — the launch home's City-meetings
   band (build.mjs steps), rendered by page/partial.steps.php on /meetings
   since round 2, on the WHITE ground between the sand list and the dark
   speak band. The numbers the home's dark band had, unchanged.           */
.ffa-steps { padding: 120px 0; }
.ffa-steps-inner { display: flex; flex-direction: column; gap: 24px; }
.ffa-steps-lead { max-width: 820px; }
.ffa-steps-list { list-style: none; margin: 40px 0 0; padding: 0; }
.ffa-step { gap: 16px; }
.ffa-step-h { font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.2; margin: 0; }
.ffa-step-b { font-size: 17px; margin: 0; }
.ffa-steps-links { margin-top: 24px; flex-wrap: wrap; row-gap: 10px; }

/* ── Breakpoints ───────────────────────────────────────
   Desktop artboard at >= 900px. Between 600 and 900 the grids drop to
   one column and the type scale steps down a notch. At <= 600 the
   phone artboard governs (spec §3).                                   */

@media (max-width: 900px) {
  .ffa-wrap, .ffa-wrap--wide { width: auto; margin: 0 24px; }
  .ffa-h1 { font-size: 60px; } .ffa-h2 { font-size: 40px; } .ffa-h3 { font-size: 32px; } .ffa-lead { font-size: 22px; }
  .ffa-grid-2, .ffa-grid-3, .ffa-grid-4 { grid-template-columns: repeat(1, minmax(0, 1fr)); }

  /* Home (slice LH): the artboard's 88/110/120px rhythm shrinks, the split
     hero and the neighborhood grid stack, the doors stack, the strip wraps. */
  .ffa-hm-hero { grid-template-columns: minmax(0, 1fr); gap: 40px; padding: 64px 0 48px; }
  .ffa-hm-h1, .ffa-hm-hero.is-solo .ffa-hm-h1 { font-size: 60px; }
  .ffa-hm-hero.is-solo { padding: 72px 0 48px; }
  .ffa-hm-doors { grid-template-columns: minmax(0, 1fr); padding: 0 0 72px; }
  .ffa-hm-week, .ffa-hm-hood, .ffa-hm-map, .ffa-doctrine { padding: 80px 0; }
  .ffa-hm-strip { grid-auto-flow: row; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .ffa-hm-what { margin-top: 48px; }
  .ffa-hm-what-head { flex-direction: column; align-items: flex-start; gap: 18px; }
  .ffa-hm-what-note { max-width: none; }
  .ffa-hm-hood-grid { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  .ffa-hm-mapcard { padding: 28px 24px; }
  .ffa-hm-tractmap { height: 480px; }
  .ffa-steps { padding: 80px 0; }

  /* This Week (the 2026-09-27 design pass): the hero stacks as the home's
     does, the calendar card under the copy, upright and narrower, without the
     strokes and the note; each panel's head folds to the tile beside the
     facts and the name, with the pill under them; the Where grid stacks —
     the copy and the list, then the map, which keeps its 520px here.       */
  .ffa-tw-intro { grid-template-columns: minmax(0, 1fr); gap: 40px; padding: 64px 0 48px; }
  .ffa-tw-art { min-height: 280px; }
  .ffa-tw-blob { width: 360px; height: 250px; }
  .ffa-tw-cal { width: 260px; padding: 20px 16px; transform: none; }
  .ffa-tw-marks, .ffa-tw-note { display: none; }
  .ffa-tw-quiet { padding: 0 0 64px; }
  .ffa-tw-meeting { padding: 44px 32px; }
  .ffa-tw-where { padding: 64px 0 80px; }
  .ffa-tw-inner { gap: 28px; }
  .ffa-tw-head { grid-template-columns: auto minmax(0, 1fr); gap: 18px 20px; }
  .ffa-tw-agenda { grid-column: 1 / -1; }
  .ffa-tw-tile { width: 96px; height: 76px; border-radius: 20px; }
  .ffa-tw-tile-n { font-size: 20px; }
  .ffa-tw-where-inner { grid-template-columns: minmax(0, 1fr); gap: 28px; }

  /* The meeting page: the same rhythm step-down, the where-grid stacks,
     and the agenda row folds its two right-hand columns under the title.
     .ffa-am-h is restated because .ffa-h1's 60px above cannot reach it —
     both selectors are one class wide and .ffa-am-h is written later, so
     a media query alone would never win.                                  */
  .ffa-am-intro { padding: 56px 0 48px; }
  .ffa-am-h { font-size: 52px; }
  .ffa-am-glance-sec { padding-bottom: 64px; }
  .ffa-am-items, .ffa-am-where, .ffa-am-docs { padding: 64px 0; }
  .ffa-am-quiet { padding: 0 0 64px; }
  .ffa-am-comment { padding: 80px 0; }
  .ffa-am-where-grid { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .ffa-glance { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px; }
  .ffa-item-row { grid-template-columns: 48px minmax(0, 1fr); column-gap: 18px; row-gap: 12px; padding: 22px 24px; }
  /* .ffa-item-main is named here too, and must be: once the map cell is
     pinned to column 2, an unpinned title block auto-flows to the next
     free cell, which is row 2 of the 48px NUMBER column — a title on
     forty lines. Seen in the local review, 2026-09-22.                 */
  .ffa-item-thumb, .ffa-item-main, .ffa-item-rec, .ffa-item-area { grid-column: 2; }
  /* On a phone the small map is a strip across the row's text column,
     beside the number and above the title — and only when it has a
     picture: an empty cell in a two-column grid is a 12px row-gap of
     nothing on every unlocated row, so the cell hides until its image has
     a src. (Desktop needs no such rule: an empty cell there is the width
     the titles align on.)                                              */
  .ffa-item-thumb { display: none; }
  .ffa-item-thumb:has(.ffa-item-thumb-img[src]) { display: block; }
  .ffa-item-thumb-img { aspect-ratio: 16 / 7; border-radius: 14px; }

  /* The agenda item: the same rhythm step-down, the facts strip drops to
     two columns and the two-column bands stack. .ffa-ai-h is restated for
     the same reason .ffa-am-h is — both selectors are one class wide and
     .ffa-ai-h is written later, so a media query alone would never win.  */
  .ffa-ai-intro { padding: 56px 0 40px; }
  .ffa-ai-h { font-size: 52px; }
  .ffa-ai-h--long { font-size: 32px; }
  .ffa-ai-facts-sec { padding-bottom: 64px; }
  .ffa-facts-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ffa-ai-vote { padding-bottom: 64px; }
  .ffa-ai-fixnotes { padding-bottom: 64px; }
  .ffa-ai-report, .ffa-ai-docs { padding: 64px 0; }
  .ffa-ai-data { padding: 64px 0; }
  .ffa-ai-input { padding: 80px 0; }
  .ffa-ai-related { padding: 64px 0; }
  .ffa-ai-data-grid { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .ffa-ai-map .issue-map-canvas:not(.issue-map-canvas--fallback) { height: 320px; }

  /* The meetings index: only the rhythm steps down. The column, the
     groups, the card and the search field are already the artboard's,
     and the artboard is a phone.                                        */
  .ffa-mt-intro { padding: 56px 0 40px; }
  .ffa-mt-list { padding: 40px 0 80px; }

  /* The issues index: the rhythm steps down, every card grid drops to one
     column — including the lead card, whose 560px picture column is wider
     than the whole viewport here — and the group heading wraps its pill
     over its sentence rather than squeezing both onto one line.         */
  .ffa-ix-intro { padding: 72px 0 56px; }
  .ffa-ix-empty { padding: 0 0 64px; }
  .ffa-ix-group { padding: 64px 0; }
  .ffa-ix-inner { gap: 22px; }
  .ffa-ix-head { flex-direction: column; align-items: flex-start; gap: 10px; }
  .ffa-ix-cards,
  .ffa-ix-group[data-key="monitoring"] .ffa-ix-cards { grid-template-columns: minmax(0, 1fr); }
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child,
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child { grid-template-columns: minmax(0, 1fr); }
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child .ffa-ix-img,
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child .ffa-ix-img,
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child .ffa-ix-ph,
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child .ffa-ix-ph { height: 240px; min-height: 0; }
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child .ffa-ix-body,
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child .ffa-ix-body { padding: 32px 36px 36px; }
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child .ffa-ix-title,
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child .ffa-ix-title { font-size: 30px; }
  .ffa-ix-img, .ffa-ix-ph { height: 240px; }
  .ffa-ix-ask { padding: 96px 0; }

  /* The issue guide: the artboard's 120/140/160px rhythm steps down, the
     full-bleed photograph loses two thirds of its height, the two-column
     "who decides" band stacks (.ffa-grid-2 above already does that), and
     the stage rail drops out of its one-column-per-step grid. A four-step
     rail at 390px is four 80px columns and a two-word step name in each,
     so below 900 it is a LIST: the steps keep their order and their state
     colours, and each one gets a line of its own.                      */
  .ffa-ig-open { padding: 72px 0 0; }
  .ffa-ig-open-inner { padding-bottom: 48px; }
  .ffa-ig-hero-img, .ffa-ig-hero-ph { height: 320px; }
  .ffa-ig-number { padding: 96px 0 80px; }
  .ffa-ig-stat { font-size: 112px; }
  .ffa-ig-strip-band { padding: 0 0 32px; }
  .ffa-ig-strip .issue-strip-line { font-size: 19px; }
  .ffa-ig-stands { padding: 80px 0; }
  .ffa-ig-stands-inner { gap: 40px; }
  .ffa-ig-clock { margin-top: -16px; }
  .ffa-ig-clock-date { font-size: 26px; }
  .ffa-stage-rail { grid-template-columns: minmax(0, 1fr); gap: 20px; }
  .ffa-ig-guardrail { padding: 56px 0; }
  .ffa-ig-stands:has(+ .ffa-ig-guardrail) { padding-bottom: 56px; }
  .ffa-ig-numbers { padding: 96px 0; }
  .ffa-compare-row { flex-direction: column; align-items: flex-start; gap: 4px; }
  .ffa-compare-v { text-align: left; }
  .ffa-ig-decide { padding: 80px 0; }
  .ffa-ig-decide-grid { gap: 32px; }
  .ffa-ig-action, .ffa-ig-record { padding: 80px 0; }
  .ffa-ig-band > .ffa-wrap > .ffa-ig-zone { padding: 64px 0; }
  .ffa-ig .issue-question { font-size: 32px; margin-bottom: 18px; }
  .ffa-updates-row { grid-template-columns: minmax(0, 1fr); row-gap: 4px; padding: 20px 0; }
  .ffa-updates-body, .ffa-updates-link { grid-column: 1; }
  .ffa-ig-doctrine { padding: 0 0 72px; }
  /* The refresh (2026-09-24): the clock drops under the heading, the early
     card above the timeline, the cards to one column. */
  .ffa-ig-stands-inner { grid-template-columns: minmax(0, 1fr); row-gap: 32px; }
  .ffa-ig-clock { max-width: none; margin-top: 0; }
  .path-grid { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .path-early { position: static; }
  .path-early-n { font-size: 56px; }

  /* About: the artboard's 112/120/96px rhythm steps down, every two-column
     band stacks (their grids are their own, so .ffa-grid-2's rule above
     cannot reach the hero, doctrine, process and ask grids), the tagline
     card drops under the lead, the doctrine list goes under its headline
     with its divider turned into a line above it, and the portrait
     placeholder loses a third of its height like every other one here. */
  .ffa-ab-intro { grid-template-columns: minmax(0, 1fr); gap: 32px; padding: 72px 0 56px; }
  .ffa-mw-intro { padding: 56px 0 64px; }
  .ffa-mw-bodies { padding: 64px 0; }
  .ffa-mw-week { padding: 48px 0; }
  .ffa-wn-hero { padding: 56px 0 64px; }
  .ffa-wn-live, .ffa-wn-building { padding: 48px 0; }
  .ffa-su { padding: 80px 0; }
  .ffa-su-inner { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .ffa-su-state { padding: 56px 0 48px; }
  .ffa-lg-intro { padding: 56px 0 64px; }
  .ffa-lg-short { padding: 64px 0; }
  .ffa-lg-detail { padding: 64px 0 80px; }
  .ffa-ab-what { padding: 64px 0; }
  .ffa-ab-never { padding: 80px 0; }
  .ffa-ab-never-grid { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  .ffa-ab-nos { padding: 32px 0 0; border-left: 0; border-top: 1px solid rgba(253, 251, 247, .18); gap: 20px; }
  .ffa-ab-no { font-size: 19px; }
  .ffa-ab-no-i, .ffa-ab-no-i svg { width: 28px; height: 28px; }
  .ffa-ab-process, .ffa-ab-ask, .ffa-ab-who { padding: 80px 0; }
  .ffa-ab-process-grid, .ffa-ab-ask-grid { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .ffa-ab-who-grid { gap: 32px; }
  .ffa-ab-who-ph { height: 300px; }
  .ffa-ab-todo { padding: 64px 0; }

  /* Sources: the artboard's 112/96/120px rhythm steps down with every
     other band in this file, and the rules grid stacks — its columns are
     its own, so .ffa-grid-2's rule above cannot reach it. The index grid
     IS a .ffa-grid-2 and is already stacked by that rule; what it needs
     here is the placeholder height every other one in this file loses a
     fifth of at this width. The card grid is a .ffa-grid-2 too.       */
  .ffa-src-intro { padding: 72px 0 56px; }
  .ffa-src-band { padding: 64px 0; }
  .ffa-src-rules, .ffa-src-index { padding: 80px 0; }
  .ffa-src-rules-grid { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .ffa-src-index-grid { gap: 32px; }
  .ffa-src-index-ph { height: 300px; }

  /* Index methodology: the /sources rhythm, stepped down the same way. */
  .ffa-mx-intro { padding: 72px 0 56px; }
  .ffa-mx-band, .ffa-mx-refs { padding: 64px 0; }
  .ffa-mx-band-inner { gap: 40px; }
  .ffa-mx-map { padding: 80px 0; }


  /* Neighborhood: the artboard's 96/120px rhythm steps down with every
     other band in this file, and both two-column bands stack — the hero's
     map column and the breakdown's head are each their own grid, so
     .ffa-grid-2's rule above cannot reach either. The measure grid IS a
     .ffa-grid-3 and is already one column by that rule (so are the
     score's three part cards since 6g); the phone block
     below takes it back to the artboard's two. The ring loses a quarter
     of its diameter, as every placeholder in this file loses a fifth of
     its height at this width.                                          */
  .ffa-nb-intro { grid-template-columns: minmax(0, 1fr); gap: 40px; padding: 72px 0 56px; }
  .ffa-index-ring { width: 200px; height: 200px; }
  .ffa-nb-why-top { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .ffa-nb-why-top .ffa-index-ring { width: 160px; height: 160px; }
  /* The breakdown keeps step with the bands around it: its hairline moves
     up with the hero that closes above it, and its own foot closes on the
     sand band below.                                                    */
  .ffa-nb-why { padding: 0 0 64px; }
  .ffa-nb-why-inner { padding-top: 40px; }
  /* The dialog's strain tag (6i) may wrap on a narrow table: five columns of
     15px type leave no room for a one-line tag between 601 and 900px.     */
  .ffa-why-c-strain .ffa-strain { white-space: normal; }
  .ffa-nb-numbers { padding: 64px 0; }
  .ffa-nb-decisions { padding: 80px 0; }
  .ffa-nb-near { padding: 0 0 64px; }
  .ffa-nb-near-head, .ffa-nb-numbers-head { flex-direction: column; align-items: flex-start; gap: 14px; }
  .ffa-nb-land, .ffa-nb-ctx { margin-top: 48px; }
  /* The land row stacks here (spec 6f §2.3), not only on the phone.      */
  .ffa-nb-land-grid { grid-template-columns: minmax(0, 1fr); }
  .ffa-nb-visual-h { font-size: 32px; }
  .ffa-nb-standouts { padding: 64px 0; }
  .ffa-nb-map, .ffa-nb-map-ph { height: 320px; }
  /* Around it stacks, the COLUMN (the map and its key, slice 6m) FIRST and
     full width, then the panel — the picture before the list (spec §4).
     The column stops sticking; the map's height steps down as the hero's. */
  .ffa-around { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .ffa-around-col { order: -1; position: static; }
  .ffa-around-map { height: 320px; }

  /* The speak band keeps the same rhythm as the other full-width bands. */
  .ffa-speak { padding: 80px 0; }
  .ffa-speak-grid { gap: 32px; }

  /* The dark seam, stepped down with the bands above (see the rule at the
     top of this file for why it is ADDITIVE). 40px on top of the 80px this
     band already carries still opens it wider than the 80px the band above
     closes with, so the line reads as the start of something rather than a
     divider — the same asymmetry the desktop's 72-on-120 draws, half a
     step tighter because a phone has less height to spend on it.        */
  .ffa-dark + .ffa-dark > .ffa-wrap { padding-top: 40px; }
  /* Issue guide, the owner's mockups (2026-09-25). */
  .ffa-ig-stat-l { font-size: 28px; }
  /* The rail becomes a list below 900: the node sits left of each step and
     the line runs down to the next node. */
  .ffa-ig .ffa-stage-rail { gap: 0; }
  .ffa-ig .ffa-stage { display: grid; grid-template-columns: 34px minmax(0, 1fr); column-gap: 16px; row-gap: 2px; align-items: start; text-align: left; padding-bottom: 22px; }
  .ffa-ig .ffa-stage:last-child { padding-bottom: 0; }
  .ffa-ig .ffa-stage .ffa-stage-bar, .ffa-ig .ffa-stage.is-done .ffa-stage-bar, .ffa-ig .ffa-stage.is-now .ffa-stage-bar { position: static; grid-row: 1 / span 2; width: 34px; }
  .ffa-ig .ffa-stage-step, .ffa-ig .ffa-stage-name { grid-column: 2; }
  .ffa-ig .ffa-stage-step { padding-top: 2px; }
  .ffa-ig .ffa-stage-bar::before { left: 15px; right: auto; top: 34px; bottom: 0; width: 4px; height: auto; margin-top: 0; }
  .ffa-ig .ffa-stage-bar::after { left: 0; margin-left: 0; }
  .ffa-ig .ffa-stage.is-done:has(+ .ffa-stage.is-now) .ffa-stage-bar::before { background: repeating-linear-gradient(180deg, var(--terracotta) 0 4px, transparent 4px 9px); }
  .path-aside { position: static; }
  .path-body { grid-template-columns: 36px minmax(0, 1fr); }
  .path-links { justify-content: flex-start; }
  .ffa-ig .ff-meter { grid-template-columns: minmax(0, 1fr); grid-template-areas: "head" "actual" "track" "limit" "note"; }
  .ffa-ig-action-inner { grid-template-columns: minmax(0, 1fr); }
  .ffa-ig-action-inner > .ffa-ig-action-h, .ffa-ig-action-inner > .ffa-ig-tiers, .ffa-ig-action-inner > .ffa-ig-primary { grid-column: 1; grid-row: auto; }
  .ffa-ig .process-steps { grid-auto-flow: row; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
  .ffa-ig .process-arrow { display: none; }
  .ffa-ig-record-h { font-size: 32px; }
  /* Header pass (2026-09-26): one column, the card under the copy. */
  .ffa-ig-open-inner:has(> .ffa-ig-status:not(:empty)) { grid-template-columns: minmax(0, 1fr); row-gap: 40px; }
  .ffa-ig-open-inner:has(> .ffa-ig-status:not(:empty)) .ffa-ig-h { font-size: 60px; }
  .ffa-ig-hero { padding-bottom: 40px; }
  .ffa-ig-site:has(> .ffa-ig-zone > .issue-module--map) { grid-template-columns: minmax(0, 1fr); padding-block: 64px; }
  .ffa-ig-site:has(> .ffa-ig-zone > .issue-module--map) > .ffa-ig-site-stat { margin-top: 0; }
  .ffa-ig-site-stat-n { font-size: 80px; }
  .ffa-ig-intro .map-head { font-size: 32px; }
  .ffa-ig-intro .issue-map-canvas:not(.issue-map-canvas--fallback) { height: 340px; }
  /* The video spot: under 900px the sheet slides up from the bottom and
     is one column — the player, then the words (spec §4.4). The /video
     page stacks the same way. The body keeps its content's height and
     the whole sheet scrolls: flexed to fit (the desktop's flex: 1), its
     rows shrank below their content and the words painted over the
     player and Back / Next (the local review).                         */
  .ffa-wt-sheet { width: 100%; max-width: 100%; margin: auto 0 0; border-radius: 22px 22px 0 0; max-height: 92vh; --ffa-wt-in: ffa-wt-up; }
  .ffa-wt-in { padding: 20px 20px 28px; max-height: 92vh; overflow-y: auto; }
  .ffa-wt-body { grid-template-columns: minmax(0, 1fr); gap: 24px; flex: none; }
  .ffa-wt-stage, .ffa-wt-side { overflow: visible; }
  .ffa-wt-frame, .ffa-wt-step .ffa-wt-frame { width: min(100%, 420px); }
  .ffa-vp { padding: 56px 0 72px; }
  .ffa-vp-grid { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .ffa-vp-video { max-width: 420px; }
  /* Small fixes: the rhythm steps down as Why go's does. */
  .ffa-fx-intro { padding: 56px 0 64px; }
  .ffa-fx-audit { padding: 64px 0; }
  .ffa-fx-list { padding: 64px 0 80px; gap: 44px; }
  .ffa-fx-how { padding: 80px 0; }
}
@media (max-width: 600px) {
  .ffa-h1 { font-size: 40px; } .ffa-h2 { font-size: 32px; } .ffa-stat { font-size: 72px; }

  /* Home on a phone (ShowcasePhone.dc.html): the caption card overlaps the
     photo by less, the doors are a grouped list of three rows, the strip
     is a list of days, each with its meeting rows, and the map's pill
     spans the card. */
  .ffa-hm-h1, .ffa-hm-hero.is-solo .ffa-hm-h1 { font-size: 40px; }
  .ffa-hm-hero { gap: 28px; padding: 28px 0 36px; }
  .ffa-hm-photo { aspect-ratio: 3 / 2; border-radius: 24px; }
  .ffa-hm-photo--ph { padding: 20px 20px 70px; }
  .ffa-hm-cap { margin: -56px 12px 0; padding: 20px; border-radius: 20px; gap: 10px; }
  .ffa-hm-title { font-size: 22px; }
  .ffa-hm-cap-body { font-size: 15px; }
  .ffa-hm-cap .ffa-hm-go { min-height: 44px; padding: 0 20px; font-size: 15px; }
  .ffa-hm-doors { display: flex; flex-direction: column; gap: 0; padding: 0 0 44px; }
  .ffa-hm-door { flex-direction: row; align-items: center; gap: 12px; padding: 12px 16px; min-height: 44px; border-radius: 0; box-shadow: none; border-bottom: 1px solid rgba(44, 36, 24, .1); }
  .ffa-hm-door:first-child { border-radius: 18px 18px 0 0; }
  .ffa-hm-door:last-child { border-radius: 0 0 18px 18px; border-bottom: 0; }
  .ffa-hm-door-w { flex: none; width: 108px; font-size: 13px; }
  .ffa-hm-ico { width: 22px; height: 22px; }
  .ffa-hm-door-t { flex: 1; min-width: 0; font-size: 17px; }
  .ffa-hm-door-s { display: none; }
  .ffa-hm-door::after { content: "\203A"; color: #B5AC9C; font-size: 20px; flex: none; }
  .ffa-hm-week, .ffa-hm-hood, .ffa-hm-map, .ffa-doctrine { padding: 44px 0; }
  .ffa-hm-strip { display: flex; flex-direction: column; gap: 14px; margin-top: 20px; }
  .ffa-hm-day-card, .ffa-hm-day-none { min-height: 60px; padding: 12px 16px; }
  .ffa-hm-day-none { justify-content: flex-start; }
  .ffa-hm-what { margin-top: 32px; gap: 20px; }
  .ffa-hm-item { padding: 20px; }
  .ffa-hm-item-t { font-size: 20px; }
  .ffa-hm-card { padding: 24px; border-radius: 20px; gap: 18px; }
  .ffa-hm-card-h { font-size: 28px; }
  .ffa-hm-tmap { aspect-ratio: 480 / 200; }
  .ffa-address-form { padding: 6px 6px 6px 16px; }
  .ffa-address-form input { font-size: 16px; }
  .ffa-hm-mapcard-wrap { margin-top: 24px; }
  .ffa-hm-mapcard { padding: 20px 16px; border-radius: 20px; }
  .ffa-hm-tractmap { height: 340px; }
  .ffa-hm-map-links { flex-direction: column; align-items: stretch; margin-top: 28px; }
  .ffa-hm-cta { justify-content: center; width: 100%; box-sizing: border-box; }
  .ffa-pill--go { padding: 10px 14px; }
  .ffa-steps { padding: 44px 0; }
  .ffa-steps-list { margin-top: 20px; }
  .ffa-step { padding: 20px; }
  .ffa-step-h { font-size: 20px; }

  /* This Week on a phone: the filter is a full-width control, the panels lose
     most of their padding and their radius steps down, and the item cards lose
     the desktop card padding like every other card at this width — all but the
     64px at the foot that clears the corner chevron. The panel head lets its
     title column go (display: contents) so the tile sits beside the time and
     the room and the body's name takes the panel's whole width under them — a
     body like "Commissioners Court" is wider than the column beside a tile.  */
  .ffa-tw-filters { align-self: stretch; }
  .ffa-tw-meeting { padding: 28px 20px; border-radius: 24px; }
  .ffa-tw-title { display: contents; }
  .ffa-tw-head .ffa-h2 { grid-column: 1 / -1; }
  .ffa-tw-item { padding: 24px 24px 64px; }
  .ffa-tw-item-t { font-size: 20px; }

  /* The issues index on a phone: the card padding comes off with every
     other card's, and the two title steps come down one notch each.     */
  .ffa-ix-body,
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child .ffa-ix-body,
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child .ffa-ix-body { padding: 24px; }
  .ffa-ix-title,
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="open"] .ffa-ix-card:first-child .ffa-ix-title,
  .ffa-ix-groups > .ffa-ix-group:first-child[data-key="deciding"] .ffa-ix-card:first-child .ffa-ix-title { font-size: 26px; }
  .ffa-ix-img, .ffa-ix-ph { height: 200px; }

  /* The meeting page on a phone: the glance is two columns of 40px
     numbers, the agenda rows and document rows lose the desktop card
     padding, and the map takes the phone height style.css gives every
     other module map at this width.                                    */
  .ffa-am-h { font-size: 40px; }
  .ffa-glance { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; }
  .ffa-glance-cell { padding: 20px 22px; }
  .ffa-glance-n { font-size: 40px; }
  .ffa-item-row { padding: 20px 22px; }
  .ffa-item-t { font-size: 18px; }
  .ffa-doc-row { padding: 18px 20px; }
  .ffa-am-map .am-map-canvas:not(.issue-map-canvas--fallback) { height: 320px; border-radius: 24px; }
  .ffa-tw-map .am-map-canvas:not(.issue-map-canvas--fallback) { height: 320px; border-radius: 24px; }

  /* The agenda item on a phone — src/agenda-body.html. Its running order
     is the artboard's: the screen opens on the title and then the vote,
     because for an item that has been decided the decision IS the news.
     Two `order` values do it and the rest of the sections keep their
     document order behind them (flex leaves equal orders alone), so the
     markup stays in the desktop artboard's reading order.              */
  .ffa-ai-item { display: flex; flex-direction: column; }
  .ffa-ai-intro { order: -2; }
  .ffa-ai-vote { order: -1; }
  .ffa-ai-fixnotes { order: -1; }   /* the Small fixes note stands where the vote would */

  .ffa-ai-h { font-size: 32px; }
  .ffa-ai-h--long { font-size: 24px; }
  .ffa-ai-official { font-size: 14px; }
  .ffa-facts-strip { grid-template-columns: minmax(0, 1fr); }
  .ffa-vote-card, .ffa-ai-roll { max-width: none; }
  .ffa-vote-card { padding: 20px 22px; border-radius: 22px; }
  .ffa-vote-tally { font-size: 30px; }
  .ffa-ai-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .ffa-ai-natl { margin-top: 2px; font-size: 11px; }
  .ffa-ai-input-card { padding: 22px 24px; }
  .ffa-ai-map .issue-map-canvas:not(.issue-map-canvas--fallback) { height: 240px; }

  /* The meetings index on a phone, which is the artboard exactly:
     tighter padding on the card and the search field, and a 17px lead.
     The 34px title is .ffa-large-title at the foot of this block — this
     page is that class's first reader, and it outranks .ffa-h1's 40px
     because both are one class wide and it is written later.           */
  .ffa-mt-intro { padding: 28px 0 24px; gap: 14px; }
  .ffa-mt-lead { font-size: 17px; }
  .ffa-mt-list { padding: 24px 0 56px; }
  .ffa-mt-search { padding: 9px 12px; }
  .ffa-mt-week { padding: 18px 20px; gap: 12px; }
  .ffa-mt-week-h { font-size: 20px; }

  /* The issue guide on a phone: the one number comes down to the 72px
     .ffa-stat already takes at this width (the rule at the top of this
     block), the card loses the desktop card padding like every other
     card, and the photograph is a 3:2 picture rather than a band.    */
  .ffa-ig-stat { font-size: 72px; }
  .ffa-ig-hero-img, .ffa-ig-hero-ph { height: 240px; }
  .ffa-ig-clock-date { font-size: 22px; }
  .ffa-issue-lead-card { padding: 24px; }
  .ffa-issue-lead-h { font-size: 22px; }
  .ffa-ig-stands-h { font-size: 32px; }
  /* The refresh (2026-09-24): the date moves above the card, the line and
     dot hug the left edge, and every caption column stacks over its value. */
  .path-stage { grid-template-columns: 16px minmax(0, 1fr); column-gap: 12px; }
  .path-stage::before { display: none; }   /* the date row sits between dots here; the cards carry the order */
  .path-date { grid-column: 2; grid-row: 1; text-align: left; padding: 0 0 6px; }
  .path-dot { grid-column: 1; grid-row: 2; margin: 22px 0 0; }
  .path-body { grid-column: 2; grid-row: 2; padding: 16px 18px; }
  .path-top { flex-direction: column; gap: 4px; }
  .path-slot, .ffa-ig .od-slot { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .ffa-ig .od-card, .ffa-ig .stat-card { padding: 24px 20px; }
  .ffa-ig .od-list, .ffa-ig .stat-grid { grid-template-columns: minmax(0, 1fr); }

  /* About on a phone: the cards and the form lose the desktop card
     padding like every other card at this width, the two sub-headings
     come down one notch each, and since 2026-09-27 the discs, the step
     cards, the callout and the tagline card come down with them. The
     dashed line follows the smaller step disc, whose centre is 22px.   */
  .ffa-ab-card, .ffa-form { padding: 24px; }
  .ffa-ab-card-h { font-size: 20px; }
  .ffa-ab-n { font-size: 34px; }
  .ffa-ab-disc { width: 56px; height: 56px; }
  .ffa-ab-disc svg { width: 24px; height: 24px; }
  .ffa-ab-tag { padding: 28px; }
  .ffa-ab-tag-l { font-size: 19px; }
  .ffa-ab-step { grid-template-columns: 44px minmax(0, 1fr); gap: 14px; }
  .ffa-ab-step::after { left: 21px; top: 44px; }
  .ffa-ab-step-n { width: 44px; height: 44px; font-size: 20px; }
  .ffa-ab-step-main { padding: 18px 20px; }
  .ffa-ab-step-h { font-size: 18px; }
  .ffa-ab-voice { padding: 22px; grid-template-columns: 52px minmax(0, 1fr); }
  .ffa-ab-voice .ffa-ab-disc { width: 52px; height: 52px; }
  .ffa-ab-who-ph { height: 240px; }

  /* Sources on a phone: the source cards lose the desktop card padding
     like every other card at this width, the dataset name comes down one
     notch with them, and the card foot stops trying to hold a meta line
     and a link on one 390px row.                                      */
  .ffa-source-card { padding: 24px; }
  .ffa-source-name { font-size: 22px; }
  .ffa-source-foot { flex-direction: column; align-items: flex-start; gap: 8px; }
  .ffa-src-index-ph { height: 240px; }

  /* Index methodology on a phone. The cards lose padding as .ffa-part's
     do, and each row of a part's table becomes a grouped-list row, the way
     .ffa-why-tbl collapses: the name and its notes on the left, the share
     on the right, and source · year as one 13px meta line under both. The
     header row stays as Measure | Share, so no share is unlabelled; the
     source and year headers leave the screen but not the accessibility
     tree — .ffa-sr's declarations are restated here, because the .ffa-sr
     CLASS in the markup would hide them on desktop too.               */
  .ffa-mx-q, .ffa-mx-part { padding: 20px; }
  .ffa-mx-tbl, .ffa-mx-tbl thead, .ffa-mx-tbl tbody, .ffa-mx-tbl thead tr { display: block; }
  .ffa-mx-tbl thead tr { position: relative; padding: 0 64px 8px 0; border-bottom: 1px solid rgba(44, 36, 24, .12); }
  .ffa-mx-tbl th, .ffa-mx-tbl td { padding: 0; border-bottom: 0; }
  .ffa-mx-tbl th:nth-child(1) { display: block; width: auto; }
  .ffa-mx-tbl th:nth-child(2) { position: absolute; top: 0; right: 0; width: auto; text-align: right; }
  .ffa-mx-tbl th:nth-child(3), .ffa-mx-tbl th:nth-child(4) { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
  .ffa-mx-c { display: block; position: relative; padding: 12px 64px 12px 0; border-bottom: 1px solid rgba(44, 36, 24, .06); font-size: 14px; }
  .ffa-mx-c-n { display: block; }
  .ffa-mx-c-why { font-size: 13px; }
  .ffa-mx-c-inv { font-size: 13px; }
  .ffa-mx-c-w { position: absolute; top: 12px; right: 0; text-align: right; }
  .ffa-mx-c-src, .ffa-mx-c-yr { display: inline; font-size: 13px; }
  .ffa-mx-c-src:not(:empty) + .ffa-mx-c-yr > span::before { content: "\00B7"; margin-right: 6px; }
  .ffa-mx-ref-list { font-size: 14px; }


  /* The neighborhood on a phone — src/tract-body.html. The page is the
     same route at every width (spec §3), so this block restyles the
     desktop's own elements into the phone artboard rather than hiding
     them and drawing a second set: the ring becomes the white card at the
     top of the screen with the index's SHORT name beside it, the six
     measures become the artboard's stat cards two to a row, and the kind
     buttons become one row that scrolls sideways inside its own box, over
     the map and then the panel — the 44pt row rule (house rule 8) holds
     for the buttons, for the panel's rows and for the dialog's list.

     The artboard's fourth stat card — "4,120 People · 29% under 18" — is
     NOT a measure and is not one of these cards: it is one fact about the
     tract, and load.neighborhood.php already builds it as the hero's
     population sentence, which is where it stays.                      */
  .ffa-nb-intro { padding: 28px 0 24px; gap: 20px; }
  .ffa-nb-index { flex-direction: row; align-items: center; gap: 16px; text-align: left; background: #FFFFFF; border-radius: 22px; padding: 16px 18px; }
  .ffa-index-ring { width: 92px; height: 92px; }
  .ffa-index-ring-t, .ffa-index-ring-v { stroke-width: 12; }
  .ffa-index-name { display: none; }
  .ffa-index-name--short { display: block; font-size: 16px; }
  .ffa-index-cap { font-size: 13px; line-height: 1.35; }
  .ffa-nb-why-top { gap: 16px; }
  .ffa-nb-why-top .ffa-index-ring { width: 92px; height: 92px; }

  /* THE BREAKDOWN'S TABLE — inside the DIALOG since 6g, where openPart()
     builds it: five columns become two. The measure and this tract's
     number are the two the reader came for and they stay side by side;

     "where it stands" moves UNDER the measure, spanning the row, because
     it is a sentence and a sentence in a 90px column is four lines; and
     "weight in this part" is HIDDEN, because it is the one figure on the
     table a phone reader cannot act on and the part's own weight is on
     its card. The strain tag (6i) joins the standing sentence's pattern —
     under it, spanning the row — and an EMPTY tag cell is dropped HERE
     ONLY, where it is a grid item on a row of its own; on the real table
     above 600px a hidden <td> would shift every later cell one column
     left. Five columns of 15px type do not fit 375px, and shrinking
     the type is how a table turns into a picture of a table.

     The table, its head and its body all become blocks so the rows can be
     grids: a <tr> laid out as a grid inside a display:table parent gets an
     anonymous table box wrapped round it and the columns come back.

     The table rules reach it where it is, which at this width is the
     bottom sheet the dialog becomes below. The part CARDS on the page
     keep a name, a weight and a score, each one notch down.            */
  .ffa-nb-why { padding: 0 0 28px; }
  .ffa-nb-why-inner { padding-top: 28px; gap: 12px; }
  .ffa-part { padding: 20px; }
  .ffa-why-n { font-size: 17px; }
  .ffa-why-s { font-size: 24px; }
  .ffa-why-w { font-size: 13px; }
  .ffa-why-d { font-size: 14px; }
  .ffa-why-tbl, .ffa-why-tbl thead, .ffa-why-tbl tbody { display: block; }
  .ffa-why-tbl thead tr, .ffa-why-c { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 12px; }
  .ffa-why-tbl th, .ffa-why-tbl td { padding: 0; border-bottom: 0; }
  .ffa-why-tbl thead tr { padding-bottom: 8px; border-bottom: 1px solid rgba(44, 36, 24, .12); }
  .ffa-why-c { padding: 10px 0; border-bottom: 1px solid rgba(44, 36, 24, .06); font-size: 14px; }
  .ffa-why-c-s { grid-column: 1 / -1; font-size: 13px; }
  .ffa-why-c-strain { grid-column: 1 / -1; }
  .ffa-why-c-strain:empty { display: none; }
  .ffa-why-c-strain .ffa-strain { margin-top: 4px; }
  .ffa-why-h-stand, .ffa-why-h-strain, .ffa-why-h-weight, .ffa-why-c-w { display: none; }
  .ffa-nb-why-link { font-size: 15px; }

  .ffa-nb-numbers { padding: 32px 0; }
  .ffa-nb-numbers-inner { gap: 16px; }
  .ffa-nb-num-note { margin: 0; }
  .ffa-nb-measures { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .ffa-measure-card { padding: 14px 16px; border-radius: 16px; gap: 4px; box-shadow: none; }
  .ffa-measure-v { font-size: 28px; }
  .ffa-measure-l { font-size: 13px; font-weight: 500; }
  .ffa-measure-c { font-size: 12px; font-weight: 600; }
  .ffa-measure-key { font-size: 12px; }
  /* Slice 6h — the three labels under the bar step down with the key and
     the rank sentence (Correction 13, the plan's one addition). The income
     card at 375px is the worst case — "$18,000 · County $52,600 · $120,000"
     in a 127px column. Checked in a browser at the 6h review: the cards sit
     TWO to a row on a phone, and no size fits three labels on that track,
     so on a CARD the centre label drops to a row of its own — still centred
     under the band — and the two ends keep the first row. The panel's row
     is 327px wide there and stays on one line. */
  .ffa-bar-ends { column-gap: 4px; }
  .ffa-bar-end, .ffa-bar-mid { font-size: 11px; }
  .ffa-measure-card .ffa-bar-ends { row-gap: 2px; }
  .ffa-measure-card .ffa-bar-mid { grid-column: 1 / -1; grid-row: 2; }

  .ffa-nb-near { padding: 0 0 32px; }
  .ffa-nb-near-inner { padding-top: 28px; gap: 18px; }
  .ffa-nb-near-copy { gap: 12px; }
  /* The button row scrolls SIDEWAYS inside its own box and the page does
     not: no wrap, overflow-x on the row, a snap so a flick lands on a
     button, and flex: none so no pill is squeezed. The row's box is the
     wrap's width, so the overflow is the row's and never the page's.    */
  .ffa-kinds { flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; padding-bottom: 6px; }
  .ffa-kind { scroll-snap-align: start; flex: none; }
  .ffa-kind-h { font-size: 20px; }
  .ffa-around-map { height: 260px; border-radius: 22px; }
  .ffa-around-map .ffa-nb-map-ph { border-radius: 22px; }
  /* Slice 6m: the card at the map's phone radius, and its head sized for a
     FULL-WIDTH card — the 28/13/12px rules above are the 2-up tiles'. */
  .ffa-kind-panel { padding: 20px; border-radius: 22px; }
  .ffa-kind-panel .ffa-measure-v { font-size: 40px; }
  .ffa-kind-panel .ffa-measure-l { font-size: 15px; font-weight: 600; }
  .ffa-kind-panel .ffa-measure-c { font-size: 15px; font-weight: 400; }
  .ffa-nearby-row { padding: 11px 16px; min-height: 44px; box-sizing: border-box; border-bottom: 0.5px solid rgba(44, 36, 24, .12); }
  .ffa-nearby-row:last-child { border-bottom: 0; }
  /* The list rule above was cut for a grouped white list's edges — the
     dialog's — and the panel's rows have no box to be inset from. The
     panel's base rule already outranks it by specificity; this says so
     where a phone reader looks, and holds if that list rule is ever made
     more specific.                                                        */
  .ffa-kind-panel .ffa-nearby-row { padding-left: 0; padding-right: 0; }
  .ffa-nearby-s { font-size: 13px; }
  .ffa-nb-land, .ffa-nb-ctx { margin-top: 32px; }
  .ffa-nb-visual-h { font-size: 24px; }
  .ffa-nb-land-grid { grid-template-columns: minmax(0, 1fr); gap: 20px; }
  .ffa-lc-row { grid-template-columns: 116px minmax(0, 1fr) 44px; font-size: 14px; }
  .ffa-lc-axis { grid-template-columns: 116px minmax(0, 1fr) 44px; }
  .ffa-lc-waffle-wrap { width: 112px; margin-left: 16px; }
  .ffa-lc-waffle { gap: 1px; }
  .ffa-nb-ctx-h { font-size: 20px; }
  .ffa-dialog { width: 100%; max-width: 100%; margin: auto 0 0; border-radius: 22px 22px 0 0; max-height: 85vh; }
  .ffa-dialog-in { padding: 22px 20px 28px; max-height: 85vh; }
  .ffa-dialog-h { font-size: 22px; }
  .ffa-nb-map, .ffa-nb-map-ph { height: 240px; }

  .ffa-nb-standouts { padding: 32px 0; }
  .ffa-nb-so-cards { grid-template-columns: minmax(0, 1fr); gap: 10px; }

  .ffa-nb-decisions { padding: 40px 0; }
  .ffa-nb-dec { padding: 24px; }
  .ffa-nb-dec-t { font-size: 20px; }

  .ffa-speak-step { padding: 20px 22px; gap: 16px; }
  .ffa-speak-n { width: 36px; height: 36px; font-size: 18px; }
  .ffa-speak-ico { width: 24px; height: 24px; }

  /* The phone vocabulary, ported from docs/design/apple/src/phone.css.
     House rule 8: grouped white lists on sand, 44pt rows, a chevron on
     anything that opens.                                              */
  .ffa-large-title { font-size: 34px; font-weight: 700; letter-spacing: -.025em; line-height: 1.1; }
  .ffa-sub { font-size: 15px; color: #6E6558; }
  .ffa-cap { font-size: 13px; color: var(--color-text-tertiary); }
  .ffa-group { background: #FFFFFF; border-radius: 14px; overflow: hidden; display: flex; flex-direction: column; }
  .ffa-row { display: flex; align-items: center; gap: 12px; padding: 11px 16px; min-height: 44px; box-sizing: border-box; border-bottom: 0.5px solid rgba(44,36,24,.12); }
  .ffa-row:last-child { border-bottom: 0; }
  .ffa-row-t { font-size: 17px; letter-spacing: -.01em; line-height: 1.25; }
  .ffa-row-s { font-size: 13px; color: var(--color-text-tertiary); margin-top: 2px; }
  .ffa-badge { display: inline-flex; align-items: center; border-radius: 999px; padding: 4px 10px; font-size: 12px; font-weight: 600; }
  .ffa-link { color: var(--accent); font-weight: 500; }
  /* Issue guide, the owner's mockups (2026-09-25). */
  .ffa-ig-stat-l { font-size: 24px; }
  .ffa-ig-strip .issue-strip-line { font-size: 17px; align-items: flex-start; }
  .ffa-ig .ffa-stage-name { font-size: 16px; }
  .ffa-ig .ffa-stage-step { font-size: 11px; letter-spacing: .05em; }
  .ffa-ig-guardrail { padding: 48px 0; }
  .ffa-ig-stands:has(+ .ffa-ig-guardrail) { padding-bottom: 48px; }
  .ffa-ig-guardrail-inner { flex-direction: column; gap: 16px; padding: 24px 22px; }
  .ffa-ig .ffa-ig-badge { font-size: 13px; padding: 4px 10px; }
  .path-body { grid-template-columns: minmax(0, 1fr); row-gap: 12px; }
  .path-n { width: 30px; height: 30px; font-size: 14px; }
  .path-links { grid-column: 1; }
  .path-meta { grid-template-columns: minmax(0, 1fr); }
  .path-slot { display: flex; }
  .ffa-ig .od-help { align-items: flex-start; font-size: 16px; }
  .ffa-ig .ffa-compare-row { border-right: 0; margin-right: 0; padding: 12px 0; border-bottom: 1px solid rgba(44, 36, 24, .12); flex-basis: 100%; }
  .ffa-ig .ff-meter { padding: 24px 20px; }
  .ffa-ig-who-row { padding: 14px 16px; gap: 14px; }
  .ffa-ig-who-mark { width: 48px; height: 48px; font-size: 20px; }
  .ffa-ig-who-logo { width: 38px; height: 38px; }
  .ffa-ig .ab-tier { padding: 24px 20px; }
  .ffa-ig-acc > .ffa-ig-sub { font-size: 26px; }
  .ffa-ig-door-q, .ffa-ig-door-take, .ffa-ig-door-link { margin-left: 20px; }
  .ffa-ig-record-inner { grid-template-columns: minmax(0, 1fr); }
  .ffa-ig-more { grid-column: 1; grid-row: auto; order: 3; }
  .ffa-ig .process-steps { grid-template-columns: minmax(0, 1fr); }
  /* Header pass (2026-09-26). */
  .ffa-ig-open-inner:has(> .ffa-ig-status:not(:empty)) .ffa-ig-h { font-size: 44px; }
  .ffa-ig .ffa-ig-links a { min-height: 50px; padding: 0 22px; font-size: 16px; }
  .ffa-ig-status .status-list { padding: 4px 18px; }
  .ffa-ig-status .status-row { gap: 14px; padding: 16px 0; }
  .ffa-ig-status .status-icon { width: 44px; height: 44px; font-size: 18px; }
  .ffa-ig-status .status-text { font-size: 16px; }
  .ffa-ig-status .status-mark { width: 32px; height: 32px; font-size: 14px; }
  .ffa-ig-hero-img { border-radius: 16px; }
  .ffa-ig-site-stat-n { font-size: 64px; }
  .ffa-ig-site:has(> .ffa-ig-zone > .issue-module--map) > .ffa-ig-site-stat { padding: 28px 24px; }
  .ffa-ig-intro .map-head { font-size: 28px; }
  .ffa-ig-intro .issue-map-canvas:not(.issue-map-canvas--fallback) { height: 280px; border-radius: 16px; }
  .ffa-ig-strip .issue-strip-line { gap: 14px; padding: 18px; border-radius: 18px; }
  .ffa-ig .ffa-ig-strip .issue-strip-icon { width: 48px; height: 48px; font-size: 20px; }
  .ffa-ig .issue-strip-link { width: 44px; height: 44px; font-size: 16px; }
  /* The video spot on a phone: a smaller lead card and shelf, and the
     sheet's title steps down with the dialog's.                        */
  .ffa-wt-lead { gap: 14px; padding: 10px 18px 10px 10px; }
  .ffa-wt-lead .ffa-wt-poster { width: 88px; border-radius: 12px; }
  .ffa-wt-title { font-size: 19px; }
  .ffa-wt-slot { width: 96px; }
  .ffa-wt-h { font-size: 22px; }
  /* Small fixes on a phone: the card's padding and title shrink; the glance stays three
     across, tighter. */
  .ffa-fx-sum { padding: 24px 20px; gap: 12px; }
  .ffa-fx-body { padding: 22px 20px 28px; }
  .ffa-fx-title { font-size: 22px; }
  .ffa-fx-steps { gap: 6px; }
  .ffa-fx-step { padding: 10px; border-radius: 12px; }
  .ffa-fx-step-l { font-size: 11px; letter-spacing: .04em; }
  .ffa-fx-step-d { font-size: 13px; }
}
