/*
Theme Name: Assembly for Peace
Theme URI: https://cpr.unu.edu/
Author: UNU-CPR
Author URI: https://cpr.unu.edu/
Description: Block theme for the "Assembly for Peace" digital Handbook — a living reference on the UN General Assembly's practice on peace and security. Design system: "Refined UN Blue". Built for researcher-friendly Gutenberg editing via a reusable pattern library.
Requires at least: 6.5
Tested up to: 6.7
Requires PHP: 7.4
Version: 0.1.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: assembly-for-peace
Tags: full-site-editing, block-patterns, editor-style, custom-colors, custom-menu, block-styles, wide-blocks, accessibility-ready

All design/behaviour lives in theme.json, templates/, parts/, and patterns/.
This file only carries the theme header (required by WordPress) plus a few
front-end rules that theme.json cannot express.
*/

/* ponytail: keep this file near-empty — theme.json is the source of truth.
   Only add rules here that block styling genuinely can't reach. */

/* Respect reduced-motion for any future interactive blocks (timeline, index). */
@media (prefers-reduced-motion: reduce) {

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* Deep-linkable headings: offset scroll target so a jumped-to anchor isn't
   hidden under a sticky header. Every heading/case gets a stable anchor (§1.7). */
:target {
  scroll-margin-top: 6rem;
}

/* A few nested column layouts overrun narrow viewports by ~6px; clip (not
   hidden — position:sticky keeps working) stops the page-level side wiggle. */
html {
  overflow-x: clip;
}

/* Sticky footer: on short pages the footer sits at the bottom of the viewport;
   on long pages it flows normally. .wp-site-blocks wraps header + content +
   footer, so the auto top-margin absorbs any leftover height. */
.wp-site-blocks {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}

.wp-site-blocks>footer {
  margin-top: auto;
}

/* Site header/footer chrome (design "1a — institutional": navy bar). These rules
   can't live in theme.json because they restyle core Navigation submenus and the
   Search block for a dark-bar context. */

/* Links on the navy bar (site title + top-level nav) go white on hover — the
   theme.json link-hover is navy, which would vanish against the bar. Submenu
   links are on the light dropdown and are handled separately below. */
.afp-site-header .wp-block-site-title a:hover,
.afp-site-header .wp-block-site-title a:focus,
.afp-site-header .wp-block-navigation>ul>li>.wp-block-navigation-item__content:hover,
.afp-site-header .wp-block-navigation [aria-current]:not([aria-current="false"])>.wp-block-navigation-item__content {
  color: #fff;
}

/* Menu labels never wrap — the nav row is nowrap (header.html) and multi-word
   labels ("Areas of practice") must not break onto two lines. */
.afp-site-header .wp-block-navigation .wp-block-navigation-item__content {
  white-space: nowrap;
}

/* Dropdown panels: light card on the navy bar. Tight spacing (override the 30px
   top-level blockGap that otherwise double-spaces submenu items) and dark,
   readable text — the 4-class selector beats the inherited navy-100 preset. */
.afp-site-header .wp-block-navigation__submenu-container {
  gap: 0;
  min-width: 250px;
  padding: 0.35rem;
  background-color: var(--wp--preset--color--paper);
  border-color: var(--wp--preset--color--border);
  border-radius: 8px;
  box-shadow: 0 10px 30px rgba(11, 37, 69, 0.2);
}

.afp-site-header .wp-block-navigation .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
  display: block;
  padding: 0.5rem 0.7rem;
  border-radius: 6px;
  color: var(--wp--preset--color--navy);
}

.afp-site-header .wp-block-navigation__submenu-container .wp-block-navigation-item:hover>.wp-block-navigation-item__content,
.afp-site-header .wp-block-navigation__submenu-container .wp-block-navigation-item__content:focus {
  background-color: var(--wp--preset--color--paper-200);
  color: var(--wp--preset--color--link);
}

/* Command-palette search: squircle trigger on the navy bar — width locked to
   height (icon-only everywhere; the label/kbd rules further down keep them
   hidden per the client mock). 40px square matches the 40px logo rhythm. */
.afp-search-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 40px;
  height: 40px;
  padding: 0;
  gap: 0.5rem;
  font: 500 0.85rem/1 var(--wp--preset--font-family--body);
  color: var(--wp--preset--color--navy-100);
  background-color: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 10px;
  cursor: pointer;
}

.afp-search-trigger:hover {
  color: #fff;
  background-color: rgba(255, 255, 255, 0.14);
  border-color: rgba(255, 255, 255, 0.35);
}

.afp-search-trigger svg {
  width: 16px;
  height: 16px;
  fill: currentColor;
}

.afp-search-trigger__kbd {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.72rem;
  padding: 0.05rem 0.3rem;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 4px;
}

/* Search modal — native <dialog>: ESC-close + focus-trap for free. */
.afp-search-modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(600px, 92vw);
  max-height: 80vh;
  margin: 0;
  padding: 0;
  color: var(--wp--preset--color--ink);
  background-color: var(--wp--preset--color--paper);
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(11, 37, 69, 0.28);
}

.afp-search-modal::backdrop {
  background-color: rgba(11, 37, 69, 0.45);
}

.afp-search-modal__form {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem 1.15rem;
}

.afp-search-modal__form svg {
  width: 20px;
  height: 20px;
  flex: none;
  fill: var(--wp--preset--color--muted);
}

.afp-search-modal__form input {
  flex: 1;
  min-width: 0;
  padding: 0.35rem 0;
  font-size: 1.15rem;
  font-family: inherit;
  color: inherit;
  background: transparent;
  border: 0;
}

.afp-search-modal__form input:focus {
  outline: none;
}

.afp-search-modal__close {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.7rem;
  padding: 0.2rem 0.4rem;
  color: var(--wp--preset--color--muted);
  background-color: var(--wp--preset--color--paper-200);
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 4px;
  cursor: pointer;
}

@media (max-width: 600px) {

  /* 44px tap target once the label is gone. Padding alone (content-box, 15px
     icon) lands at ~36px — box-sizing + min-height/width close the gap. The
     project floor is 44px and this trigger was under it. */
  .afp-search-trigger {
    box-sizing: border-box;
    min-width: 44px;
    min-height: 44px;
    padding: 0.6rem;
    justify-content: center;
  }

  .afp-search-trigger__label,
  .afp-search-trigger__kbd {
    display: none;
  }
}

/* User-guide tab — fixed to the left edge, vertically centred (client change,
   2026-08-20; it sat mid-right before). Deliberately NOT a bottom corner:
   .afp-top (bottom-right), .afp-toc-pill (bottom-left) and .afp-dock
   (full-width bottom bar) can all be on screen at once on an Area or case
   page. Mid-edge never collides at any scroll position, and it sits where the
   panel slides from, so it reads as the handle you pull the drawer out by.
   Same z-index as those three. */
.afp-acronyms-tab {
  position: fixed;
  left: 0;
  top: auto;
  bottom: 1.25rem;
  translate: 0 -50%;
  z-index: 90;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  box-sizing: border-box;
  min-width: 36px;
  min-height: 44px;
  padding: 0.7rem 0.5rem;
  border: 0;
  /* Gold spine on the leading edge — the side the tab is pulled out from.
     Near-square corners (2px) keep it reading as an edge-mounted tab rather
     than a floating pill. */
  border-right: 3px solid var(--wp--preset--color--gold);
  border-radius: 0 2px 2px 0;
  background: var(--wp--preset--color--navy);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(11, 47, 74, 0.3);
  /* The label collapsing on tuck resizes this box; containment keeps that
     reflow inside the tab instead of dirtying the page's layout. No
     will-change — the browser promotes for the duration of the transition
     on its own, and a permanent layer for an idle tab is the worse trade. */
  contain: layout;
}

/* Hover lifts to Reference Navy rather than the lighter Link blue: the gold
   bulb below only clears the 3:1 non-text contrast floor against a dark
   ground (5.2:1 here, 2.7:1 on Link blue). */
.afp-acronyms-tab:hover {
  background: var(--wp--preset--color--navy-700);
}

/* Outline bulb in gold — matches the spine, and a hairline drawing reads as a
   mark rather than a filled pictogram at 18px. */
.afp-acronyms-tab svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: var(--wp--preset--color--gold);
  stroke-width: 1.4;
  stroke-linejoin: round;
}

/* Vertical label keeps this a labelled control rather than a bare icon, per
   the no-icon-system rule in .claude/rules/conventions.md. */
.afp-acronyms-tab__label {
  font: 700 0.65rem/1 var(--wp--preset--font-family--body);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
  /* Physical height even in vertical-rl — this is what collapses on tuck.
     Sized for "User Guide". */
  max-height: 9rem;
  overflow: hidden;
}

@media (max-width: 600px) {

  /* No tab on phones (client change): the edge tab competes with body text
     on a narrow measure. The User Guide stays desktop-only. */
  .afp-acronyms-tab {
    display: none;
  }
}

/* Idle tuck — the tab introduces itself once, then gets out of the way. A
   minute in, the label folds up into the bulb; three seconds later the button
   draws its padding in around the bulb and dims, and a cookie remembers it, so
   later pages start tucked. Hover or focus reverses it, box first, label after.

   The bulb itself is never hidden or clipped — the chrome around it shrinks.
   Nothing leaves the viewport, so there's no cropped-button reading and the
   whole control stays a hover target rather than a sliver at the edge.

   The open state is a JS-held `.is-open` class rather than :hover, because
   leaving has to linger for 30s before re-tucking — see the listeners in
   inc/acronyms-panel.php.

   Reverse sequencing falls out of transition-delay, which comes from the state
   being entered. The resting (tucked) rule delays the shrink, so on release
   the label folds away before the box tightens; .is-open zeroes that delay and
   instead delays the label, so the box opens up first. */
.afp-acronyms-tab.is-animated {
  transition: padding 0.55s ease 0.35s, gap 0.55s ease 0.35s,
    min-width 0.55s ease 0.35s, min-height 0.55s ease 0.35s,
    opacity 0.55s ease 0.35s, box-shadow 0.55s ease 0.35s;
}

.afp-acronyms-tab.is-animated .afp-acronyms-tab__label {
  transition: max-height 0.5s ease, opacity 0.35s ease, translate 0.5s ease;
}

/* The gap goes with the label. Left at 0.4rem it reserves dead space under a
   label of zero height, which lands as 6.4px of extra bottom padding and a
   visibly off-centre bulb. */
.afp-acronyms-tab.is-quiet {
  gap: 0;
}

.afp-acronyms-tab.is-quiet .afp-acronyms-tab__label {
  max-height: 0;
  opacity: 0;
  translate: 0 -0.75rem;
}

@media (hover: hover) {

  /* Only where there's a pointer to open it back up. The base 44px minimum is
     a touch-target floor; relaxing it needs a pointer, and ~31px still clears
     the 24px WCAG 2.2 AA target minimum for one. Touch keeps the full tab. */
  .afp-acronyms-tab.is-tucked {
    padding: 0.4rem;
    min-width: 0;
    min-height: 0;
    /* Recedes by weight as well as size — the shadow softens with it so a
       parked control stops casting onto the text it is staying out of. */
    opacity: 0.72;
    box-shadow: 0 1px 4px rgba(11, 47, 74, 0.18);
  }
}

.afp-acronyms-tab.is-quiet.is-open {
  gap: 0.4rem;
}

.afp-acronyms-tab.is-tucked.is-open {
  padding: 0.7rem 0.5rem;
  min-width: 36px;
  min-height: 44px;
  opacity: 1;
  box-shadow: 0 2px 8px rgba(11, 47, 74, 0.3);
  transition-delay: 0s;
}

.afp-acronyms-tab.is-quiet.is-open .afp-acronyms-tab__label {
  max-height: 9rem;
  opacity: 1;
  translate: 0 0;
  transition-delay: 0.4s;
}

@media (prefers-reduced-motion: reduce) {

  .afp-acronyms-tab.is-animated,
  .afp-acronyms-tab.is-animated .afp-acronyms-tab__label {
    transition: none;
  }
}

/* Acronym chip — highlight a known acronym anywhere on the page and its meaning
   appears beside the selection. No click: the definition shows straight away.
   popover="auto" supplies the top layer, light-dismiss and ESC. The UA sheet
   centres popovers with inset:0;margin:auto — undone here so JS can place it
   against the selection rect. */
/* `display` belongs on :popover-open only. Setting it on the base rule keeps the
   chip painted after hidePopover(): the UA sheet hides a closed popover with
   `[popover]:not(:popover-open){display:none}`, and an author declaration beats
   any UA one whatever the specificity — so the box stayed on screen for good
   while the popover API correctly reported itself closed. */
.afp-acronyms-chip {
  position: fixed;
  inset: auto;
  margin: 0;
  z-index: 95;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  max-width: min(22rem, 90vw);
  padding: 0.5rem 0.75rem;
  border: 0;
  border-radius: 6px;
  background: var(--wp--preset--color--navy);
  color: #fff;
  font-family: var(--wp--preset--font-family--body);
  text-align: left;
  box-shadow: 0 4px 14px rgba(11, 47, 74, 0.35);
}

.afp-acronyms-chip__term {
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.06em;
}

.afp-acronyms-chip:popover-open {
  display: flex;
}

.afp-acronyms-chip__def {
  font-size: 0.85rem;
  line-height: 1.4;
}

/* User-guide panel — native <dialog> slid in from the left edge, the side its
   tab is mounted on. */
.afp-acronyms-panel {
  position: fixed;
  inset: 0 auto 0 0;
  width: min(420px, 92vw);
  max-width: none;
  height: 100dvh;
  max-height: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  color: var(--wp--preset--color--ink);
  background-color: var(--wp--preset--color--paper);
  border: 0;
  border-right: 1px solid var(--wp--preset--color--border);
  box-shadow: 12px 0 40px rgba(11, 37, 69, 0.22);
  translate: -100% 0;
  transition: translate 0.25s ease, display 0.25s allow-discrete, overlay 0.25s allow-discrete;
}

.afp-acronyms-panel[open] {
  translate: 0 0;
}

@starting-style {
  .afp-acronyms-panel[open] {
    translate: -100% 0;
  }
}

.afp-acronyms-panel::backdrop {
  background-color: rgba(11, 37, 69, 0.45);
}

@media (prefers-reduced-motion: reduce) {
  .afp-acronyms-panel {
    transition: none;
  }
}

.afp-acronyms-panel__head {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 1rem 1.15rem;
  background-color: var(--wp--preset--color--paper);
  border-bottom: 1px solid var(--wp--preset--color--border);
}

.afp-acronyms-panel__title {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.afp-acronyms-panel__close {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.7rem;
  padding: 0.5rem 0.7rem;
  color: var(--wp--preset--color--muted);
  background-color: var(--wp--preset--color--paper-200);
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 4px;
  cursor: pointer;
}

.afp-acronyms-panel__body {
  padding: 0.5rem 1.15rem 2rem;
}

.afp-acronyms-panel__body>p {
  line-height: 1.6;
}

.afp-acronyms-panel .afp-acronyms-panel__body table {
  width: 100%;
  border-collapse: collapse;
}

/* Content modal (afp/modal, inc/modal.php) — native <dialog>, same centered-card
   recipe as .afp-search-modal above: ESC-close + focus-trap for free. Unlike the
   search modal and the acronyms panel, this one repeats per page — each instance
   gets its own id and assets/modal.js wires up every .afp-modal it finds rather
   than one hardcoded id. */
.afp-modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(600px, 92vw);
  max-height: 80vh;
  margin: 0;
  padding: 1.5rem 1.5rem 1.75rem;
  color: var(--wp--preset--color--ink);
  background-color: var(--wp--preset--color--paper);
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(11, 37, 69, 0.28);
  overflow-y: auto;
}

.afp-modal::backdrop {
  background-color: rgba(11, 37, 69, 0.45);
}

.afp-modal__close {
  position: absolute;
  top: 0.85rem;
  right: 0.9rem;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.7rem;
  padding: 0.2rem 0.4rem;
  color: var(--wp--preset--color--muted);
  background-color: var(--wp--preset--color--paper-200);
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 4px;
  cursor: pointer;
}

.afp-modal__body {
  padding-top: 0.5rem;
}

/* The dialog is a fixed-width card, so an inserted image (core/image, core/gallery)
   has to be held to the body measure rather than pushing the card wider. */
.afp-modal__body :where(img) {
  max-width: 100%;
  height: auto;
}

.afp-modal__body figure {
  margin-left: 0;
  margin-right: 0;
}

/* The trigger is a real <button>, not a link (it sits inline in running text,
   so it must not carry site-chrome styling like .afp-search-trigger's chip).
   Underlined in the content-link colour to match this theme's own in-content
   links (~line 908: "underlined in their own colour"). */
.afp-modal__trigger {
  display: inline;
  padding: 0;
  font: inherit;
  color: var(--wp--preset--color--link);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  background: none;
  border: 0;
  cursor: pointer;
}

.afp-modal__trigger:hover,
.afp-modal__trigger:focus-visible {
  color: var(--wp--preset--color--navy);
}

@media (max-width: 600px) {
  .afp-modal {
    width: 92vw;
    max-height: 85vh;
  }

  /* 44px tap-target floor (project rule — see the same note on
     .afp-search-trigger above): a bare inline text trigger has no padding box
     to expand, so give it a minimum hit area without changing its visual size. */
  .afp-modal__trigger {
    display: inline-block;
    min-height: 44px;
    line-height: 44px;
  }
}

/* Two classes + an extra element, the same trick the content tables use
   below (~539-545/600): the extracted table keeps its live `is-style-stripes`
   class, and core's `.wp-block-table.is-style-stripes td` (0,2,1) beats a
   single-class selector outright — border:0 before border-bottom because
   core's stripes rule sets border-color, not just border-bottom. */
.afp-acronyms-panel .afp-acronyms-panel__body table td {
  padding: 0.5rem 0.6rem 0.5rem 0;
  font-size: 0.95rem;
  line-height: 1.45;
  vertical-align: top;
  border: 0;
  border-bottom: 1px solid var(--wp--preset--color--border);
}

.afp-acronyms-panel .afp-acronyms-panel__body table td:first-child {
  width: 6.5rem;
  font-weight: 700;
}

/* Hides the header row and, with it, core's `.wp-block-table thead` 3px
   border-bottom — hiding just `th` (as before) left that line stranded. */
.afp-acronyms-panel .afp-acronyms-panel__body thead {
  display: none;
}

/* Kill the core zebra fill so rows read as theme-token hairlines, not
   hardcoded #f0f0f0 stripes (same override as line ~600 for content tables). */
.afp-acronyms-panel .afp-acronyms-panel__body .wp-block-table.is-style-stripes tbody tr:nth-child(odd) {
  background-color: transparent;
}

/* Home hero — split layout: paper text panel left, photo (Cover block, editor-
   controlled overlay) right with an angled leading edge. Stacks on mobile. */
.afp-hero-split {
  position: relative;
  display: grid;
  grid-template-columns: minmax(22rem, 42%) 1fr;
}

/* Absolutely fill the band's right side so the photo meets the header, the
   viewport edge, and the section below with no flow margins in between. */
.afp-hero-split__media {
  position: absolute;
  inset: 0 0 0 38%;
  margin: 0;
  min-height: 0 !important;
  clip-path: polygon(12% 0, 100% 0, 100% 100%, 0 100%);
}

/* Short gold rule under headings (separator block; block-valid markup, width
   here since the separator can't serialize a custom width). */
/* :not() matches core's .wp-block-separator:not(...):not(...) specificity. */
.wp-block-separator.afp-rule:not(.is-style-dots) {
  width: 3rem;
}

.afp-hero-split .afp-rule {
  margin-left: 0;
}

/* Header logo — sized here so the image block stays attribute-clean. The figure
   never shrinks: the masthead row is nowrap on phones, so a flexible logo gets
   squeezed horizontally while `height` holds — a distorted emblem. */
.afp-site-logo {
  flex: none;
}

/* The cropped UNU-CPR lockup carries no built-in margins (unlike the old
   _WH export, whose transparent padding faked the gaps), so its breathing
   room lives here: 13px above/below (a 40px mark centred in a 66px masthead —
   margins, not row padding, so the air survives layout changes) and 10px
   toward the wordmark on top of the row's 14px gap. Two classes to out-rank
   core's flex-child reset, `.is-layout-flex > :is(*, div) { margin: 0 }`. */
.afp-site-header .afp-site-logo {
  margin: 13px 10px 13px 0;
}

.afp-site-logo img {
  height: 40px;
  width: auto;
}

/* The directory row sits flush under the hero (no main blockGap). */
main>.afp-hero-split+.afp-directory {
  margin-block-start: 0;
}

@media (max-width: 781px) {
  .afp-hero-split {
    grid-template-columns: 1fr;
    /* The band inherits ~40px root side padding; with the photo full-bleed
       behind the text the gutter is the content panel's job (below). */
    padding-left: 0;
    padding-right: 0;
  }

  /* AR design revisions (17 Aug), Home §3(a): the photo no longer stacks as
     its own full-height band. It backs the text panel instead — the cover's
     object-fit crops it responsively to whatever the text needs, so the title,
     standfirst and CTA all land inside the first screen view. Done in CSS
     because the front-page template is a flattened DB copy (see the
     .afp-directory note below) — pattern edits never reach the homepage. */
  .afp-hero-split__media {
    position: absolute;
    inset: 0;
    clip-path: none;
    min-height: 0 !important;
  }

  /* Aim the crop at the hall's gold wall and emblem, just above centre. */
  .afp-hero-split__media .wp-block-cover__image-background {
    object-position: 50% 42%;
  }

  /* Deepen the editor's 30% dim into a navy scrim: white 17px text on navy
     at this opacity over the photo's brightest gold holds WCAG AA. !important
     because core's per-ratio rule (.has-background-dim-NN, 0,4,0) outguns any
     ratio-agnostic selector, and the ratio is the editor's to change. */
  .afp-hero-split__media .wp-block-cover__background.has-background-dim {
    background-color: var(--wp--preset--color--navy) !important;
    opacity: 0.72 !important;
  }

  /* Lift the text panel above the (later-in-DOM, positioned) cover. The
     block's inline padding sizes the panel for the desktop split (48/32px
     sides on top of the band's root padding — a ~230px measure on a phone);
     over the full-bleed photo the text runs broader, aligned to the site's
     20px base gutter. !important: it must beat the inline style. */
  .afp-hero-split__content {
    position: relative;
    z-index: 1;
    padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--30) !important;
  }

  /* The panel's navy/ink presets carry !important, so matching force here. */
  .afp-hero-split__content .has-navy-color,
  .afp-hero-split__content .has-ink-color {
    color: var(--wp--preset--color--white) !important;
    text-shadow: 0 1px 3px rgba(11, 47, 74, 0.6);
  }

  /* Navy button would sink into the scrim — invert it. */
  .afp-hero-split__content .wp-block-button__link {
    background-color: var(--wp--preset--color--white) !important;
    color: var(--wp--preset--color--navy) !important;
  }
}

/* Home directory — flat columns with hairline dividers, centred content,
   sliding gold arrow on the link (mirrors the card-grid affordance). */
.afp-directory__grid {
  row-gap: var(--wp--preset--spacing--40);
}

/* Span the full band, not the 77rem content column — the five columns are
   navigation, so they read as a rail edge-to-edge (per the landing mock).
   Done in CSS, not on the block's layout attribute, because the front-page
   template is customised in the DB: it holds a flattened copy of this pattern
   and edits to patterns/home-section-directory.php never reach the homepage.
   Beats core's constrained rule, whose selector is a single class in :where(). */
.afp-directory>.afp-directory__grid {
  max-width: none;
  /* auto-fit, not core's auto-fill: with five items in a six-track row the
     spare track would stay open and shove the columns to the left. auto-fit
     collapses it so the five always share the full width evenly. */
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}

.afp-directory__item {
  border-left: 1px solid var(--wp--preset--color--border);
}

/* Reserve two heading lines so the gold rules share a baseline even when one
   title ("Assembly for Peace Handbook") wraps. Desktop-only: single-column
   phones don't stagger. */
@media (min-width: 782px) {
  .afp-directory__item .wp-block-heading {
    min-height: 2.6em;
    display: flex;
    align-items: flex-end;
    justify-content: center;
  }

  /* The rules align from the top; the links have to align from the bottom,
     because the blurbs run 3–5 lines. Flex column + auto margin soaks up the
     slack so all five links land on one baseline, as in the landing mock. */
  .afp-directory__item {
    display: flex;
    flex-direction: column;
  }

  .afp-directory__link {
    margin-block-start: auto;
  }
}

.afp-directory__item:first-child {
  border-left: none;
}

.afp-directory__link a {
  text-decoration: none;
  white-space: nowrap;
  /* keep the gold arrow on the same line as the label */
}

.afp-directory__link a::after {
  content: "\2192";
  display: inline-block;
  margin-left: 0.4em;
  color: var(--wp--preset--color--gold);
  transition: transform 0.18s ease;
}

.afp-directory__link a:hover::after,
.afp-directory__link a:focus::after {
  transform: translateX(5px);
}

/* Directory cards — interactive lift + gold accent + sliding arrow. Perceived
   quality comes from the affordance: a card that responds reads as clickable. */
.afp-card-grid .is-style-afp-card {
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

.afp-card-grid .is-style-afp-card:hover,
.afp-card-grid .is-style-afp-card:focus-within {
  transform: translateY(-4px);
  border-color: var(--wp--preset--color--gold);
  box-shadow: 0 14px 30px rgba(11, 37, 69, 0.12);
}

.afp-card-grid .is-style-afp-card h3 a {
  text-decoration: none;
}

.afp-card-grid .is-style-afp-card h3 a::after {
  content: "\2192";
  display: inline-block;
  margin-left: 0.4em;
  color: var(--wp--preset--color--gold);
  transition: transform 0.18s ease;
}

.afp-card-grid .is-style-afp-card:hover h3 a::after,
.afp-card-grid .is-style-afp-card:focus-within h3 a::after {
  transform: translateX(5px);
}

/* Home timeline teaser — landmark GA actions as gold nodes on a navy spine.
   Layout only; colours/type come from token classes in the pattern markup. */
.afp-timeline__track {
  position: relative;
  align-items: flex-start;
}

.afp-timeline__track::before {
  content: "";
  position: absolute;
  top: 6px;
  left: 7px;
  right: 7px;
  height: 2px;
  background: var(--wp--preset--color--navy-500);
}

.afp-timeline__item {
  position: relative;
  flex: 1 1 0;
  min-width: 140px;
  padding-top: 2rem;
}

.afp-timeline__item::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--wp--preset--color--gold);
  box-shadow: 0 0 0 4px var(--wp--preset--color--navy);
}

/* Links on the navy band. The global link element styles are tuned for light
   backgrounds: #2F6C94 lands at 2.4:1 here, and the global hover colour is
   navy — this band's own background — so the link vanishes under the pointer.
   Inherit the band's colour (gold, 6.6:1) and brighten to white on hover, the
   same convention the footer already uses. */
.afp-timeline a {
  color: inherit;
}

.afp-timeline a:hover,
.afp-timeline a:focus-visible {
  color: #fff;
}

@media (max-width: 781px) {
  .afp-timeline__track {
    overflow-x: auto;
    padding-bottom: 0.75rem;
    scroll-snap-type: x proximity;
  }

  .afp-timeline__item {
    min-width: 62vw;
    scroll-snap-align: start;
  }
}

/* Above the mobile band the five teaser items must be allowed to shrink —
   flex's min-width:auto floor (longest label) otherwise forces a page-wide
   horizontal scrollbar below ~1048px. */
@media (min-width: 782px) {
  .afp-timeline__item {
    min-width: 0;
  }
}

/* ---------------------------------------------------------------------------
   "Diplomatic Editorial" content layer — treaty-annex typography for every
   content page. All selectors scope to post content or opt-in classes, so
   pages editors assemble from patterns inherit the craft with zero effort.
--------------------------------------------------------------------------- */

/* Reading progress: hairline gold bar under the header, driven by pure CSS
   scroll-timeline. Browsers without support simply never show it. */
@supports (animation-timeline: scroll()) {
  .afp-progress {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 99;
    width: 100%;
    height: 3px;
    background: linear-gradient(90deg, var(--wp--preset--color--gold), var(--wp--preset--color--blue));
    transform-origin: 0 50%;
    transform: scaleX(0);
    animation: afp-progress linear both;
    animation-timeline: scroll(root);
  }

  @keyframes afp-progress {
    from {
      transform: scaleX(0);
    }

    to {
      transform: scaleX(1);
    }
  }
}

/* Page title: the treaty double rule — a short gold bar sitting on a full
   hairline. The signature mark of the site. */
main .wp-block-post-title {
  padding-bottom: 0.6em;
  background:
    linear-gradient(var(--wp--preset--color--gold), var(--wp--preset--color--gold)) left bottom / 64px 3px no-repeat,
    linear-gradient(var(--wp--preset--color--border), var(--wp--preset--color--border)) left bottom / 100% 1px no-repeat;
}

/* Sections read as numbered annex articles: mono gold "§ 01" counters and a
   hairline rule above each h2 — automatic, so editors just write headings. */
main .wp-block-post-content {
  counter-reset: afp-section;
}

main .wp-block-post-content>h2 {
  counter-increment: afp-section;
  border-top: 1px solid var(--wp--preset--color--border);
  padding-top: var(--wp--preset--spacing--40);
  margin-top: var(--wp--preset--spacing--50);
}

main .wp-block-post-content>h2::before {
  content: "\00a7\2009" counter(afp-section, decimal-leading-zero);
  display: block;
  margin-bottom: 0.5rem;
  font: 600 0.8rem/1 var(--wp--preset--font-family--mono);
  letter-spacing: 0.14em;
  color: var(--wp--preset--color--gold-dark);
}

/* Content links: underlined in their own colour (gold underlines were dropped —
   the mocks show link-coloured rules), thickening on hover. */
main .wp-block-post-content a:not(.wp-block-button__link) {
  text-decoration-color: currentColor;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  transition: text-decoration-thickness 0.15s ease;
}

main .wp-block-post-content a:not(.wp-block-button__link):hover {
  text-decoration-thickness: 2px;
}

/* ── Tables ──────────────────────────────────────────────────────────────
   One look for every table on the site, applied without a class so a table
   an editor inserts today matches the twenty already in the content: a
   hairline card wearing the gold top rule the theme's cards wear, a tinted
   header strip, hairline rows, and bands for any row that spans the table.

   Keyed on `.wp-block-post-content .wp-block-table` because core's own
   `.wp-block-table.is-style-stripes` rules are two classes deep — a single
   class loses to them, and most of the content tables carry that style.
   Departures from this base are the registered options further down. */
main .wp-block-post-content .wp-block-table {
  border: 1px solid var(--wp--preset--color--border);
  border-top: 3px solid var(--wp--preset--color--gold);
  border-radius: 10px;
  background-color: var(--wp--preset--color--paper);
}

/* Separate borders, not collapsed: the card cannot round its corners under
   `border-collapse: collapse`. */
main .wp-block-post-content .wp-block-table table {
  border-collapse: separate;
  border-spacing: 0;
}

main .wp-block-post-content .wp-block-table td,
main .wp-block-post-content .wp-block-table th {
  vertical-align: top;
  text-align: left;
  padding: 0.85rem 1rem;
  border: 0;
  border-bottom: 1px solid var(--wp--preset--color--border);
}

main .wp-block-post-content .wp-block-table tbody tr:last-child td {
  border-bottom: 0;
}

/* A tinted header strip rather than a heavy navy underline: inside a card the
   weight is redundant. (Not sticky — the figure's own overflow-x makes it the
   scrollport, so a sticky header would never move.) */
main .wp-block-post-content .wp-block-table th {
  background-color: var(--wp--preset--color--paper-200);
  font: 600 0.7rem/1.4 var(--wp--preset--font-family--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp--preset--color--navy-700);
}

main .wp-block-post-content .wp-block-table thead tr:first-child th:first-child {
  border-top-left-radius: 9px;
}

main .wp-block-post-content .wp-block-table thead tr:first-child th:last-child {
  border-top-right-radius: 9px;
}

/* A column floor: on a phone the table scrolls sideways rather than squeezing
   every column down to a word apiece. Rows that span the table are exempt. */
main .wp-block-post-content .wp-block-table td:not([colspan]) {
  min-width: 9rem;
}

/* A row spanning every column groups the rows beneath it — a decade in the
   timeline, a mechanism in the investigatory table. */
main .wp-block-post-content .wp-block-table td[colspan] {
  background-color: var(--wp--preset--color--pale-blue);
  color: var(--wp--preset--color--navy);
  font-size: 0.95rem;
  border-bottom: 1px solid var(--wp--preset--color--navy-100);
}

main .wp-block-post-content .wp-block-table tbody tr:hover td[colspan] {
  background-color: var(--wp--preset--color--pale-blue);
}

/* A spanning header cell is a sentence, not a column label: uppercase mono at
   that length is unreadable. */
main .wp-block-post-content .wp-block-table th[colspan] {
  font-family: inherit;
  font-size: 0.95rem;
  letter-spacing: 0;
  text-transform: none;
  border-bottom: 0;
  padding-bottom: 0;
}

main .wp-block-post-content .wp-block-table tbody tr:hover {
  background-color: var(--wp--preset--color--paper-200);
}

main .wp-block-post-content .wp-block-table.is-style-stripes tbody tr:nth-child(odd) {
  background-color: transparent;
}

/* A note a table closes on sits under the card, not in it. */
.afp-reftable-note {
  max-width: 52rem;
}

/* Option — Compact. For long lookup tables (the abbreviations list runs to 46
   rows) where the default row height turns the page into a scroll. */
main .wp-block-post-content .wp-block-table.is-style-afp-table-compact td,
main .wp-block-post-content .wp-block-table.is-style-afp-table-compact th {
  padding: 0.45rem 0.7rem;
  font-size: 0.92rem;
}

main .wp-block-post-content .wp-block-table.is-style-afp-table-compact th {
  font-size: 0.65rem;
}

main .wp-block-post-content .wp-block-table.is-style-afp-table-compact td:not([colspan]) {
  min-width: 7rem;
}

/* Option — Grid lines. Vertical rules as well as horizontal, for matrix data
   where the eye has to track across columns rather than read down one. */
main .wp-block-post-content .wp-block-table.is-style-afp-table-grid td+td,
main .wp-block-post-content .wp-block-table.is-style-afp-table-grid th+th {
  border-left: 1px solid var(--wp--preset--color--border);
}

/* Option — Plain. No card at all: the bare ledger the theme used before, for a
   two-column table inside a run of prose where a card would over-furnish it. */
main .wp-block-post-content .wp-block-table.is-style-afp-table-plain {
  border: 0;
  border-radius: 0;
  background-color: transparent;
}

main .wp-block-post-content .wp-block-table.is-style-afp-table-plain th {
  background-color: transparent;
  color: var(--wp--preset--color--navy);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  border-bottom: 2px solid var(--wp--preset--color--navy);
}

main .wp-block-post-content .wp-block-table.is-style-afp-table-plain td:first-child,
main .wp-block-post-content .wp-block-table.is-style-afp-table-plain th:first-child {
  padding-left: 0;
}

main .wp-block-post-content .wp-block-table.is-style-afp-table-plain td:last-child,
main .wp-block-post-content .wp-block-table.is-style-afp-table-plain th:last-child {
  padding-right: 0;
}

@media (max-width: 781px) {

  main .wp-block-post-content .wp-block-table td,
  main .wp-block-post-content .wp-block-table th {
    padding: 0.7rem 0.8rem;
  }
}

/* Clean list ("AFP Clean list"): gold arrow markers instead of bullets. */
/* Plain link list (client design: no arrow/bullet markers on nav or panel lists). */
.is-style-afp-checklist {
  list-style: none;
  padding-left: 0;
}

.is-style-afp-checklist>li {
  padding-left: 0;
}

/* Cards anywhere in content behave like the home directory cards — but only
   when they actually contain a heading link (no false clickable affordance). */
main .wp-block-post-content .is-style-afp-card {
  border-top: 3px solid var(--wp--preset--color--gold);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

main .wp-block-post-content .is-style-afp-card:has(h3 a):hover,
main .wp-block-post-content .is-style-afp-card:has(h3 a):focus-within,
main .wp-block-post-content .afp-resource-row.is-style-afp-card:hover,
main .wp-block-post-content .afp-resource-row.is-style-afp-card:focus-within {
  transform: translateY(-4px);
  border-color: var(--wp--preset--color--gold);
  box-shadow: 0 14px 30px rgba(11, 37, 69, 0.12);
}

main .wp-block-post-content .is-style-afp-card h3 a {
  text-decoration: none;
}

/* One quiet entrance: content rises in once. The global reduced-motion
   kill switch above disables it. `backwards`, not `both`: a transform
   animation that keeps filling forwards leaves <main> a containing block
   for every position:fixed descendant (the provenance tip anchored to the
   column instead of the viewport). The end frame equals the natural state,
   so detaching after the run changes nothing visually. */
main.wp-block-group {
  animation: afp-enter 0.45s ease-out backwards;
}

@keyframes afp-enter {
  from {
    opacity: 0;
    transform: translateY(10px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* Selection + keyboard focus carry the accent. */
::selection {
  background-color: var(--wp--preset--color--gold-tint);
  color: var(--wp--preset--color--navy);
}

:focus-visible {
  outline: 2px solid var(--wp--preset--color--gold);
  outline-offset: 2px;
}

/* Footer links: light on navy, underline on hover. */
.afp-site-footer a {
  color: var(--wp--preset--color--navy-100);
  text-decoration: none;
}

.afp-site-footer a:hover,
.afp-site-footer a:focus {
  color: #fff;
  text-decoration: underline;
}

/* Short gold rule under page titles (client design: title + gold accent rule). */
/* Gold title rule: core sizes separators with a :not() chain and centres
   layout children with !important, so both have to be out-specified. */
.wp-block-separator.afp-title-rule:not(.is-style-wide) {
  width: 48px;
  height: 4px;
  border: none;
  margin-left: 0 !important;
  margin-right: auto !important;
}

/* Smaller gold tick used as the row marker in editorial list rows
   (Areas of Practice list — replaces the numeral of the thematic index).
   Three classes to out-cascade core's `.wp-block-separator:not(...):not(...)`
   100px default width. */
.wp-block-separator.has-gold-background-color.afp-row-rule,
.afp-row-rule {
  flex: none;
  width: 28px;
  height: 4px;
  border: none;
  margin: 0;
}

/* Line-icon row marker in the Areas of Practice list (replaces the gold tick).
   Color is structural (navy), never per-topic. Carried by a core/image block so
   the block editor renders it exactly as the front end does — a core/html block
   would be a 300x300 sandboxed iframe in the canvas. */
.afp-row-icon {
  flex: none;
  margin: 0;
}

.afp-row-icon img {
  display: block;
  width: 28px;
  height: 28px;
}

/* Header per client mock: icon-only search trigger, underlined active nav item,
   and the mobile drawer up to 1200px so the nowrap nav never overflows. */
.afp-search-trigger__label,
.afp-search-trigger__kbd {
  display: none;
}

.afp-site-header .wp-block-navigation>ul>li>.wp-block-navigation-item__content {
  padding-bottom: 3px;
  border-bottom: 2px solid transparent;
}

.afp-site-header .wp-block-navigation>ul>li>[aria-current]:not([aria-current="false"]) {
  border-bottom-color: #fff;
}

@media (min-width: 600px) and (max-width: 1023px) {
  .afp-site-header .wp-block-navigation__responsive-container-open:not(.always-shown) {
    display: flex;
  }

  .afp-site-header .wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) {
    display: none;
  }
}

/* Tablet band [AR-G7]: the horizontal nav used to give way to the drawer below
   1200px; compacting every gap the row carries lets it hold a single line down
   to 1024px (iPad landscape) before collapsing. !important only where the
   value being beaten is an inline block style (font sizes, bar padding). */
@media (min-width: 1024px) and (max-width: 1279px) {
  .afp-site-header {
    padding-left: 12px !important;
    padding-right: 12px !important;
  }

  /* The wordmark's 0.06em tracking alone is ~14px across the line. */
  .afp-site-header .wp-block-site-title {
    letter-spacing: 0.03em !important;
  }

  .afp-search-trigger {
    width: 36px;
    height: 36px;
  }

  /* Fluid gaps: breathing room that grows with the viewport — ~11px between
     items at the 1024px floor, ~18px by 1280 where full sizing resumes. */
  .afp-site-header .wp-block-navigation,
  .afp-site-header .wp-block-navigation .wp-block-navigation__container {
    gap: clamp(11px, 3vw - 20px, 18px);
    font-size: 0.8125rem !important;
  }

  .afp-site-header .wp-block-site-title {
    font-size: 0.75rem !important;
  }

  /* The masthead row's own two-group gap (32px blockGap) is the last spare. */
  .afp-site-header>.wp-block-group.alignwide {
    gap: 8px;
  }

  /* Logo drops to a 32px mark, still centred in the 66px bar. */
  .afp-site-header .afp-site-logo {
    margin: 17px 4px 17px 0;
  }

  .afp-site-header .afp-site-logo img {
    height: 32px;
  }

  .afp-site-header .wp-block-group:has(> .afp-site-logo) {
    gap: clamp(10px, 2vw - 10px, 16px);
  }

  /* nav ↔ search trigger */
  .afp-site-header .wp-block-group:has(> .wp-block-navigation) {
    gap: 10px;
  }
}

/* Open drawer (reworked 2026-08-19): a navy sheet matching the header bar, in
   place of the old white list with every submenu expanded. Top-level rows are
   white 44px bars split by hairlines; the three section submenus (Areas of
   Practice, Cases of Practice, Resource Centre) collapse behind a full-size
   chevron toggle and start closed — the server never renders
   aria-expanded="true", and core flips the attribute (and rotates the
   chevron) on tap. The layout flatten below is still needed: the nav is a
   right-justified row of dark-bar dropdown cards, and both traits leak into
   the overlay. */
.afp-site-header .wp-block-navigation__responsive-container.is-menu-open,
.afp-site-header .is-menu-open .wp-block-navigation__container {
  /* the <ul> repeats the nav's items-justified-right class, so the override has
     to land on it too — inheriting from the container isn't enough */
  --navigation-layout-justification-setting: flex-start;
}

.afp-site-header .wp-block-navigation:not(.has-background) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) {
  /* core's own gutter is clamp(1rem, var(--wp--style--root--padding-left), 20rem);
     the theme sets no root padding, so the clamp is invalid and drops to 0 */
  padding: 1rem var(--wp--preset--spacing--40);
  /* the sheet wears the header's own navy. Core paints #fff with both :not()
     qualifiers spelled out — (0,5,0), each :not(.x) counts as a class — so
     this selector repeats them plus .afp-site-header to out-rank it. */
  background-color: var(--wp--preset--color--navy);
  color: #fff;
}

.afp-site-header .wp-block-navigation .is-menu-open .wp-block-navigation__submenu-container,
.afp-site-header .wp-block-navigation .is-menu-open .wp-block-navigation__container {
  /* the 24px row blockGap doubles the drawer's height; the 44px rows already
     separate the links */
  gap: 0;
}

/* Brand row at the top of the sheet (injected by drawers.js): the header's
   logo and site name, linking home. It takes over the top strip that core
   pads out for the close button, sharing the row with the X — hence the
   right padding holding its text clear of it. Never rendered in the inline
   desktop nav row. */
.afp-nav-brand {
  display: none;
}

.afp-site-header .wp-block-navigation .is-menu-open .wp-block-navigation__responsive-container-content {
  padding-top: 0.25rem;
  /* the brand row replaces core's 2rem+24px X-strip */
}

.afp-site-header .is-menu-open .afp-nav-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  margin-bottom: 0.5rem;
  padding: 0 44px 0.5rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.14);
  color: #fff;
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
}

.afp-site-header .is-menu-open .afp-nav-brand img {
  height: 28px;
  width: auto;
}

/* Full-width rows so the hairlines and tap areas span the sheet (the
   justification override otherwise shrink-wraps each item to its label). */
.afp-site-header .is-menu-open .wp-block-navigation__container {
  width: 100%;
}

.afp-site-header .wp-block-navigation .is-menu-open .wp-block-navigation__container>li {
  width: 100%;
}

.afp-site-header .is-menu-open .wp-block-navigation__container>li+li {
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}

.afp-site-header .wp-block-navigation .is-menu-open .wp-block-navigation-item__content {
  display: flex;
  align-items: center;
  min-height: 44px;
  /* tap target */
  white-space: normal;
  /* the nowrap row rule would clip long labels */
  color: #fff;
}

/* Section rows: label left, chevron toggle right (core stacks overlay items
   into columns and hides the toggle; here the toggle is the accordion
   control, sized to a full tap target). */
.afp-site-header .wp-block-navigation .is-menu-open li.wp-block-navigation-submenu {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
}

.afp-site-header .wp-block-navigation .is-menu-open li.wp-block-navigation-submenu>.wp-block-navigation-item__content {
  flex: 1;
}

.afp-site-header .wp-block-navigation .is-menu-open .wp-block-navigation__submenu-icon {
  /* four classes: core hides the icon in the overlay at (0,4,0) */
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  /* tap target */
  margin: 0;
  color: inherit;
}

.afp-site-header .is-menu-open .wp-block-navigation__submenu-icon svg {
  /* core sizes the chevron from the button (height:inherit) — 44px of arrow */
  width: 14px;
  height: 14px;
}

/* Collapsed by default: no submenu until its toggle reports open. */
.afp-site-header .is-menu-open .wp-block-navigation-submenu__toggle:not([aria-expanded="true"])+.wp-block-navigation__submenu-container {
  display: none;
}

/* Open submenu: an indented navy-100 list behind a hairline spine — the same
   quiet structure cue the rail drawers use, recolored for the navy sheet. */
.afp-site-header .wp-block-navigation .is-menu-open .wp-block-navigation__submenu-container {
  flex-basis: 100%;
  box-shadow: none;
  border-radius: 0;
  margin: 0 0 0.5rem;
  padding: 0 0 0 0.85rem;
  border-left: 2px solid var(--wp--preset--color--navy-500);
}

.afp-site-header .wp-block-navigation .is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
  min-height: 44px;
  padding: 0 0.5rem;
  border-radius: 4px;
  color: var(--wp--preset--color--navy-100);
}

.afp-site-header .is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item:hover>.wp-block-navigation-item__content,
.afp-site-header .is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item__content:focus {
  /* the desktop dropdown's paper hover chip would glare on the navy sheet */
  background-color: rgba(255, 255, 255, 0.08);
  color: #fff;
}

/* Hero band emblem accent — faded UN emblem bleeding off the right edge,
   per the client mocks (page-title bands on About/Handbook/Areas/Cases). */
.afp-hero-band {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  /* ponytail: the band's height lives here, not in each page's stored padding.
     Pages were built from several patterns over time and drifted across three
     spacing steps (2rem / 3rem / 4.5rem); every page now opens the same, and a
     page saved with a stale value simply follows. Only the content inside the
     band should vary. Change this one pair to restyle every page title. */
  padding-top: var(--wp--preset--spacing--50) !important;
  padding-bottom: var(--wp--preset--spacing--50) !important;
}

/* The content wrapper every page pattern places directly under the hero band
   opens with its own padding-top:50 (3rem, a block attribute baked into each
   page's stored content, not this stylesheet) AND picks up the layout's 1.5rem
   blockGap as a margin-block-start — together that's the white gap between the
   hero and the main content, separate from the band's own (symmetric, left
   alone above) padding. Zero the blockGap margin and halve the padding so every
   pattern page matches the single-case layout (band 3rem + 1.5rem = 4.5rem).
   Targeted structurally so already-published pages get it too, without touching
   their stored content. */
main .afp-hero-band+.wp-block-group {
  margin-block-start: 0 !important;
  padding-top: calc(var(--wp--preset--spacing--50) * 0.5) !important;
}

/* Phones shrink the band's whitespace, never its type (design spec p14). */
@media (max-width: 781px) {
  .afp-hero-band {
    padding-top: var(--wp--preset--spacing--40) !important;
    padding-bottom: calc(var(--wp--preset--spacing--40) * 0.5) !important;
  }
}

.afp-hero-band::after {
  content: "";
  position: absolute;
  z-index: -1;
  top: -15%;
  right: -70px;
  width: min(420px, 40vw);
  height: 130%;
  background: url(assets/un-emblem-blue.svg) no-repeat center / contain;
  opacity: 0.14;
  pointer-events: none;
}

/* Icon chips — small circular accents per the client About mock. The chip is a
   core/image block (navy SVG from assets/icons/) wrapped in the disc, so the
   editor canvas renders it exactly as the front end; a core/html block would be
   a 300x300 sandboxed iframe there. The glyph navy is baked into the SVG files.
   Default chip is pale-blue on white; inside a pale-blue panel it inverts. */
.afp-icon-chip {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background-color: var(--wp--preset--color--pale-blue);
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
}

/* On a pale-blue panel the chip deepens a shade rather than going white
   (client About mock). */
.has-pale-blue-background-color .afp-icon-chip {
  background-color: var(--wp--preset--color--navy-100);
}

.afp-icon-chip img {
  display: block;
  width: 22px;
  height: 22px;
}

/* Bare variant: the glyph alone, no disc — the mock's pull-quote mark. */
.afp-icon-chip.is-bare,
.has-pale-blue-background-color .afp-icon-chip.is-bare {
  width: 2rem;
  height: 2rem;
  background: none;
  align-items: flex-start;
}

.afp-icon-chip.is-bare img {
  width: 2rem;
  height: 2rem;
}

/* About page (client "Sample about page" mock) --------------------------- */
/* Landing title over a narrow measure, per the mock's hero. Sized ~1.4x the
   standard band title (huge, 2.5rem) — the ratio the client mocks show between
   the About hero and the other page-title bands. */
.afp-hero-band .afp-hero-title {
  max-width: 32rem;
  /* core's constrained layout centres children with !important */
  margin-inline: 0 !important;
}

.afp-hero-title h1 {
  font-size: clamp(2.25rem, 4.5vw, 3.5rem);
  line-height: 1.05;
}

/* Rail sits behind a hairline; its cards are separated by full-width rules. */
.afp-about-rail {
  border-left: 1px solid var(--wp--preset--color--border);
  padding-left: 2.25rem;
}

.afp-about-rail>.wp-block-separator {
  margin-block: var(--wp--preset--spacing--40);
}

/* The rail is too narrow for the side-by-side On-this-page columns used in the
   main column, so its links stack as rows — on the checklist rhythm (0.55rem,
   .is-style-afp-checklist) the Handbook-sections rail list uses. */
.afp-about-rail .afp-onpage-links {
  grid-auto-flow: row;
  grid-auto-columns: auto;
  gap: 0.55rem;
}

.afp-about-rail .afp-onpage-links a {
  padding: 0;
  border-left: 0;
}

/* Quote card and descriptor: glyph in its own column, text block beside it. */
.afp-rail-quote>.wp-block-group,
.afp-rail-descriptor>.wp-block-group {
  flex: 1;
  min-width: 0;
}

.afp-rail-descriptor .wp-block-heading {
  margin-top: 0;
}

/* Disclaimer / attribution row: icon column, text aligned to its heading,
   the two notes split by a hairline. */
.afp-about-notes>.wp-block-column+.wp-block-column {
  border-left: 1px solid var(--wp--preset--color--border);
  padding-left: var(--wp--preset--spacing--50);
}

.afp-about-notes .wp-block-group>.wp-block-group {
  flex: 1;
  min-width: 0;
}

.afp-about-notes .wp-block-heading {
  margin-top: 0;
}

/* Phones: the columns stack, so the vertical hairlines go away. */
@media (max-width: 781px) {

  .afp-about-rail,
  .afp-about-notes>.wp-block-column+.wp-block-column {
    border-left: 0;
    padding-left: 0;
  }
}

/* Standalone action links (label + →) carry no underline in the mocks. */
.afp-plain-link a {
  text-decoration: none;
}

.afp-plain-link a:hover,
.afp-plain-link a:focus-visible {
  text-decoration: underline;
}

/* Anchor target kept for the "On this page" jump without a visible heading. */
.afp-vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Cases library — theme clusters and case finder (client cases-of-practice mock). */
.afp-theme-cluster {
  border-bottom: 1px solid var(--wp--preset--color--border);
  padding: 0.9rem 0;
}

.afp-theme-cluster summary {
  cursor: pointer;
  color: var(--wp--preset--color--navy);
  font-size: var(--wp--preset--font-size--large);
}

.afp-theme-cluster summary:hover {
  color: var(--wp--preset--color--link);
}

.afp-theme-cluster>p {
  margin: 0.5rem 0 0;
  color: var(--wp--preset--color--muted);
  font-size: var(--wp--preset--font-size--small);
}

.afp-theme-cluster>ul {
  list-style: none;
  padding: 0.5rem 0 0 1rem;
  margin: 0;
}

.afp-theme-cluster>ul>li {
  padding: 0.3rem 0;
}

.afp-case-select {
  width: 100%;
  padding: 0.6rem 0.8rem;
  font: 400 1rem var(--wp--preset--font-family--body);
  color: var(--wp--preset--color--ink);
  background-color: #fff;
  border: 1px solid var(--wp--preset--color--blue);
  border-radius: 6px;
}

/* Area of Practice head (client "Sample areas of practice" mock): breadcrumb,
   then a display-size title over a ~46rem measure. The trail is placed by
   inc/breadcrumbs.php and looks the same on every page that gets one. */
.afp-breadcrumb {
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
  margin: 0 0 0.5rem;
  line-height: 1.4;
}

/* Every crumb sits the same distance below the masthead: spacing 50, which is
   what the case single's <main> already uses. Pale title bands were given their
   own (varying) top padding before they carried a crumb, so the one holding a
   crumb is pulled back to that measure — !important because the band's padding
   is an inline style from the editor. */
.afp-hero-band:has(> .afp-breadcrumb) {
  padding-top: var(--wp--preset--spacing--50) !important;
}

.afp-breadcrumb a {
  color: var(--wp--preset--color--link);
}

.afp-area-head {
  position: relative;
  /* anchors the above-title provenance line */
  max-width: 46rem;
  margin-inline: 0 !important;
  /* core centres constrained children */
}

.afp-area-head h1 {
  font-size: clamp(1.9rem, 3.4vw, 2.85rem);
  line-height: 1.15;
}

/* "On this page" box (area pages, per the mock): the jump links sit in equal
   columns split by hairline rules, each free to wrap to two lines. Phones drop
   the rules and stack them as 44px rows. The whole box is server-rendered by
   the afp/onpage block (inc/area-nav.php), so its panel and label styling
   lives here rather than in pattern markup. */
.afp-onpage-pills {
  display: grid;
  gap: var(--wp--preset--spacing--20);
  padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
  border-radius: 6px;
}

.afp-onpage-title {
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The box is a drawer like the rail ones: the label is its <summary>. Desktop
   locks it open with no marker — indistinguishable from the plain label —
   and phones collapse it into the same labeled 44px +/– bar as the rail
   drawers (drawers.js strips `open` on load below 782px). The label↔links
   gap lives here now that the drawer, not the panel grid, separates them. */
.afp-onpage-drawer>summary {
  list-style: none;
}

.afp-onpage-drawer>summary::-webkit-details-marker {
  display: none;
}

.afp-onpage-drawer>.afp-onpage-links {
  margin-top: var(--wp--preset--spacing--20);
}

@media (min-width: 782px) {
  .afp-onpage-drawer>summary {
    pointer-events: none;
  }
}

@media (max-width: 781px) {
  .afp-onpage-drawer>summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 44px;
    cursor: pointer;
  }

  .afp-onpage-drawer>summary::after {
    content: "+";
    font-size: 1.2rem;
    font-weight: 400;
  }

  .afp-onpage-drawer[open]>summary::after {
    content: "–";
  }
}

.afp-onpage-links {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
}

.afp-onpage-links a {
  padding: 0 0.75rem;
  border-left: 1px solid var(--wp--preset--color--navy-100);
  line-height: 1.35;
  text-decoration: none;
  /* Columns are narrow; wrap between words, never inside one. */
  overflow-wrap: normal;
  word-break: normal;
}

.afp-onpage-links a:first-child {
  padding-left: 0;
  border-left: 0;
}

.afp-onpage-links a:last-child {
  padding-right: 0;
}

.afp-onpage-links a:hover,
.afp-onpage-links a:focus-visible {
  text-decoration: underline;
}

/* Number of columns (GA Settings → "On this page" box). data-cols="auto" is
   the shipped single-row design — one column per link — and deliberately has
   no rules; a number splits the same links into that many columns, filled
   top to bottom (--afp-onpage-rows carries the row count that split needs,
   computed server-side). The whole first column (.afp-onpage-col-lead,
   marked server-side because the split point depends on the link count)
   drops its hairline and lead padding the way the single row's first link
   does. Desktop only — phones keep their stacked rows — and the About rail
   (excluded at zero specificity below) keeps its vertical list. */
@media (min-width: 601px) {
  .afp-onpage-links[data-cols]:where(:not(.afp-about-rail *)) {
    /* Same rhythm as the rail checklist lists (.is-style-afp-checklist). */
    row-gap: 0.55rem;
    grid-template-rows: repeat(var(--afp-onpage-rows, 1), auto);
  }

  .afp-onpage-links[data-cols="auto"]:where(:not(.afp-about-rail *)) {
    row-gap: 0;
    grid-template-rows: none;
  }

  .afp-onpage-links:where(:not(.afp-about-rail *)) a.afp-onpage-col-lead {
    padding-left: 0;
    border-left: 0;
  }
}

@media (max-width: 600px) {

  /* Stacked rows on the same 0.55rem checklist rhythm as the rail's
     "Return to the Handbook" list, so the two drawers read as one system. */
  .afp-onpage-links {
    grid-auto-flow: row;
    grid-auto-columns: auto;
    row-gap: 0.55rem;
  }

  .afp-onpage-links a {
    display: flex;
    align-items: center;
    padding: 0;
    border-left: 0;
  }
}

/* Right-rail current item (area pages) — navy bar + bold, per the mock. */
.afp-rail-current {
  border-left: 3px solid var(--wp--preset--color--navy-700);
  padding-left: 0.6rem;
  font-weight: 700;
  color: var(--wp--preset--color--navy);
}

/* The current row is a link too now — it keeps the navy/bold treatment and
   only reveals its linkness on hover/focus. */
.afp-rail-current>a {
  color: inherit;
  font-weight: inherit;
  text-decoration: none;
}

.afp-rail-current>a:hover,
.afp-rail-current>a:focus {
  text-decoration: underline;
}

/* The bar hangs into the card padding; the text stays flush with the other
   items. (li selector outranks the checklist reset.) */
.is-style-afp-checklist>li.afp-rail-current {
  margin-left: -0.6rem;
  padding-left: calc(0.6rem - 3px);
}

/* Rail drawers (client DS p8): shipped open; desktop locks them open and hides
   the toggle; phones collapse them into separate labeled 44px drawer bars in
   the rail column, which stacks below the body (client change, 2026-08-19). */
.afp-rail-drawer>summary {
  font-family: var(--wp--preset--font-family--body);
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp--preset--color--navy-700);
  list-style: none;
}

.afp-rail-drawer>summary::-webkit-details-marker {
  display: none;
}

/* Both drawer lists share one left edge (card padding), with the heading badge
   sitting in the gutter above them — per the [AP] mock rail. */
.afp-rail-drawer .is-style-afp-checklist {
  padding-left: 0;
}

/* Rail links read as a nav list, not body prose — no rule until hover. */
.afp-rail-drawer a {
  text-decoration: none;
}

/* The primary drawer heading links back to the Handbook landing (client
   request) — same look as the plain heading, underline on hover only. */
.afp-rail-drawer--primary>summary a {
  color: inherit;
}

.afp-rail-drawer a:hover,
.afp-rail-drawer a:focus-visible {
  text-decoration: underline;
}

/* Rail heading badge (the mock's folder disc) — smaller than a body chip and
   hidden on phones, where the drawer bar carries the label alone. This one sits
   inside a <summary> rich text, where an image block can't go, so it keeps the
   masked-span form; the disc styling is shared with .afp-icon-chip.
   Area pages built by scripts/page-layout.php carry .afp-icon-chip--folder for
   the same badge, so it is styled here too rather than rewriting their content. */
.afp-rail-drawer>summary .afp-rail-badge,
.afp-rail-drawer>summary .afp-icon-chip--folder {
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  /* White disc, like the primary drawer's ← badge — pale-blue on a pale-blue
     rail reads as no circle at all. */
  background-color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.afp-rail-drawer>summary .afp-rail-badge::before,
.afp-rail-drawer>summary .afp-icon-chip--folder::before {
  content: "";
  width: 1.15rem;
  height: 1.15rem;
  background-color: var(--wp--preset--color--navy);
  -webkit-mask: url(assets/icons/folder.svg) center / contain no-repeat;
  mask: url(assets/icons/folder.svg) center / contain no-repeat;
}

@media (max-width: 781px) {

  .afp-rail-drawer>summary .afp-rail-badge,
  .afp-rail-drawer>summary .afp-icon-chip--folder {
    display: none;
  }
}

/* Case list in the rail: a chevron per row, per the mock. */
.afp-rail-drawer--cases li:not(:last-child)>a::after {
  content: " \203A";
}

/* The rule between the two rail sections spans the card. */
.afp-rail-drawer+.wp-block-separator,
.wp-block-separator+.afp-rail-drawer {
  margin-block: var(--wp--preset--spacing--40);
}

@media (min-width: 782px) {
  .afp-rail-drawer>summary {
    pointer-events: none;
  }

  /* …but the heading link stays clickable inside the locked-open drawer. */
  .afp-rail-drawer--primary>summary a {
    pointer-events: auto;
  }

  /* Icon badges on the rail headings, per the mock. Desktop only — phones keep
     the plain +/– drawer bar. */
  .afp-rail-drawer--primary>summary,
  .afp-rail-drawer--cases>summary {
    display: flex;
    align-items: center;
    gap: 0.75rem;
  }

  .afp-rail-drawer--primary>summary::before {
    content: "←";
    flex: none;
    display: grid;
    place-items: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background-color: #fff;
    color: var(--wp--preset--color--navy-700);
    font-size: 1rem;
    font-weight: 400;
    letter-spacing: 0;
    line-height: 1;
  }
}

@media (max-width: 781px) {

  /* Reading order on phones: body first, rail below it (client change,
     2026-08-19 — reversed from the earlier nav-before-content stacking). */
  .afp-practice-cols {
    display: flex;
    flex-direction: column;
  }

  /* Stacking these leaves core's `flex-wrap: wrap !important` in place, and a
     wrapping column-direction flex container takes each line's width from its
     content rather than from the container — so the column sized itself to its
     widest child (680px inside a 350px page) and every Area page scrolled
     sideways on a phone. Constraining the column is the fix that doesn't need
     to out-!important core. */
  .afp-practice-cols>.wp-block-column {
    width: 100%;
    min-width: 0;
  }

  .afp-rail-drawer>summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 44px;
    cursor: pointer;
  }

  .afp-rail-drawer>summary::after {
    content: "+";
    font-size: 1.2rem;
    font-weight: 400;
  }

  .afp-rail-drawer[open]>summary::after {
    content: "–";
  }

  .afp-rail-drawer--primary>summary {
    color: var(--wp--preset--color--navy);
  }

  /* On phones the bar is a toggle; the heading link goes inert so a tap
     opens the drawer (the drawer's first row links to the Handbook anyway). */
  .afp-rail-drawer--primary>summary a {
    pointer-events: none;
  }
}

/* Phone masthead: keep one row — smaller wordmark/logo so brand + hamburger +
   search fit 390px. !important beats the block's inline size. The wordmark wraps
   to two lines here, as in the client mockup: held on one line it measured 179px,
   which ran the title under the hamburger and pushed the search pill 14px past
   the right gutter at 375px. */
@media (max-width: 600px) {
  .afp-site-header .wp-block-group.alignwide {
    flex-wrap: nowrap;
  }

  .afp-site-header .wp-block-site-title {
    font-size: 0.9375rem !important;
    letter-spacing: 0.04em !important;
    text-wrap: balance;
    /* "ASSEMBLY / FOR PEACE", not "…FOR / PEACE" */
  }

  .afp-site-logo img {
    height: 32px;
  }

  /* The UNU-CPR lockup is ~3.6:1, so height drives width: 26px ≈ 93px wide,
     the most the 375px masthead row absorbs next to the two-line wordmark. */
  .afp-site-header .afp-site-logo img {
    height: 26px;
  }
}

/* One-page cases library (design brief scroll states 2-4): anchored clusters,
   compact case headings (never a new page hero), gold kicker, prev/next row. */
.afp-cluster {
  padding-top: var(--wp--preset--spacing--40);
  border-top: 2px solid var(--wp--preset--color--navy-100);
  margin-top: var(--wp--preset--spacing--40);
}

/* On its own /cases/<theme> page the cluster is the whole column — the rule
   that separates clusters on the library page has nothing to separate from. */
.tax-case_category .afp-cluster {
  padding-top: 0;
  margin-top: 0;
  border-top: 0;
}

.afp-cluster__title {
  font-size: var(--wp--preset--font-size--x-large);
}

.afp-cluster__desc {
  color: var(--wp--preset--color--muted);
  font-size: var(--wp--preset--font-size--small);
}

.afp-case {
  padding-top: var(--wp--preset--spacing--40);
  margin-top: var(--wp--preset--spacing--40);
  border-top: 3px solid var(--wp--preset--color--gold);
}

.afp-case__title {
  font-size: var(--wp--preset--font-size--large);
  margin: 0 0 0.25rem;
}

.afp-case__kicker {
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--wp--preset--color--gold-dark);
  margin: 0 0 0.75rem;
}

/* GA Settings → CoP Kicker "Hide on mobile": the area-of-practice segment
   drops off on phones, leaving just "Cases of Practice". */
@media (max-width: 781px) {
  .afp-case__kicker-area--desktop {
    display: none;
  }
}

.afp-case-related a {
  font-weight: 600;
}

.afp-case-finder-control__label {
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp--preset--color--navy-700);
  margin: 0 0 0.5rem;
}

/* Cases list page: linked rows per theme cluster (client landing mock). */
.afp-case-list {
  list-style: none;
  padding: 0;
  margin: var(--wp--preset--spacing--20) 0 0;
}

.afp-case-list__row {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  min-height: 44px;
  padding: 0.375rem 0.75rem;
  margin-inline: -0.75rem;
  border-radius: 4px;
  border-bottom: 1px solid var(--wp--preset--color--border);
  transition: background-color 120ms ease;
}

/* Whole row clickable: the single case link stretches over the row. Safe only
   because each row has exactly one anchor (marker/date/chevron are spans). */
.afp-case-list__row>a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.afp-case-list__row:hover,
.afp-case-list__row:focus-within {
  background-color: var(--wp--preset--color--pale-blue);
}

.afp-case-list__row span {
  color: var(--wp--preset--color--blue);
}

.afp-case-list__row>span[aria-hidden] {
  transition: transform 120ms ease;
}

.afp-case-list__row:hover>span[aria-hidden] {
  transform: translateX(2px);
}

@media (prefers-reduced-motion: reduce) {

  .afp-case-list__row,
  .afp-case-list__row>span[aria-hidden] {
    transition: none;
  }

  .afp-case-list__row:hover>span[aria-hidden] {
    transform: none;
  }
}

/* Rail/panel link lists: consistent rhythm whether the list comes from the
   editor (block gap) or a server-rendered block (raw ul). */
.is-style-afp-checklist>li+li {
  margin-top: 0.55rem;
}

/* Core footnotes (wp:footnotes; markers keep original Handbook numbers).
   The Notes heading + list ship wrapped in an .afp-notes group (alignwide,
   left-justified — scripts/wrap-footnotes-group.php) so they align with the
   body-text column; being nested also keeps the h2 out of the § counter. */
.afp-notes {
  margin-top: var(--wp--preset--spacing--50);
  padding-top: var(--wp--preset--spacing--30);
  border-top: 1px solid var(--wp--preset--color--border);
}

.afp-notes h2 {
  font-size: var(--wp--preset--font-size--large);
}

.wp-block-footnotes {
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
  padding-left: 2.5rem;
}

/* Notes run the full width of their group — every page and every case that has
   them. They are citation lists, not prose, so a 70ch measure and the group's
   constrained-layout contentSize clamp both just left them short of the text and
   tables above. The `ol` beats core's layout rule
   (:root :where(.is-layout-constrained) > :where(…)) on specificity. */
.afp-notes ol.wp-block-footnotes {
  max-width: none;
}

/* On an Area of Practice page the rail ends thousands of pixels above the Notes,
   so they'd stop mid-page with the right side empty. Notes are an article footer,
   not body copy: run them under the rail. Excluded on single cases — that rail
   (sibling cases + summaries + Further Reading) usually outruns the short case
   body, and a widened Notes list would print straight over it. */
@media (min-width: 782px) {

  /* 100% is the body column, wide-size is the full columns width, so the
     negative remainder pulls the right edge out to the rail's outer edge.
     !important is unavoidable: core's constrained-layout rule sets
     `margin-right: auto !important` on every child. */
  body:not(.single-case_study) .afp-practice-cols .wp-block-group.afp-notes.alignwide {
    max-width: none;
    margin-right: calc(100% - var(--wp--style--global--wide-size)) !important;
  }
}

.wp-block-footnotes li {
  margin-top: 0.5rem;
  overflow-wrap: anywhere;
}

sup.fn a {
  text-decoration: none;
  font-weight: 600;
}

.wp-block-footnotes li>a[href$="-link"] {
  text-decoration: none;
}

/* Footnote hover popover (filled by drawers.js from the Notes list). */
.afp-fn-pop {
  position: absolute;
  z-index: 60;
  max-width: min(26rem, calc(100vw - 16px));
  padding: 0.85rem 1rem;
  background: var(--wp--preset--color--white);
  border: 1px solid var(--wp--preset--color--border);
  border-top: 3px solid var(--wp--preset--color--blue);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(11, 47, 74, 0.14);
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.55;
  color: var(--wp--preset--color--ink);
  overflow-wrap: anywhere;
}

.afp-fn-pop__num {
  display: inline-block;
  margin-right: 0.5rem;
  font-weight: 700;
  color: var(--wp--preset--color--navy);
}

.afp-fn-pop__num::after {
  content: ".";
}

/* Back-to-top (inner pages; injected by drawers.js). Sentinel spans the first
   viewport — the button appears once you scroll past it. */
.afp-top-sentinel {
  position: absolute;
  top: 0;
  width: 1px;
  height: 100vh;
  pointer-events: none;
}

/* Zero-height sticky rail placed right before the footer (drawers.js): while
   the page scrolls it pins to the viewport bottom, then rests at the footer's
   top edge so the button stops just above the footer instead of riding over it
   — as .afp-dock.is-docked does. margin-block:0 keeps it out of the root
   layout's block gap. */
.afp-top-rail {
  position: sticky;
  bottom: 0;
  height: 0;
  margin-block: 0;
  z-index: 90;
}

.afp-top-rail .afp-top {
  position: absolute;
  /* against the rail; fixed is the no-<main> fallback */
}

.afp-top {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 90;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: var(--wp--preset--color--navy);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(11, 47, 74, 0.3);
  opacity: 0;
  visibility: hidden;
  translate: 0 0.75rem;
  transition: opacity 0.2s ease, visibility 0.2s ease, translate 0.2s ease,
    background-color 0.15s ease;
}

.afp-top.is-visible {
  opacity: 1;
  visibility: visible;
  translate: 0 0;
}

.afp-top:hover {
  background: var(--wp--preset--color--link);
}

.afp-top:focus-visible {
  outline: 2px solid var(--wp--preset--color--link);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .afp-top {
    transition: none;
    translate: 0 0;
  }
}

/* Floating "On this page" pill + panel (injected by drawers.js once the
   inline TOC box scrolls out of view). Pairs with .afp-top bottom-right. */
.afp-toc-pill {
  position: fixed;
  left: 1.25rem;
  bottom: 1.25rem;
  z-index: 90;
  min-height: 44px;
  padding: 0 1.1rem;
  border: 0;
  border-radius: 22px;
  background: var(--wp--preset--color--navy);
  color: #fff;
  font-family: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(11, 47, 74, 0.3);
  opacity: 0;
  visibility: hidden;
  translate: 0 0.75rem;
  transition: opacity 0.2s ease, visibility 0.2s ease, translate 0.2s ease,
    background-color 0.15s ease;
}

.afp-toc-pill.is-visible {
  opacity: 1;
  visibility: visible;
  translate: 0 0;
}

.afp-toc-pill:hover {
  background: var(--wp--preset--color--link);
}

.afp-toc-pill:focus-visible {
  outline: 2px solid var(--wp--preset--color--link);
  outline-offset: 2px;
}

.afp-toc-panel {
  position: fixed;
  left: 1.25rem;
  bottom: calc(1.25rem + 44px + 0.5rem);
  z-index: 91;
  width: max-content;
  max-width: min(20rem, calc(100vw - 32px));
  max-height: 60vh;
  overflow-y: auto;
  padding: 0.75rem 1rem;
  border-radius: 6px;
  background: var(--wp--preset--color--pale-blue);
  box-shadow: 0 6px 24px rgba(11, 47, 74, 0.25);
}

.afp-toc-panel ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.afp-toc-panel a {
  display: block;
  padding: 0.65rem 0.5rem;
  border-left: 3px solid transparent;
  text-decoration: none;
}

.afp-toc-panel a:hover {
  text-decoration: underline;
}

.afp-toc-panel a.is-current {
  border-left-color: var(--wp--preset--color--link);
  color: var(--wp--preset--color--link);
  font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
  .afp-toc-pill {
    transition: none;
    translate: 0 0;
  }
}

/* Cases of Practice card browser (design/design-july27 "Case cards" mock).
   Structure from the mock; colour stays theme-standard — the mock's per-area
   card colours are a client red-line (colour marks structure, never topic). */
.afp-browse__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  background-color: var(--wp--preset--color--pale-blue);
  border-radius: 6px 6px 0 0;
}

.afp-browse__barlabel {
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  color: var(--wp--preset--color--navy-700);
}

.afp-browse__tabs {
  display: flex;
  flex-wrap: wrap;
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 4px;
  overflow: hidden;
  background: #fff;
}

.afp-browse__tabs button {
  min-height: 44px;
  padding: 0 1rem;
  border: 0;
  border-left: 1px solid var(--wp--preset--color--border);
  background: transparent;
  font: inherit;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--navy-700);
  cursor: pointer;
}

.afp-browse__tabs button:first-child {
  border-left: 0;
}

.afp-browse__tabs button[aria-pressed="true"] {
  background-color: var(--wp--preset--color--navy);
  color: #fff;
  font-weight: 700;
}

.afp-browse__search {
  margin-left: auto;
}

.afp-browse__search input {
  min-height: 44px;
  min-width: 16rem;
  padding: 0 2.25rem 0 0.75rem;
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 4px;
  font: inherit;
  font-size: var(--wp--preset--font-size--small);
  /* Magnifier per the mock. Decorative, so it stays a background, not an <img>.
     ponytail: inline SVG data-URI — no icon font, no sprite sheet. Stroke is the
     "muted" token (#5A6572); background-image can't read a CSS variable. */
  background: #fff url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%235A6572" stroke-width="2" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><path d="M16.5 16.5 21 21"/></svg>') no-repeat right 0.7rem center / 1.05rem;
}

/* Chrome/Safari draw their own clear "x" over the icon. */
.afp-browse__search input::-webkit-search-cancel-button {
  margin-right: 1.4rem;
}

.afp-browse__count {
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

/* Browsing by Area of Practice is one long run of cards, so the bar and the
   rail both have to travel with the reader — the tabs, the search and the
   facets stay reachable without scrolling back up. The rail parks under the
   bar. Its own scrollbar keeps a tall facet list reachable on a short
   viewport. Sticky only where the rail sits beside the grid — on phones the
   bar wraps to three rows and the rail is a drawer above the grid, so both
   would eat the viewport (see the 900px block below). */
@media (min-width: 901px) {
  .afp-browse {
    /* ponytail: measured (70px) — CSS can't ask the bar how tall it is. The
       bar is a single row at this width; revisit if it gains a control. */
    --afp-browse-bar-h: 4.375rem;
    /* WP sets this only when the admin bar is on screen; 0 for readers. */
    --afp-browse-top: var(--wp-admin--admin-bar--height, 0px);
  }

  .afp-browse__bar {
    position: sticky;
    top: var(--afp-browse-top);
    z-index: 30;
  }

  .afp-browse__filters {
    position: sticky;
    top: calc(var(--afp-browse-top) + var(--afp-browse-bar-h) + var(--wp--preset--spacing--30));
    align-self: start;
    /* The rail is content-box by default, so its padding and border would push
       the pinned box past the fold on a short viewport. */
    box-sizing: border-box;
    max-height: calc(100vh - var(--afp-browse-top) - var(--afp-browse-bar-h) - 2 * var(--wp--preset--spacing--30));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}

.afp-browse__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 17rem;
  gap: var(--wp--preset--spacing--40);
  padding: var(--wp--preset--spacing--40) 1rem;
  border: 1px solid var(--wp--preset--color--border);
  border-top: 0;
  border-radius: 0 0 6px 6px;
}

.afp-browse__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--wp--preset--spacing--30);
  align-content: start;
}

.afp-ccard {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 1rem;
  border: 1px solid var(--wp--preset--color--border);
  border-top: 3px solid var(--wp--preset--color--navy);
  border-radius: 2px;
  background: #fff;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}

/* display:flex above would beat the UA [hidden] rule — the pager needs this. */
.afp-ccard[hidden] {
  display: none;
}

.afp-ccard:hover,
.afp-ccard:focus-within {
  transform: translateY(-3px);
  box-shadow: 0 12px 26px rgba(11, 37, 69, 0.12);
}

.afp-ccard__cue {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--wp--preset--color--navy-700);
}

.afp-ccard__date {
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--gold-dark);
}

.afp-ccard__title {
  margin: 0;
  font-size: var(--wp--preset--font-size--medium);
  line-height: 1.25;
}

.afp-ccard__title a {
  text-decoration: none;
}

.afp-ccard__sum {
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--ink);
}

.afp-ccard__open {
  margin: auto 0 0;
  padding-top: 0.5rem;
  text-align: right;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
}

.afp-browse__filters {
  align-self: start;
  padding: 1rem;
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 4px;
}

.afp-browse__filters-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 44px;
  margin: 0 0 0.5rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--wp--preset--color--border);
  font-size: var(--wp--preset--font-size--medium);
  font-weight: 700;
  cursor: pointer;
}

/* display:flex on a summary suppresses the UA marker, so both the panel and the
   drawers draw their own — same +/– idiom as the rail drawers above. */
.afp-browse__filters-title,
.afp-browse__drawer>summary {
  list-style: none;
}

.afp-browse__filters-title::-webkit-details-marker,
.afp-browse__drawer>summary::-webkit-details-marker {
  display: none;
}

.afp-browse__filters-title::after,
.afp-browse__drawer>summary::after {
  content: "+";
  font-size: 1.2rem;
  font-weight: 400;
  line-height: 1;
  color: var(--wp--preset--color--muted);
}

.afp-browse__panel[open]>.afp-browse__filters-title::after,
.afp-browse__drawer[open]>summary::after {
  content: "–";
}

.afp-browse__drawer>summary:hover,
.afp-browse__filters-title:hover {
  color: var(--wp--preset--color--link);
}

.afp-browse__facet-label {
  margin: 0 0 0.5rem;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 700;
}

.afp-browse__facet {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  font-size: var(--wp--preset--font-size--small);
}

.afp-browse__facet label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0.25rem 0;
  cursor: pointer;
}

.afp-browse__facet label:hover {
  color: var(--wp--preset--color--link);
}

/* ponytail: 44px targets are the phone rule; with a mouse the list just reads
   as gappy, so tighten it there only. */
@media (pointer: fine) {
  .afp-browse__facet label {
    min-height: 32px;
  }
}

.afp-browse__n {
  margin-left: auto;
  padding-left: 0.5rem;
  color: var(--wp--preset--color--muted);
  font-variant-numeric: tabular-nums;
}

.afp-browse__drawer>summary {
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 700;
  border-top: 1px solid var(--wp--preset--color--border);
  cursor: pointer;
}

.afp-browse__clear {
  width: 100%;
  min-height: 44px;
  margin-top: 0.5rem;
  border: 1px solid var(--wp--preset--color--blue);
  border-radius: 4px;
  background: transparent;
  font: inherit;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--link);
  cursor: pointer;
}

/* An option nothing would match still reads, so the reader can see it is the
   combination that is empty rather than wonder where the option went. */
.afp-browse__facet label.is-empty {
  color: var(--wp--preset--color--muted);
  opacity: 0.65;
}

.afp-browse__empty {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--wp--preset--color--muted);
}

.afp-browse__clear--inline {
  width: auto;
  margin: 0 0 0 0.5rem;
  padding: 0 0.75rem;
  vertical-align: middle;
}

.afp-browse__pager {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.35rem;
  margin-top: var(--wp--preset--spacing--30);
}

.afp-browse__pager button {
  min-width: 44px;
  min-height: 44px;
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 4px;
  background: #fff;
  font: inherit;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--link);
  cursor: pointer;
}

.afp-browse__pager button[aria-current="true"] {
  background-color: var(--wp--preset--color--navy);
  border-color: var(--wp--preset--color--navy);
  color: #fff;
  font-weight: 700;
}

/* Previous/Next read as links, not numbered chips (design mock "Case cards"). */
.afp-browse__step {
  min-width: 0;
  padding: 0 0.75rem;
  border-color: transparent;
  background: transparent;
}

.afp-browse__step:disabled {
  color: var(--wp--preset--color--muted);
  cursor: default;
}

.afp-browse__step--prev::before {
  content: "← ";
}

.afp-browse__step--next::after {
  content: " →";
}

/* Browsing by Area of Practice — or by Type of GA action — runs every cluster
   in one scroll, so the heading is the only thing marking where a group
   starts. Later ones need a gap above. Each group is a section wrapping its
   own card grid (assets/case-grid.js), which is what lets the heading stick
   over its own cards and no further. */
.afp-browse.is-area .afp-browse__grid,
.afp-browse.is-theme .afp-browse__grid {
  display: block;
}

.afp-browse__area-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--wp--preset--spacing--30);
  align-content: start;
}

.afp-browse__group {
  /* The grid gap used to space this off the cards; now it is their sibling. */
  margin: 0 0 var(--wp--preset--spacing--30);
  font-size: var(--wp--preset--font-size--large);
  color: var(--wp--preset--color--navy);
}

.afp-browse__area+.afp-browse__area {
  margin-top: var(--wp--preset--spacing--40);
  padding-top: var(--wp--preset--spacing--30);
  border-top: 1px solid var(--wp--preset--color--border);
}

/* Deep in a 13-card area the heading is the answer to "which area am I in?", so
   it rides under the browse bar until its own cards run out. Same reason the bar
   is sticky, same breakpoint — see the bar block above. */
@media (min-width: 901px) {
  .afp-browse__group {
    position: sticky;
    top: calc(var(--afp-browse-top) + var(--afp-browse-bar-h));
    z-index: 20;
    padding: 0.5rem 0;
    background-color: var(--wp--preset--color--paper);
  }
}

/* Under that heading every card's cue would repeat it verbatim. */
.afp-browse.is-area .afp-ccard__cue {
  display: none;
}

.afp-browse__foot {
  margin-top: var(--wp--preset--spacing--30);
  text-align: center;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

/* No JS: every card shows, so the paging/filter chrome would lie. */
.afp-browse:not(.is-ready) .afp-browse__filters,
.afp-browse:not(.is-ready) .afp-browse__tabs,
.afp-browse:not(.is-ready) .afp-browse__search {
  display: none;
}

@media (max-width: 900px) {
  .afp-browse__body {
    grid-template-columns: minmax(0, 1fr);
  }

  .afp-browse__filters {
    order: -1;
  }

  .afp-browse__search {
    margin-left: 0;
    width: 100%;
  }

  .afp-browse__search input {
    width: 100%;
    min-width: 0;
  }
}

/* Long facet lists (countries, GA actions) scroll rather than push the grid. */
.afp-browse__facet--scroll {
  max-height: 18rem;
  overflow-y: auto;
}

/* Case catalogue metadata (docs/Case study metadata.xlsx): the provenance note
   and the "*" new-content mark. */
/* Provenance sits at the head of the case (client, 2026-08-04): a second muted
   metadata line under the facts, not a boxed footnote competing with the title. */
.afp-case-note {
  margin: 0.35rem 0 0;
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.6;
  color: var(--wp--preset--color--muted);
}

.afp-case-note__updated {
  font-style: italic;
}

/* Optional tint (GA Settings → Background). The border is derived from whatever
   background was picked, so the two can never drift apart. */
.afp-case-note--boxed {
  margin-top: var(--wp--preset--spacing--30);
  padding: 0.7rem 0.95rem;
  border: 1px solid color-mix(in srgb, var(--afp-note-bg) 88%, #000);
  border-radius: 4px;
  background-color: var(--afp-note-bg);
}

/* Provenance, "Above the title" position (GA Settings; client mock 2026-08-18):
   the date on the kicker's row, right-aligned to the content measure — not the
   band edge, which the emblem watermark occupies — with the publication note in
   a hover/focus card behind a circle-i. */
.afp-provenance {
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.6;
  color: var(--wp--preset--color--muted);
  text-align: right;
}

/* Area head: pinned to the head's top-right — the kicker is the first in-flow
   child at top 0, so the two share a row without magic offsets. */
.afp-area-head>.afp-provenance {
  position: absolute;
  top: 0;
  right: 0;
}

/* The injected first child would hand core's blockGap margin to the kicker;
   keep the kicker as the visual first child. */
.afp-area-head>.afp-provenance+* {
  margin-block-start: 0;
}

/* Case single: kicker left, provenance right, one row, wrapping gracefully. */
.afp-kicker-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 1rem;
}

.afp-kicker-row .afp-provenance {
  margin-left: auto;
}

@media (max-width: 781px) {

  /* Phones stack it as its own line above the kicker. */
  .afp-area-head>.afp-provenance {
    position: static;
    margin-bottom: 0.5rem;
    text-align: left;
  }
}

.afp-provenance__info {
  position: relative;
  display: inline-block;
  margin-left: 0.4rem;
}

/* Mirrors .afp-info-bar__icon (styled "i" — the icon set has no info glyph) at
   text size. Navy disc, not UN Blue: white on blue is ~2.6:1 and fails AA. */
.afp-provenance__toggle {
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--wp--preset--color--navy);
  color: var(--wp--preset--color--white);
  font-family: inherit;
  font-style: italic;
  font-weight: 700;
  font-size: 0.75rem;
  line-height: 1;
  cursor: pointer;
  vertical-align: text-bottom;
  position: relative;
}

.afp-provenance__toggle::after {
  content: "";
  /* 44px hit area around the 20px disc */
  position: absolute;
  inset: -12px;
}

.afp-provenance__toggle:focus-visible {
  outline: 2px solid var(--wp--preset--color--blue);
  outline-offset: 2px;
}

/* White card per the mock — same recipe as .afp-fn-pop. A child of the hovered
   wrapper, so the pointer can travel onto it without a hide-delay script. */
.afp-provenance__tip {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 60;
  width: max-content;
  max-width: min(22rem, calc(100vw - 16px));
  padding: 0.85rem 1rem;
  background: var(--wp--preset--color--white);
  border: 1px solid var(--wp--preset--color--border);
  border-top: 3px solid var(--wp--preset--color--blue);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(11, 47, 74, 0.14);
  font-size: var(--wp--preset--font-size--small);
  font-style: normal;
  line-height: 1.55;
  color: var(--wp--preset--color--ink);
  text-align: left;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.15s;
}

.afp-provenance__info:focus-within .afp-provenance__tip,
.afp-provenance__info.is-open .afp-provenance__tip {
  visibility: visible;
  opacity: 1;
}

/* Hover reveal only where hover is a real capability. On touch, a tap
   leaves a sticky :hover behind, so a dismissed card (second tap, Esc)
   would pop straight back in its in-place, cropped position. */
@media (hover: hover) {
  .afp-provenance__info:hover .afp-provenance__tip {
    visibility: visible;
    opacity: 1;
  }
}

/* On narrow screens the icon sits near the left page edge, so a card hung
   right-anchored off it runs off-screen — and left in place it also loses:
   the hero band isolates its stacking context and the section after the band
   paints over it. drawers.js re-homes the card to <body> while open (the
   same recipe as .afp-fn-pop), pins it just below the icon with viewport
   clamping, and this class carries the floating state. */
.afp-provenance__tip.is-floating {
  position: absolute;
  /* page coordinates set inline by drawers.js */
  top: auto;
  right: auto;
  z-index: 100001;
  /* above the dock (90) and every in-page stratum */
  width: min(22rem, calc(100vw - 16px));
  max-width: none;
  visibility: visible;
  opacity: 1;
}

/* New content marker (* / "(new)", per [WA#4, #8]) — gold, never colour-only:
   the screen-reader text and title attribute carry the same meaning. */
.afp-new {
  color: var(--wp--preset--color--gold-dark);
  font-weight: 700;
}

.afp-case-list__date {
  margin-left: auto;
  padding-left: 1rem;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
  white-space: nowrap;
}

/* ── Single case study: action bar + rail ─────────────────────────────────────
   Design: "Sample _Case of practice_model 1_non continuous" (design-aug3).
   Colour marks structure, never topic — no per-theme accents here. */
.afp-case-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin: 0 0 calc(var(--wp--preset--spacing--50) / 2);
  padding: 0.85rem 1.15rem;
  border-radius: 6px;
  background-color: var(--wp--preset--color--pale-blue);
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
}

.afp-case-actions a {
  color: var(--wp--preset--color--link);
}

.afp-case-actions__summary {
  font-weight: 400;
}

.afp-case-rail {
  padding: var(--wp--preset--spacing--40);
  border-radius: 6px;
  background-color: var(--wp--preset--color--pale-blue);
}

.afp-rail-label {
  margin: 0 0 0.75rem;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp--preset--color--navy);
}

.afp-rail-timeline {
  margin: var(--wp--preset--spacing--40) 0 0;
  font-size: var(--wp--preset--font-size--small);
}

/* Call-out buttons for in-text cross-references (client comment, legal basis):
   "Each of these would be call-out buttons linking to the cases below." */
.afp-callout-buttons {
  gap: 0.75rem;
  margin: var(--wp--preset--spacing--40) 0;
}

.afp-callout-button .wp-block-button__link {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--wp--preset--color--blue);
  background-color: transparent;
  color: var(--wp--preset--color--navy);
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
}

.afp-callout-button .wp-block-button__link:hover,
.afp-callout-button .wp-block-button__link:focus-visible {
  background-color: var(--wp--preset--color--pale-blue);
}

/* Phones: the summary sentence wraps over several lines. Drop the per-link 44px
   tap box — as an inline run inside a sentence it only inflated the leading —
   and tighten to 1.2 so the wrapped links read as one block (client request).
   Desktop keeps the compact one-line bar the mock shows. */
@media (max-width: 781px) {
  .afp-case-actions {
    gap: 0;
  }

  .afp-case-actions__summary {
    line-height: 1.5;
  }
}

/* --- /timeline ----------------------------------------------------------- */
/* The decade rail is also the mock's horizontal spine (design-aug3 p5): one
   component doing orientation, navigation and the visual language. Filtering
   and the view switch are :has() over a single DOM, so both work with JS off
   and the 41 entries are never re-rendered. */

.afp-tl-controls {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.6rem 0;
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--wp--preset--color--paper, #fafbfc);
  border-bottom: 1px solid var(--wp--preset--color--pale-blue, #eaf3f8);
}

.afp-tl-dd-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  position: relative;
}

.afp-tl-dd {
  position: relative;
}

.afp-tl-dd>summary {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  min-height: 44px;
  padding: 0.3rem 0.9rem;
  border: 1px solid var(--wp--preset--color--pale-blue, #eaf3f8);
  border-radius: 0.5rem;
  background: #fff;
  font-size: 0.9375rem;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}

.afp-tl-dd>summary::-webkit-details-marker {
  display: none;
}

.afp-tl-dd>summary::after {
  content: "";
  width: 0.45em;
  height: 0.45em;
  border-right: 2px solid var(--wp--preset--color--gold, #d4af37);
  border-bottom: 2px solid var(--wp--preset--color--gold, #d4af37);
  transform: rotate(45deg) translateY(-15%);
  transition: transform 0.15s ease;
}

.afp-tl-dd__value {
  display: none;
  max-width: 13rem;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-weight: 400;
  color: var(--wp--preset--color--muted, #5a6b7a);
}

/* Only the span matching the checked radio is shown, so the button's label
   text is correct with JS disabled — no server-frozen value, no JS sync. */
body:has(#tl-view-detail:checked) [data-for="tl-view-detail"],
body:has(#tl-view-compact:checked) [data-for="tl-view-compact"],
body:has(#tl-area-all:checked) [data-for="tl-area-all"],
body:has(#tl-area-peace-operations:checked) [data-for="tl-area-peace-operations"],
body:has(#tl-area-responses-to-use-of-force:checked) [data-for="tl-area-responses-to-use-of-force"],
body:has(#tl-area-sanctions:checked) [data-for="tl-area-sanctions"],
body:has(#tl-area-accountability:checked) [data-for="tl-area-accountability"],
body:has(#tl-area-good-offices:checked) [data-for="tl-area-good-offices"],
body:has(#tl-area-uniting-for-peace:checked) [data-for="tl-area-uniting-for-peace"],
body:has(#tl-area-humanitarian-response:checked) [data-for="tl-area-humanitarian-response"],
body:has(#tl-area-judicial-referrals:checked) [data-for="tl-area-judicial-referrals"] {
  display: inline-block;
}

.afp-tl-dd[open]>summary .afp-tl-dd__value {
  color: #cfe3f0;
}

.afp-tl-dd[open]>summary {
  background: var(--wp--preset--color--navy, #0b2f4a);
  border-color: var(--wp--preset--color--navy, #0b2f4a);
  color: #fff;
}

.afp-tl-dd[open]>summary::after {
  transform: rotate(225deg) translateY(15%);
}

/* The open panel floats below its button. */
.afp-tl-dd>.afp-tl-switch {
  position: absolute;
  top: calc(100% + 0.4rem);
  left: 0;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  min-width: 18rem;
  max-width: min(88vw, 26rem);
  margin: 0;
  padding: 0.75rem;
  background: #fff;
  border: 1px solid var(--wp--preset--color--pale-blue, #eaf3f8);
  border-radius: 0.5rem;
  box-shadow: 0 8px 24px rgba(11, 47, 74, 0.18);
}

.afp-tl-dd>summary:focus-visible {
  outline: 2px solid var(--wp--preset--color--blue, #4b93c3);
  outline-offset: 2px;
}

.afp-tl-switch {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  border: 0;
  margin: 0;
  padding: 0;
}

.afp-tl-switch input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.afp-tl-switch label {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 44px;
  /* mobile-first tap target */
  padding: 0.25rem 0.75rem;
  border: 1px solid var(--wp--preset--color--pale-blue, #eaf3f8);
  border-radius: 0.5rem;
  background: #fff;
  font-size: 0.9375rem;
  cursor: pointer;
}

/* 44px is a touch-target floor; with a mouse the pills tighten up. */
@media (pointer: fine) {
  .afp-tl-switch label {
    min-height: 2rem;
  }

  .afp-tl-dd>summary {
    min-height: 2rem;
  }
}

.afp-tl-switch input:checked+label {
  background: var(--wp--preset--color--navy, #0b2f4a);
  border-color: var(--wp--preset--color--navy, #0b2f4a);
  color: #fff;
}

/* Gold signals selection only — never a decorative background (design-aug3 p4). */
.afp-tl-switch input:checked+label .afp-browse__n {
  color: var(--wp--preset--color--gold, #d4af37);
}

.afp-tl-switch input:focus-visible+label {
  outline: 2px solid var(--wp--preset--color--blue, #4b93c3);
  outline-offset: 2px;
}

/* The spine. */
/* The controls bar (dropdowns + rail) is what's pinned now that it's a
   compact strip — see .afp-tl-controls above; .afp-tl-rail itself no longer
   needs its own background/border-bottom, .afp-tl-controls already carries them. */
.afp-tl-rail ol {
  display: flex;
  gap: 0;
  margin: 0;
  padding: 0.5rem 0 0;
  list-style: none;
  overflow-x: auto;
  scrollbar-width: none;
  position: relative;
}

.afp-tl-rail li {
  flex: 1 0 auto;
  position: relative;
  text-align: center;
}

/* One track and one fill bar, so the navy line GROWS between decades
   instead of segments crossfading in place. Geometry comes from JS via
   the custom properties; without JS the track alone shows, full width
   and navy, exactly as before. Top = ol's 0.5rem padding + the 5px that
   centres a 2px line on a 12px node. */
.afp-tl-rail ol::before,
.afp-tl-rail ol::after {
  content: "";
  position: absolute;
  top: 13px;
  height: 2px;
  border-radius: 2px;
  pointer-events: none;
  z-index: 0;
}

.afp-tl-rail ol::before {
  inset-inline: 0;
  background: var(--wp--preset--color--navy, #0b2f4a);
}

.afp-tl-rail ol::after {
  left: var(--afp-tl-start, 0px);
  width: 0;
  background: var(--wp--preset--color--navy, #0b2f4a);
}

/* Once JS has measured, the track lightens and spans node to node, and
   the fill takes over the navy. */
.afp-tl-rail.is-spy ol::before {
  inset-inline: auto;
  left: var(--afp-tl-start, 0px);
  width: var(--afp-tl-track, 0px);
  background: #d4dee6;
}

.afp-tl-rail.is-spy ol::after {
  width: var(--afp-tl-fill, 0px);
}

.afp-tl-rail a {
  position: relative;
  display: block;
  padding-top: 1.25rem;
  padding-inline: 0.6rem;
  white-space: nowrap;
  font-size: 0.8125rem;
  text-decoration: none;
  color: var(--wp--preset--color--navy, #0b2f4a);
}

.afp-tl-rail a::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 12px;
  height: 12px;
  margin-left: -6px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--wp--preset--color--blue, #4b93c3);
  box-sizing: border-box;
  z-index: 1;
}

.afp-tl-rail .is-current a {
  font-weight: 700;
}

.afp-tl-rail .is-current a::before {
  background: var(--wp--preset--color--gold, #d4af37);
  border-color: var(--wp--preset--color--navy, #0b2f4a);
  box-shadow: 0 0 0 4px rgba(212, 175, 55, 0.25);
  transform: scale(1.33);
}

@media (prefers-reduced-motion: no-preference) {

  /* The fill sweeps between decades rather than snapping. */
  .afp-tl-rail.is-spy ol::after {
    transition: width 0.12s linear;
  }

  .afp-tl-rail a::before {
    transition: transform 0.3s ease, background-color 0.3s ease,
      border-color 0.3s ease, box-shadow 0.3s ease;
  }

  /* Hover growth applies to the decades you are not already on. */
  .afp-tl-rail li:not(.is-current) a:hover::before,
  .afp-tl-rail li:not(.is-current) a:focus-visible::before {
    border-color: var(--wp--preset--color--navy, #0b2f4a);
    transform: scale(1.2);
  }
}

/* Entries — Detail view. */
.afp-tl__decade-title {
  margin-top: 2.5rem;
}

/* Entries read as points on a line: the year holds its own column so eight
   decades can be scanned by date, and one rule runs the length of the decade
   with a node per entry — the same grammar as the rail above, at body scale.
   Detail and Compact are then the same structure at two densities. */
.afp-tl__list {
  position: relative;
}

.afp-tl__list::before {
  content: "";
  position: absolute;
  top: 0.75rem;
  bottom: 0.75rem;
  left: 8rem;
  width: 2px;
  background: #d4dee6;
}

.afp-tl__entry {
  position: relative;
  display: grid;
  grid-template-columns: 7rem 1fr;
  column-gap: 3rem;
  padding: 0.6rem 0;
}

.afp-tl__entry::before {
  content: "";
  position: absolute;
  top: 1.4rem;
  left: 8rem;
  width: 0.85rem;
  height: 2px;
  margin-left: -0.3rem;
  border-radius: 1px;
  background: #d4dee6;
}

.afp-tl__year {
  grid-column: 1;
  grid-row: 1;
  margin: 0;
  text-align: right;
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--wp--preset--color--gold-dark, #8a6d1f);
}

.afp-tl__event {
  grid-column: 2;
  grid-row: 1;
  margin: 0 0 0.3rem;
  font-size: 1.125rem;
}

/* Prose stays inside a comfortable measure however wide the window gets. */
.afp-tl__response {
  grid-column: 2;
  grid-row: 2;
  max-width: 68ch;
  margin: 0;
}

/* Phones have no room for a year gutter: stack, and slim the rule down. */
@media (max-width: 700px) {
  .afp-tl__list::before {
    left: 0;
  }

  .afp-tl__entry {
    display: block;
    padding-left: 1.5rem;
  }

  .afp-tl__entry::before {
    left: 0;
    top: 1.35rem;
  }

  .afp-tl__year {
    text-align: left;
  }

  .afp-tl__event,
  .afp-tl__response {
    max-width: none;
  }
}

.afp-tl__permalink {
  margin-left: 0.4rem;
  opacity: 0;
  text-decoration: none;
  font-size: 0.8em;
}

.afp-tl__entry:hover .afp-tl__permalink,
.afp-tl__permalink:focus-visible {
  opacity: 1;
}

/* No hover to reveal it on touch, so give it a visible resting state instead
   of a permanently invisible link. */
@media (hover: none) {
  .afp-tl__permalink {
    opacity: 0.55;
  }
}

.afp-tl__entry:target {
  background: var(--wp--preset--color--pale-blue, #eaf3f8);
}

/* Anchor jumps clear the sticky rail, and the movement is animated for
   users who have not asked for reduced motion. The landed-on entry
   pulses once — un-blue tint settling into the pale-blue :target state,
   colour marking structure (your position), never topic. */
.afp-tl__decade,
.afp-tl__entry {
  scroll-margin-top: 8.5rem;
}

@media (prefers-reduced-motion: no-preference) {
  html:has(.afp-tl-rail) {
    scroll-behavior: smooth;
  }

  .afp-tl__entry:target {
    animation: afp-tl-landed 1.1s ease-out;
  }
}

@keyframes afp-tl-landed {
  0% {
    background-color: #cfe3f0;
  }

  100% {
    background-color: var(--wp--preset--color--pale-blue, #eaf3f8);
  }
}

/* Compact view: same elements, table layout. No second render. */
/* Compact is the table density — the year already has a column there, so the
   Detail rule and its nodes would only draw over the cells. */
body:has(#tl-view-compact:checked) .afp-tl__list::before,
body:has(#tl-view-compact:checked) .afp-tl__entry::before {
  display: none;
}

body:has(#tl-view-compact:checked) .afp-tl__list {
  display: table;
  width: 100%;
  border-collapse: collapse;
}

body:has(#tl-view-compact:checked) .afp-tl__entry {
  display: table-row;
  border-left: 0;
}

body:has(#tl-view-compact:checked) .afp-tl__entry>* {
  display: table-cell;
  padding: 0.6rem 0.75rem;
  border-top: 1px solid var(--wp--preset--color--pale-blue, #eaf3f8);
  vertical-align: baseline;
}

body:has(#tl-view-compact:checked) .afp-tl__year {
  width: 5.5rem;
  white-space: nowrap;
}

body:has(#tl-view-compact:checked) .afp-tl__event {
  width: 30%;
  font-size: 1rem;
  margin: 0;
}

body:has(#tl-view-compact:checked) .afp-tl__permalink {
  display: none;
}

/* Phone: Compact drops the response and becomes a dense year+event index.
   Tables become cards on phones; prose never does. */
@media (max-width: 700px) {
  body:has(#tl-view-compact:checked) .afp-tl__response {
    display: none;
  }

  body:has(#tl-view-compact:checked) .afp-tl__event {
    width: auto;
  }

  /* Narrow phones (360-390px): the two filter buttons are tight enough to
     wrap onto a second line, pushing the sticky bar well past its ~140px
     budget. Trim padding/gaps so both stay on one row. */
  .afp-tl-dd-row {
    gap: 0.35rem;
  }

  .afp-tl-dd>summary {
    gap: 0.2rem;
    padding-inline: 0.6rem;
  }

  .afp-tl-dd {
    position: static;
  }

  .afp-tl-dd>.afp-tl-switch {
    left: 0;
    right: 0;
    min-width: 0;
    max-width: none;
  }
}

/* Area filter. Each rule hides non-matching entries, then any decade left
   with nothing in it. Pure CSS, so there is no unfiltered flash and it works
   with JS disabled. */
body:has(#tl-area-peace-operations:checked) .afp-tl__entry:not([data-areas~="peace-operations"]),
body:has(#tl-area-peace-operations:checked) .afp-tl__decade:not(:has([data-areas~="peace-operations"])),
body:has(#tl-area-responses-to-use-of-force:checked) .afp-tl__entry:not([data-areas~="responses-to-use-of-force"]),
body:has(#tl-area-responses-to-use-of-force:checked) .afp-tl__decade:not(:has([data-areas~="responses-to-use-of-force"])),
body:has(#tl-area-sanctions:checked) .afp-tl__entry:not([data-areas~="sanctions"]),
body:has(#tl-area-sanctions:checked) .afp-tl__decade:not(:has([data-areas~="sanctions"])),
body:has(#tl-area-accountability:checked) .afp-tl__entry:not([data-areas~="accountability"]),
body:has(#tl-area-accountability:checked) .afp-tl__decade:not(:has([data-areas~="accountability"])),
body:has(#tl-area-good-offices:checked) .afp-tl__entry:not([data-areas~="good-offices"]),
body:has(#tl-area-good-offices:checked) .afp-tl__decade:not(:has([data-areas~="good-offices"])),
/* No entry carries this tag yet — the pill appears when the client's corrected docx links a UFP case. Keep. */
body:has(#tl-area-uniting-for-peace:checked) .afp-tl__entry:not([data-areas~="uniting-for-peace"]),
body:has(#tl-area-uniting-for-peace:checked) .afp-tl__decade:not(:has([data-areas~="uniting-for-peace"])),
body:has(#tl-area-humanitarian-response:checked) .afp-tl__entry:not([data-areas~="humanitarian-response"]),
body:has(#tl-area-humanitarian-response:checked) .afp-tl__decade:not(:has([data-areas~="humanitarian-response"])),
body:has(#tl-area-judicial-referrals:checked) .afp-tl__entry:not([data-areas~="judicial-referrals"]),
body:has(#tl-area-judicial-referrals:checked) .afp-tl__decade:not(:has([data-areas~="judicial-referrals"])) {
  display: none;
}

/* A decade with nothing left after filtering is not a place you can go. */
.afp-tl-rail li.is-empty {
  opacity: 0.35;
}

.afp-tl-rail li.is-empty a {
  pointer-events: none;
  text-decoration: none;
}

/* Rail node dims/disables in lockstep with the decade section the :has() rules
   above hide — same eight area slugs. */
body:has(#tl-area-peace-operations:checked) .afp-tl-rail li:not([data-areas~="peace-operations"]),
body:has(#tl-area-responses-to-use-of-force:checked) .afp-tl-rail li:not([data-areas~="responses-to-use-of-force"]),
body:has(#tl-area-sanctions:checked) .afp-tl-rail li:not([data-areas~="sanctions"]),
body:has(#tl-area-accountability:checked) .afp-tl-rail li:not([data-areas~="accountability"]),
body:has(#tl-area-good-offices:checked) .afp-tl-rail li:not([data-areas~="good-offices"]),
body:has(#tl-area-uniting-for-peace:checked) .afp-tl-rail li:not([data-areas~="uniting-for-peace"]),
body:has(#tl-area-humanitarian-response:checked) .afp-tl-rail li:not([data-areas~="humanitarian-response"]),
body:has(#tl-area-judicial-referrals:checked) .afp-tl-rail li:not([data-areas~="judicial-referrals"]) {
  opacity: 0.35;
}

body:has(#tl-area-peace-operations:checked) .afp-tl-rail li:not([data-areas~="peace-operations"]) a,
body:has(#tl-area-responses-to-use-of-force:checked) .afp-tl-rail li:not([data-areas~="responses-to-use-of-force"]) a,
body:has(#tl-area-sanctions:checked) .afp-tl-rail li:not([data-areas~="sanctions"]) a,
body:has(#tl-area-accountability:checked) .afp-tl-rail li:not([data-areas~="accountability"]) a,
body:has(#tl-area-good-offices:checked) .afp-tl-rail li:not([data-areas~="good-offices"]) a,
body:has(#tl-area-uniting-for-peace:checked) .afp-tl-rail li:not([data-areas~="uniting-for-peace"]) a,
body:has(#tl-area-humanitarian-response:checked) .afp-tl-rail li:not([data-areas~="humanitarian-response"]) a,
body:has(#tl-area-judicial-referrals:checked) .afp-tl-rail li:not([data-areas~="judicial-referrals"]) a {
  pointer-events: none;
  text-decoration: none;
}

/* Print: Detail, everything, no chrome. Researchers print this page. */
@media print {
  .afp-tl-controls {
    display: none;
  }

  .afp-tl__entry,
  .afp-tl__decade {
    display: block !important;
  }

  .afp-tl__list {
    display: block !important;
  }

  .afp-tl__entry>* {
    display: block !important;
  }

  /* The rule and its nodes are screen orientation; on paper the year sits
     above its entry and the measure is the page's, not 68ch. */
  .afp-tl__list::before,
  .afp-tl__entry::before {
    display: none !important;
  }

  .afp-tl__response {
    max-width: none !important;
  }

  .afp-tl__permalink {
    display: none;
  }
}

/* Floating bottom dock (Area + case pages; rendered by inc/area-nav.php).
   A fixed bar of drop-up menus — On this page / Related cases / Handbook
   sections — with prev/next on the right, alongside the back-to-top circle. */
.afp-dock {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 90;
  display: flex;
  align-items: stretch;
  gap: 0.25rem;
  padding: 0 max(var(--wp--preset--spacing--40), env(safe-area-inset-left)) 0 max(var(--wp--preset--spacing--40), env(safe-area-inset-right));
  background: var(--wp--preset--color--pale-blue);
  color: var(--wp--preset--color--navy);
  border-top: 1px solid var(--wp--preset--color--border);
  box-shadow: 0 -2px 12px rgba(11, 47, 74, 0.12);
  font-size: var(--wp--preset--font-size--small);
  transition: translate 0.2s ease, visibility 0.2s ease;
}

/* Once drawers.js moves the dock inside <main>, sticky replaces fixed: the
   bar rides the viewport bottom and rests above the footer at page end,
   never covering it. (fixed is the no-JS fallback.) */
.afp-dock.is-docked {
  position: sticky;
  bottom: 0;
  margin-top: var(--wp--preset--spacing--60);
  /* Width comes from .alignfull — no 100vw tricks (they overflow by the
     scrollbar width). */
}

/* The bar is the page's visual end — drop main's bottom padding (inline on
   the template, hence the !important) so it rests flush on the footer. */
.has-afp-dock main {
  padding-bottom: 0 !important;
}

.afp-dock a {
  text-decoration: none;
}

.afp-dock a:hover,
.afp-dock a:focus-visible {
  text-decoration: underline;
}

.afp-dock__menu {
  position: relative;
}

.afp-dock__menu>summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 48px;
  /* ≥44px tap target */
  padding: 0 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--wp--preset--color--navy);
  white-space: nowrap;
}

.afp-dock__menu>summary::-webkit-details-marker {
  display: none;
}

.afp-dock__menu>summary::after {
  content: "▴";
  font-size: 0.8em;
  translate: 0 -1px;
}

.afp-dock__menu[open]>summary {
  background: rgba(11, 47, 74, 0.08);
}

.afp-dock__menu[open]>summary::after {
  content: "▾";
}

.afp-dock__panel {
  position: absolute;
  bottom: calc(100% + 1px);
  left: 0;
  min-width: 17rem;
  max-width: min(24rem, 92vw);
  max-height: 65vh;
  overflow: auto;
  padding: 0.85rem 1.1rem;
  background: #fff;
  border: 1px solid var(--wp--preset--color--border);
  border-bottom: 0;
  border-radius: 6px 6px 0 0;
  box-shadow: 0 -8px 24px rgba(11, 47, 74, 0.14);
}

.afp-dock__panel ul {
  margin: 0;
}

.afp-dock__panel a {
  display: block;
  padding: 0.35rem 0;
  /* rows land ≥44px with the checklist line height */
}

/* The injected back-to-top circle rises above the dock instead of under it. */
.has-afp-dock .afp-top {
  bottom: calc(1.25rem + 3.25rem);
}

.has-afp-dock .afp-acronyms-tab {
  bottom: calc(1.25rem + 3.25rem);
}

/* The bottom-left corner belongs to the On-this-page pill where one exists;
   the tab stacks above it (pill is 44px tall + the same 0.75rem gap the
   dock lift uses). */
body:has(.afp-toc-pill) .afp-acronyms-tab {
  bottom: calc(1.25rem + 2.75rem + 0.75rem);
}


@media (max-width: 760px) {
  .afp-dock {
    justify-content: space-between;
  }

  /* Full labels on phones too (client change, 2026-08-19 — the "Contents"/
     "Cases" short variants are retired). Three uppercase labels at body size
     overrun a 375px bar, so they step down and may wrap to a second line
     inside the 48px bar rather than clip. */
  .afp-dock__menu {
    min-width: 0;
  }

  .afp-dock__menu>summary {
    padding: 0 0.5rem;
    letter-spacing: 0.04em;
    font-size: 0.8125rem;
    white-space: normal;
    line-height: 1.2;
  }

  .afp-dock__menu {
    position: static;
    /* panels span the bar's full width on phones */
  }

  .afp-dock__panel {
    left: 0;
    right: 0;
    max-width: none;
  }
}

/* ---------------------------------------------------------------------------
   Contact form (inc/contact-form.php)
   Mobile-first: one column, 17px fields, 44px targets. Two columns from 620px.
   -------------------------------------------------------------------------*/
.afp-contact {
  max-width: 44rem;
}

.afp-contact__form {
  display: flex;
  flex-direction: column;
  gap: var(--wp--preset--spacing--30);
  padding: var(--wp--preset--spacing--40);
  background: #fff;
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 6px;
  box-shadow: 0 1px 2px rgba(11, 47, 74, 0.04);
}

.afp-contact__cue {
  margin-bottom: 0.25rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp--preset--color--navy-500);
}

.afp-contact__row {
  display: grid;
  gap: 1rem;
}

@media (min-width: 620px) {
  .afp-contact__row {
    grid-template-columns: 1fr 1fr;
  }
}

.afp-contact__field label {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--wp--preset--color--navy-700);
}

.afp-contact__field input,
.afp-contact__field select,
.afp-contact__field textarea {
  box-sizing: border-box;
  /* inputs aren't blocks — core's reset doesn't reach them */
  display: block;
  width: 100%;
  padding: 0.7rem 0.85rem;
  font: inherit;
  line-height: 1.5;
  color: var(--wp--preset--color--ink);
  background: var(--wp--preset--color--paper);
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 6px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}

.afp-contact__field input,
.afp-contact__field select {
  height: 48px;
}

/* ponytail: the select keeps its native chevron and native mobile picker — no
   appearance:none plus a hand-drawn arrow to maintain. */
.afp-contact__optional {
  font-weight: 400;
  color: var(--wp--preset--color--muted);
}

/* .afp-contact__form is a flex column, not a grid, so justify-self does
   nothing on its children — the cue and the legend are wrapped in their own
   flex row instead so the legend can sit at the row's end. */
.afp-contact__heading {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.25rem 1rem;
}

/* Required marker. Gold would read as Further Reading; this is a form state, so
   it uses the error colour the form already uses for its failure notice. */
.afp-contact__req {
  margin-left: 0.15rem;
  color: #B3261E;
  font-weight: 700;
}

.afp-contact__legend {
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

.afp-contact__field textarea {
  min-height: 160px;
  resize: vertical;
}

.afp-contact__field input::placeholder,
.afp-contact__field textarea::placeholder {
  color: var(--wp--preset--color--muted);
}

.afp-contact__field input:hover,
.afp-contact__field select:hover,
.afp-contact__field textarea:hover {
  border-color: var(--wp--preset--color--navy-300);
}

.afp-contact__field input:focus,
.afp-contact__field select:focus,
.afp-contact__field textarea:focus {
  outline: none;
  background: #fff;
  border-color: var(--wp--preset--color--navy-500);
  box-shadow: 0 0 0 3px var(--wp--preset--color--navy-100);
}

.afp-contact__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--wp--preset--spacing--30);
  margin-top: 0.25rem;
}

.afp-contact__submit {
  min-height: 48px;
  padding: 0 1.75rem;
  font: inherit;
  font-weight: 700;
  color: #fff;
  background: var(--wp--preset--color--navy);
  border: 0;
  border-radius: 6px;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.afp-contact__submit:hover {
  background: var(--wp--preset--color--navy-700);
}

.afp-contact__submit:focus-visible {
  outline: 2px solid var(--wp--preset--color--navy);
  outline-offset: 2px;
}

.afp-contact__hint {
  font-size: 0.875rem;
  color: var(--wp--preset--color--muted);
}

.afp-contact__notice {
  margin: 0 0 var(--wp--preset--spacing--30);
  padding: 0.85rem 1rem;
  font-size: 0.9375rem;
  border-radius: 6px;
  background: var(--wp--preset--color--pale-blue);
  border-left: 3px solid var(--wp--preset--color--navy-500);
}

.afp-contact__notice.is-error {
  background: #FBF1F1;
  border-left-color: #9B2226;
  color: #7A1B1E;
}

@media (max-width: 619px) {
  .afp-contact__form {
    padding: var(--wp--preset--spacing--30);
  }

  .afp-contact__submit,
  .afp-contact__hint {
    width: 100%;
    text-align: center;
  }
}

/* Footer colophon: segments spaced apart instead of separated by middots,
   which read as dated at 13px. Flex gap survives wrapping on phones. */
.afp-colophon {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.75rem;
  margin: 0;
}

/* Areas of Practice cards — the client's per-area line logos (assets/icons/areas/).
   The glyph sits in a pale-blue rounded square big enough to read at a glance on a
   phone; the card itself is the standard afp-card (gold rule + hover lift). */
.afp-area-card__icon,
.afp-tile__icon {
  width: 68px;
  height: 68px;
  margin: 0 auto;
  border-radius: 18px;
  background-color: var(--wp--preset--color--pale-blue);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color 0.18s ease;
}

.afp-area-card__icon img,
.afp-tile__icon img {
  display: block;
  width: 34px;
  height: 34px;
}

.afp-area-card:hover .afp-area-card__icon,
.afp-area-card:focus-within .afp-area-card__icon,
.afp-tile:hover .afp-tile__icon,
.afp-tile:focus-within .afp-tile__icon {
  background-color: var(--wp--preset--color--navy-100);
}

/* The theme carries no .screen-reader-text rule and core only ships one to classic
   themes, so define it here — the chip and external links depend on it to give
   screen readers the context sighted readers get from position. */
.screen-reader-text {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The "leaves this site" arrow rides as a superscript — present enough to read as
   a signal, quiet enough not to compete with the link text, the way most modern
   sites treat it. The arrow spans are already aria-hidden (the announcement comes
   from the .screen-reader-text beside them), so this is purely visual.
   ponytail: one attribute selector rather than a class threaded through five
   patterns and two saved pages — no other aria-hidden span in the theme sits
   inside an anchor. Add a class if that ever stops being true. */
a>span[aria-hidden="true"] {
  font-size: 0.72em;
  vertical-align: 0.32em;
  margin-left: 0.15em;
  opacity: 0.6;
  line-height: 1;
}

/* Publications shelf — cover cards on a grid that fits 5-up → 3 → 2. Layout and
   state only; every colour comes from a preset class in patterns/shelf-publications.php. */
/* The shelf grid and the card chrome live here rather than in theme.json's
   is-style-afp-pub variation, because the shelf is a dynamic block. WordPress
   only emits a variation's CSS when it finds the class in parsed post content,
   and a render_callback's output is never parsed — so the variation styled the
   old hardcoded pattern and silently stopped applying the moment the shelf
   became a block. The is-style-* classes stay on the markup so the editor's
   Styles panel still names them; the front end must not depend on them.
   auto-fit at 12rem reproduces the minimumColumnWidth the old group carried,
   but auto-fill keeps the empty tracks it can fit — five cards in a row wide
   enough for six 12rem tracks left a card-width of dead space on the right.
   auto-fit collapses the empties so the remaining cards stretch to fill.
   Capped at five columns above 64rem, matching the client's mockup — more
   than five publications wrap onto a second row of five rather than
   shrinking. 64rem is arithmetic, not convention: five 12rem cards plus
   four 1rem gaps need 1024px, and repeat(5, 1fr) has no minimum of its own —
   it discards the 12rem floor that minmax(12rem, 1fr) exists to enforce.
   Below 1024px that would squeeze each column to ~70% of the intended
   minimum, so the auto-fit fallback (3-and-2) stays in charge until there is
   room for five full-width cards. The theme's 782px wide breakpoint is right
   for components without a hard minimum track width; this grid has one, so
   it deliberately does not reuse that breakpoint. */
.afp-shelf {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: 1rem;
}

@media (min-width: 64rem) {
  .afp-shelf {
    grid-template-columns: repeat(5, 1fr);
  }
}

.afp-pub {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  background-color: var(--wp--preset--color--white);
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 8px;
  padding: var(--wp--preset--spacing--20);
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}

/* Whole-card click. The title link's hit area is stretched over the card, so
   it stays the one real link (keyboard focus, screen-reader name unchanged)
   while a click anywhere on the tile follows it. The PDF chip is lifted back
   above the overlay so it remains separately clickable. No title link (the
   unlinked sidebar card, or a record with nowhere to point) means no overlay. */
.afp-pub__title a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.afp-pub__meta a {
  position: relative;
  z-index: 1;
}

.afp-pub:hover,
.afp-pub:focus-within {
  border-color: var(--wp--preset--color--blue);
  box-shadow: 0 2px 10px rgba(11, 37, 69, 0.12);
}

.afp-pub__cover {
  margin: 0 0 12px;
}

.afp-pub__cover img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 5px;
}

/* Generated cover — used when a publication has no featured image. The gradient
   comes from a theme.json preset class, so no colour is hardcoded here; this
   rule only does layout. Same 3:4 box as an uploaded cover so a mixed shelf
   still lines up. */
.afp-pub__cover--generated {
  display: flex;
  flex-direction: column;
  gap: 10px;
  aspect-ratio: 3 / 4;
  padding: 14px;
  border-radius: 5px;
  color: var(--wp--preset--color--white);
}

.afp-pub__cover-icon svg {
  width: 26px;
  height: 26px;
}

.afp-pub__cover-title {
  font-size: 0.8125rem;
  font-weight: 800;
  line-height: 1.35;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}

/* The card title. The old static markup carried these three as inline block
   attributes; a render_callback emits a bare <h3>, so without this the theme's
   default h3 size applies and a title dwarfs the card it sits in. Same class of
   loss as the grid and the card chrome above — every visual property that lived
   in a block attribute had to be restated here. */
.afp-pub__title {
  margin: 0 0 8px;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  line-height: 1.4;
}

.afp-pub h3 a {
  text-decoration: none;
}

.afp-pub h3 a:hover,
.afp-pub h3 a:focus-visible {
  text-decoration: underline;
}

/* Pinned to the card bottom so meta rows line up across uneven titles.
   Date and chip share a row, per the client's reference rendering: the date
   wraps to two lines beside the chip rather than pushing it down. */
.afp-pub__meta {
  display: flex;
  margin-top: auto;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: center;
  column-gap: 0.5rem;
  width: 100%;
  font-size: 12.5px;
  margin-left: 0 !important;
  margin-right: 0 !important;
}

.afp-pub__date {
  flex: 0 1 auto;
  margin: 0;
}

.afp-pub__meta>p:last-child {
  flex: 0 0 auto;
  margin: 0 0 0 auto;
}

/* Compact by default, per the client's reference rendering. The 44px tap target
   is a project red-line for touch, not for a mouse — WCAG AA asks 24px, and
   44px is the AAA figure. pointer:coarse is the input, not the screen width, so
   a small laptop stays compact and a large tablet does not. */
.afp-pdf-chip {
  display: inline-flex;
  align-items: center;
  min-height: 0;
  padding: 3px 9px;
  border-radius: 4px;
  background-color: var(--wp--preset--color--navy);
  color: var(--wp--preset--color--white);
  font-size: 0.71875rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-decoration: none;
}

@media (pointer: coarse) {
  .afp-pdf-chip {
    min-height: 44px;
    padding: 0 0.7rem;
  }
}

.afp-pdf-chip:hover,
.afp-pdf-chip:focus-visible {
  background-color: var(--wp--preset--color--link);
  color: var(--wp--preset--color--white);
}

/* Forthcoming: this 2px dashed border is hand-written CSS, not theme.json's
   afp-pub-forthcoming style variation. That variation is dead for this shelf —
   WordPress only emits block-style-variation CSS for markup it finds in parsed
   post content, and afp_publication_card() is a render_callback's output,
   which is never parsed. The className swap the border relies on lives in
   afp_publication_card() (inc/publication-shelf.php), not in the pattern file.
   See the README's "Server-rendered blocks and lost styling" section — this
   exact belief caused three regressions on this branch before it was fixed
   here. */
.afp-pub--soon {
  position: relative;
  border: 2px dashed var(--wp--preset--color--navy-300);
}

.afp-pub--soon::before {
  content: "FORTHCOMING";
  position: absolute;
  top: 1.25rem;
  left: 1.25rem;
  z-index: 1;
  padding: 3px 8px;
  border-radius: 4px;
  background-color: var(--wp--preset--color--gold);
  color: var(--wp--preset--color--navy);
  font-size: 0.6875rem;
  font-weight: 800;
  letter-spacing: 0.06em;
}

/* A forthcoming publication has no document, so its tile stops imitating a
   cover: a pale panel with the glyph and title centred, rather than a gradient
   dimmed to 45%. An uploaded image, if one exists, still washes out — there the
   greying reads as "not yet", because there is a real cover underneath it. */
.afp-pub--soon .afp-pub__cover img {
  filter: grayscale(1);
  opacity: 0.45;
}

.afp-pub--soon .afp-pub__cover--generated {
  align-items: center;
  justify-content: center;
  padding: 14px;
  border: 1px solid var(--wp--preset--color--border);
  background-color: var(--wp--preset--color--paper-200);
  color: var(--wp--preset--color--ink);
  text-align: center;
}

.afp-pub--soon .afp-pub__cover-icon svg {
  width: 38px;
  height: 38px;
}

.afp-pub--soon .afp-pub__cover-title {
  text-transform: none;
  font-weight: 600;
}

/* "View all publications" — the mockup's outlined CTA. Colour comes from the
   core outline button style; only the geometry is ours. */
.afp-btn-cta .wp-block-button__link {
  border-width: 1.5px;
  border-radius: 6px;
  padding: 10px 18px;
  font-weight: 600;
}

/* Commentary panel — a white card inside the pale band: feature on the left, a
   divided list of shorter entries on the right. Stacks below the columns
   breakpoint, where the side list becomes a continuation of the feature. */
.afp-comm__grid {
  overflow: hidden;
}

/* Four nested paddings — panel, columns, media-text, content — compound to leave
   the feature headline a ~90px column on a phone, which breaks words mid-syllable.
   Shrink the whitespace, never the type (design spec p14).
   The panel and media-text paddings are inline block-support styles, so they need
   !important; core's columns padding sits in a :where() at zero specificity, so a
   plain class beats it. */
@media (max-width: 781px) {
  .afp-comm {
    padding-left: var(--wp--preset--spacing--30) !important;
    padding-right: var(--wp--preset--spacing--30) !important;
  }

  .afp-comm__grid {
    padding-left: 1rem;
    padding-right: 1rem;
  }

  .afp-comm .wp-block-media-text {
    padding-left: var(--wp--preset--spacing--20) !important;
    padding-right: var(--wp--preset--spacing--20) !important;
  }
}

.afp-comm__side {
  border-left: 1px solid var(--wp--preset--color--border);
}

@media (max-width: 781px) {
  .afp-comm__side {
    border-left: 0;
    border-top: 1px solid var(--wp--preset--color--border);
  }
}

.afp-comm__item+.afp-comm__item {
  border-top: 1px solid var(--wp--preset--color--border);
}

.afp-comm a {
  text-decoration: none;
}

.afp-comm a:hover,
.afp-comm a:focus-visible {
  text-decoration: underline;
}

/* Core centres the media in a grid row as tall as the text column; top-align it so
   the image sits with the headline as the mockup shows. */
.afp-comm .wp-block-media-text__media {
  align-self: start;
}

.afp-comm .wp-block-media-text__media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 6px;
}

/* Reference-section tiles — the area-card chip at a smaller, left-aligned size,
   on a pale ground so the row reads as navigation rather than content. */
/* !important: theme.json's `.wp-block-group.is-style-afp-card` background-color
   rule is (0,2,0), which outranks this plain (0,1,0) class on its own. */
.afp-tile {
  background-color: var(--wp--preset--color--pale-blue) !important;
}

.afp-tile__icon {
  width: 48px;
  height: 48px;
  margin: 0;
  border-radius: 10px;
  background-color: var(--wp--preset--color--white);
  border: 1px solid var(--wp--preset--color--border);
}

.afp-tile__icon img {
  width: 24px;
  height: 24px;
}

.afp-tile h3 a {
  color: var(--wp--preset--color--link);
}

.afp-new-marker {
  color: var(--wp--preset--color--gold-dark);
}

/* WordPress core stamps `has-border-color` on any block that sets a preset border
   colour, and the palette slug `border` makes WP generate a same-named text-colour
   utility — so a bordered block silently repaints inherited text to the hairline
   grey. Nobody wants #DCE3EA as body text; the border itself comes from the block's
   inline style, so neutralising the text half is lossless — but only when the block
   has no text colour of its own. `has-text-color` is always co-emitted whenever an
   editor sets a text colour, preset or custom, so :not(.has-text-color) excludes
   exactly the blocks where this rule would otherwise erase a real choice with
   nothing in the UI to explain it. The `:root` prefix raises specificity to (1,1,0)
   so this wins over a same-specificity (0,1,0) !important rule regardless of
   source order — it no longer depends on style.css happening to be enqueued after
   core's global styles.
   ponytail: one rule instead of renaming the token across 13 patterns and ~40 CSS
   references. Upgrade path: rename the palette slug to `hairline` in theme.json if
   a genuine text use for this colour ever appears. */
:root .has-border-color:not(.has-text-color) {
  color: inherit !important;
}

/* auto-fill drops to 1-up below ~480px because two 12rem tracks plus the gap
   exceed the phone content box. The design calls for 2-up on phone — shrink the
   tracks rather than the type, per the mobile-first red-line. */
@media (max-width: 600px) {

  .afp-shelf,
  .afp-tiles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* External-resource rows — a two-column directory list. Hairlines come from the
   rows themselves so the grid needs no borders of its own; layout and state only,
   every colour is a preset class in patterns/rows-external.php. */
.afp-xrows {
  border-top: 1px solid var(--wp--preset--color--border);
}

.afp-xrow {
  padding: 0.8rem 0.25rem;
  min-height: 44px;
  border-bottom: 1px solid var(--wp--preset--color--border);
  flex-wrap: nowrap !important;
}

.afp-xrow__icon {
  width: 38px;
  height: 38px;
  flex: none;
  margin: 0;
  border-radius: 8px;
  background-color: var(--wp--preset--color--pale-blue);
  display: flex;
  align-items: center;
  justify-content: center;
}

.afp-xrow__icon img {
  display: block;
  width: 20px;
  height: 20px;
}

.afp-xrow__body {
  min-width: 0;
}

.afp-xrow a {
  color: var(--wp--preset--color--link);
  text-decoration: none;
}

.afp-xrow a:hover,
.afp-xrow a:focus-visible {
  text-decoration: underline;
}

/* Directory cards — the standard card with a tighter grid and no gold top rule,
   so a page of forty links does not read as forty separate sections. */
.afp-xcard h3 a {
  color: var(--wp--preset--color--link);
  text-decoration: none;
}

.afp-xcard h3 a:hover,
.afp-xcard h3 a:focus-visible {
  text-decoration: underline;
}

/* Sidebar link panel. Items are separated by hairlines rather than bullets, and
   each clears the 44px tap target. :not(:first-of-type) — not :first-child,
   since the panel's own heading precedes the items as a sibling — so the
   first item (right under that heading) doesn't draw a redundant line there
   too. */
.afp-xpanel {
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 6px;
}

.afp-xpanel__item {
  display: flex;
  align-items: center;
  min-height: 44px;
  margin: 0;
}

.afp-xpanel__item:not(:first-of-type) {
  border-top: 1px solid var(--wp--preset--color--border);
}

.afp-xpanel__item a {
  color: var(--wp--preset--color--link);
  text-decoration: none;
}

.afp-xpanel__item a:hover,
.afp-xpanel__item a:focus-visible {
  text-decoration: underline;
}

/* Directory layout — main column plus a sidebar of link panels. Core stacks the
   columns at 781px; the sidebar panels then read as a continuation of the page.
   Shrink the whitespace on phone, never the type (design spec p14). */
.afp-xside {
  display: flex;
  flex-direction: column;
  gap: var(--wp--preset--spacing--30);
}

@media (max-width: 781px) {
  .afp-xpanel {
    padding-left: var(--wp--preset--spacing--30) !important;
    padding-right: var(--wp--preset--spacing--30) !important;
  }
}

/* Resource Centre landing (client mock, 2026-08-06) — four full-width link
   rows, each the standard afp-card treatment (including the site-wide gold
   top rule) with a content block on the left and a right-aligned CTA. */
.afp-resource-row__body {
  flex: 1 1 auto;
  min-width: 0;
}

/* The body grows to fill the row (flex:1 above), but its own heading and
   description are children of a layout:"constrained" group, so core's
   `.is-layout-constrained > :where(:not(.alignleft):not(.alignright)
   :not(.alignfull))` rule shrink-wraps and centres them with
   `margin-left/right: auto !important`. That drifts each card's title left
   edge by however long its description is. Override so they fill the body
   and start flush at the card's padding edge instead. */
.afp-resource-row__body>* {
  margin-inline: 0 !important;
}

.afp-resource-row__cta {
  flex: none;
  margin: 0;
}

.afp-resource-row__cta a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--wp--preset--color--link);
  text-decoration: none;
}

.afp-resource-row__cta a:hover,
.afp-resource-row__cta a:focus-visible {
  text-decoration: underline;
}

/* Phone: CTA drops below the description and the row stacks (client mock is
   desktop-only; this follows the site's mobile-first stacking rule). */
@media (max-width: 781px) {
  .afp-resource-row {
    flex-direction: column;
    align-items: flex-start;
  }

  .afp-resource-row__cta {
    margin-top: var(--wp--preset--spacing--20);
  }
}

/* Resource Centre intro paragraph (client mock, 2026-08-06): the paragraph is
   a direct, non-aligned child of an alignwide group whose layout sets
   wideSize:77rem with no contentSize, so core's constrained-layout rule caps
   it at the wide measure instead of the theme's 46rem content measure.
   Constrain it directly, and override core's `margin-left/right: auto
   !important` (same mechanism as .afp-hero-title / .afp-area-head above) so
   it stays flush left under the <h1> instead of centring. */
.afp-resource-intro {
  max-width: 46rem;
  margin-inline: 0 !important;
}

/* Resource Centre info callout — reuses the theme's afp-callout block style
   (pale panel, theme.json) rather than a new idiom. The circular "i" mark is
   a styled character, not a new SVG asset — the icon set has no info glyph
   and adding one just for this bar would be more new surface than a disc of
   text needs. */
.afp-info-bar__icon {
  flex: none;
  width: 28px;
  height: 28px;
  margin: 0;
  border-radius: 50%;
  background-color: var(--wp--preset--color--blue);
  color: var(--wp--preset--color--white);
  display: flex;
  align-items: center;
  justify-content: center;
  font-style: italic;
  font-weight: 700;
  font-size: var(--wp--preset--font-size--medium);
  line-height: 1;
}

/* Reference Tables page (design/reference-tables.png, 2026-08-06): each row's
   aside stacks an Area of Practice label above the "Go to table" link. The
   row shell reuses .is-style-afp-card .afp-resource-row as-is (including its
   own mobile column-stack rule above); only the badge and its column are new.
   The client mock colours each label per area — dropped per the
   no-per-area-colour rule (CLIENT-REQUIREMENTS.md §J); every label uses one
   neutral treatment instead. */
.afp-reftable-aside {
  flex: none;
  align-items: flex-end;
}

.afp-reftable-badge {
  margin: 0;
  padding: 0.3em 0.85em;
  border-radius: 999px;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  line-height: 1.4;
}

@media (max-width: 781px) {
  .afp-reftable-aside {
    align-items: flex-start;
    margin-top: var(--wp--preset--spacing--20);
  }
}

/* Publication meta box — swatch grid and media field. Editor-side chrome, so it
   sits with the rest of the admin-facing rules rather than the front-end ones. */
.afp-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.afp-swatch {
  display: block;
  width: 34px;
  height: 34px;
  border: 2px solid transparent;
  border-radius: 4px;
  cursor: pointer;
}

.afp-swatch:focus-within,
.afp-swatch:has(input:checked) {
  border-color: var(--wp--preset--color--gold);
}

.afp-swatch input {
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}

/* Cover icon grid — grouped radio tiles, the same clickable-tile idea as
   .afp-swatch above but each tile carries a rendered glyph and its slug.
   39 icons is too many for an unscrolled sidebar column, so the whole grid
   scrolls inside a fixed-height frame instead of pushing the rest of the box
   down the page. */
.afp-icons {
  display: block;
  max-height: 16rem;
  overflow-y: auto;
  padding: 6px;
  border: 1px solid var(--wp--preset--color--border);
  border-radius: 4px;
}

.afp-icons__group-label {
  display: block;
  margin: 10px 0 4px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--wp--preset--color--muted);
}

.afp-icons__group-label:first-child {
  margin-top: 0;
}

.afp-icons__row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
  gap: 4px;
}

.afp-icon-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 6px 2px;
  border: 2px solid transparent;
  border-radius: 4px;
  cursor: pointer;
  text-align: center;
}

.afp-icon-tile:hover {
  background: var(--wp--preset--color--pale-blue);
}

.afp-icon-tile:focus-within,
.afp-icon-tile:has(input:checked) {
  border-color: var(--wp--preset--color--gold);
}

.afp-icon-tile input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}

.afp-icon-tile__glyph {
  font-size: 1.25rem;
  line-height: 1;
  color: var(--wp--preset--color--navy);
}

.afp-icon-tile__name {
  font-size: 10px;
  line-height: 1.3;
  color: var(--wp--preset--color--muted);
  overflow-wrap: anywhere;
}

.afp-media-name {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  color: var(--wp--preset--color--muted);
  overflow-wrap: anywhere;
}

/* Publication single — the download card sits in a sticky aside beside the
   written page. Mobile-first: the columns stack below the block editor's own
   breakpoint, and the card then reads as a header for the document rather than
   a rail, so the sticky positioning is desktop-only. */
.afp-pub-aside {
  max-width: 22rem;
}

@media (min-width: 782px) {
  .afp-pub-aside {
    position: sticky;
    top: var(--wp--preset--spacing--40);
  }
}

/* Publications index (inc/publication-index.php) — Task 10c switched this
   from a bespoke full-width row to the shelf's own card,
   afp_publication_card(), dropped straight into the browse rail's grid: the
   rail's .afp-browse__grid (repeat(auto-fill, minmax(13rem, 1fr)), above) is
   already the shelf's column shape, so no new grid CSS was needed. The card
   itself is untouched; each grid cell is a thin wrapper,
   .afp-pub-index-item (afp_publication_index_card()), that exists only to
   carry the data-cat/data-tag/data-year/data-lang/data-search attributes
   assets/publication-index.js filters and hides on. --nofilters drops the
   17rem rail column for the case (not currently live, but possible as
   terms/languages change) where every facet has fewer than two distinct
   values. */
.afp-browse--nofilters .afp-browse__body {
  grid-template-columns: 1fr;
}

/* Option — Wide lead column: first column takes 30% of the table. */
main .wp-block-post-content .wp-block-table.afp-table-lead-col th:first-child,
main .wp-block-post-content .wp-block-table.afp-table-lead-col td:first-child {
  width: 30%;
}

/* Option — Narrow 3rd column: for a short-value column (e.g. "Veto by")
   sitting between longer prose/link columns that would otherwise be
   squeezed evenly with it. Overrides the column-floor `min-width: 9rem`
   above (td:not([colspan])) — without that, the floor pins this column to
   9rem no matter what width we hint here. */
main .wp-block-post-content .wp-block-table.afp-table-narrow-col-3 th:nth-child(3),
main .wp-block-post-content .wp-block-table.afp-table-narrow-col-3 td:nth-child(3) {
  width: 10%;
  min-width: 4rem;
}