/**
 * Durham Pre-K Site Locator — public styles.
 *
 * Design tokens first (ARCHITECTURE.md §9). Every themeable value routes through
 * an organized `--dpk-*` custom-property layer defined on `.dpk-locator`, grouped
 * below into Colors, Typography, Spacing, Layout, and Utility. Rules consume the
 * tokens; they never hardcode a brand value.
 *
 * The brand palette defaults to the design's explicit hex values here and is
 * dashboard-overridable (each color emitted as an inline `--dpk-color-*` override,
 * same mechanism as the accent). Fonts stay inherit-first: no family is hardcoded —
 * `--dpk-font-family` is an unset seam (empty = inherit the theme), filled only by
 * the dashboard font override. Ships no framework.
 *
 * Font sizes are rem-mapped from the design's px specs so browser zoom and user
 * font-size preferences are honored (WCAG 1.4.4).
 *
 * LAYOUT (Step 4): the desktop two-panel grid (fixed sidebar + map) is a
 * progressive enhancement — it applies ONLY under `.dpk-locator.is-enhanced.has-map`,
 * a class the JS adds. With no JS the widget is a single accessible column and the
 * map stays hidden; the server-rendered list is the source of truth.
 */

/* ====================================================================== TOKENS */

.dpk-locator {
	/* ------------------------------------------------------------- Colors */
	/* Functional palette (design defaults; dashboard-overridable). */
	--dpk-color-primary: #1779a6;        /* Search panel bg, headings, active state */
	--dpk-color-accent: #cb3a00;         /* Buttons, default links, default pins, map UI */
	--dpk-color-divider: #a3c0cc;        /* Divider rules/pipes, site-block icons */
	--dpk-color-filter-label: #ffffff;   /* Filter field labels on the panel (white for AA on primary; the design's #d9f4ff was 4.24:1, below AA — see DECISIONS D25) */
	--dpk-color-selected-bg: #f6fafc;    /* Selected/active site-card background */
	--dpk-color-scroll-track: #e4eef2;   /* Results scrollbar trough (light tint of the divider) */
	--dpk-color-card-shadow: #c6d9e1;    /* List-view card shadow (designer, 2026-07-27) — a step deeper than the scroll track, since the shadow is spread evenly on all four sides rather than pooled on two */
	--dpk-color-text: #000;              /* Text on light backgrounds (fixed) */
	--dpk-color-on-color: #fff;          /* Text on colored/dark backgrounds (fixed) */

	/* --------------------------------------------------------- Typography */
	/* Inherit-first: no family hardcoded. Unset = inherit theme; the dashboard
	   font override fills this in (e.g. "Avenir Next W01" on the prod install). */
	/* Four steps, keyed to the faces the brand kit actually ships — Avenir Next LT
	   Pro on Adobe Fonts serves Regular, MEDIUM, Demi (delivered AT 700) and Heavy.
	   There is still no 600: it collapses silently onto Demi, so it must never be
	   used here. Re-measure if the kit is republished — `getComputedStyle` echoes
	   the weight you ASKED for and cannot tell you which face rendered; compare the
	   same string's `getBoundingClientRect().width` at each weight instead. (500 was
	   itself added on 2026-07-30 after that measurement showed a distinct face where
	   the old note said none existed.) */
	--dpk-fw-default: 400;               /* Regular — default text weight */
	--dpk-fw-medium: 500;                /* Medium — the site cards' info rows */
	--dpk-fw-demi: 700;                  /* Demi — scan-anchors inside body text (care labels) */
	--dpk-fw-bold: 800;                  /* Heavy — anything bolder on the design */
	--dpk-fs-h1: 1.375rem;               /* 22px — "Find PreK", "Search Results" */
	--dpk-fs-h2: 1.25rem;                /* 20px — "Filter", care-site names */
	--dpk-fs-h3: 1.0625rem;              /* 17px — filter option labels */
	--dpk-fs-placeholder: 1rem;          /* 16px — search + distance dropdown */
	--dpk-fs-checkbox: 0.9rem;           /* 14.4px — checkbox option text (also the mobile List/Map buttons) */
	--dpk-fs-results-info: 1rem;         /* 16px — "N sites within…", list link */
	--dpk-fs-site-info: 0.875rem;        /* 14px — address, phone, etc. */
	--dpk-fs-small: 0.75rem;             /* 12px — website/directions, reset */

	/* ------------------------------------------------------------ Spacing */
	--dpk-pad-panel: 20px;               /* Search-area interior padding (mobile: 30) */
	--dpk-pad-results: 20px;             /* Results-list interior padding (mobile: 30) */
	--dpk-gap-results-details: 10px;     /* "N sites within…" → first listing */
	--dpk-pad-card: 20px;                /* Care-site block interior padding */
	--dpk-gap-after-name: 6px;           /* After care-site name, before divider */
	--dpk-gap-after-divider: 15px;       /* After divider, before details */
	--dpk-gap-info-list: 0.4rem;         /* Between info rows (address/phone/care/seats) — 6.4px, designer call 2026-07-27. Deliberately `rem`, NOT `em`: it is a fixed step the designer picked, not a fraction of the row's line-height, so it must not shift with the font-size of whatever element the `gap` is declared on */
	--dpk-gap-before-actions: 13px;      /* Info block → the action links beneath it */
	--dpk-gap-before-links: 5px;         /* Action links → the associated-links row (Virtual Tour). Smaller than it looks: both rows are 12px UPPERCASE, whose caps leave ~4px of empty line box above and below, so 5px of margin renders ~12.8px of VISIBLE space. That was tuned to match the address→phone gap back when --dpk-gap-info-list was 8.75px; at 0.4rem those rows read ~10.3px apart, so lower this to ~2.5px if the two are meant to keep matching */
	--dpk-gap: 1rem;                     /* Generic layout gap */
	--dpk-hover-ease: 200ms;             /* Card info links easing into their hover state (designer, 2026-07-30). Withdrawn wholesale by the prefers-reduced-motion block at the end of this file */
	--dpk-gap-list-columns: 20px;        /* List view: BETWEEN the card columns — on top of each card's own --dpk-pad-results, so the visible gutter is this + 2×20px. Matches the row gap and the grid's own padding: one 20px rhythm around and between the cards (Jennifer, 2026-07-29) */
	--dpk-gap-list-rows: 20px;           /* List view: BETWEEN the card rows — likewise on top of each card's --dpk-pad-card, so the visible separation is this + 2×20px */

	/* ------------------------------------------------------------- Layout */
	--dpk-sidebar-width: 500px;          /* Fixed left sidebar width */
	--dpk-locator-max: 1356px;           /* Total width, flexible */
	/* Desktop cap for the WHOLE two-panel widget (search + expanded Filter +
	   results); the list scrolls within the leftover space. Viewport-relative
	   rather than the flat 740px it started as, because a fixed pixel cap is only
	   ever right for the one display it was measured on: it wasted a tall monitor
	   and overflowed a short one.
	     76vh  — reproduces the original 740px on the ~975px viewport of a 1080p
	             laptop, so the tuned-for display is unchanged.
	     480px — floor. At 200% browser zoom a 1080p viewport is ~480 CSS px tall;
	             the old 740px could not fit there at all, so the widget ran past
	             the screen and nested a scroller inside a scrolling page (1.4.4).
	     1040px— ceiling, so an unscaled 4K monitor doesn't stretch the sidebar
	             into a column taller than the widget is wide.
	   `vh` (not `dvh`) on purpose: every rule using this token is inside
	   the wide container query, where no collapsing browser chrome exists to correct for,
	   and `vh` has shipped since IE9 while `dvh` only lands in 2022 engines.
	   No px fallback declaration is paired with this: the repeated-declaration
	   trick does NOT work in a custom property (its value is parsed as an arbitrary
	   token sequence, so a `clamp()`-less engine accepts the declaration and then
	   fails at the *use* site, computing max-height to `none`). clamp() is
	   supported in every engine from 2020 on — far less exotic than the WebGL
	   basemap this plugin already requires. */
	--dpk-widget-max-height: clamp( 480px, 76vh, 1040px );

	/* ---------------------------------------------------------- Basemap */
	/* Vector-basemap palette ("variant A", designer review 2026-07-24 — see
	   docs/maps/MAP-TILE-SELECTION.md §6). These are tokens rather than literals in
	   the style JSON for the usual reason: they stay themeable and dashboard-
	   overridable like the rest of the palette. They cannot be *consumed* by CSS,
	   though — a WebGL canvas has no cascade — so locator-map.js reads them with
	   getComputedStyle() at init and feeds them to MapLibre's setPaintProperty().
	   The resolution order (admin → theme → fallback, D6/D23) is unchanged; it just
	   resolves in JS instead of CSS.

	   The muting deliberately stops at the geometry: road LABELS and route SHIELDS
	   are exempt and keep full contrast. That distinction is the whole point of
	   moving off the old `filter: opacity()` on the raster tiles, which faded label
	   text and terrain alike. Also learned the hard way: on a field this pale, major
	   roads and motorways must carry visible tone — white-on-white made the network
	   vanish and left the shields floating in empty space (§6.1). */
	--dpk-map-land: #f1f5f8;             /* Background / default landcover */
	--dpk-map-residential: #e9eff4;      /* Built-up areas, schools, hospitals */
	--dpk-map-green: #e4eee8;            /* Parks, woodland, grass, pitches */
	--dpk-map-water: #d4e5ef;            /* Water bodies + waterways */
	--dpk-map-sand: #f1f0ea;
	--dpk-map-building: #e2e9ef;
	--dpk-map-aeroway: #e6edf2;
	--dpk-map-road: #fff;                /* Minor roads, streets, service, paths */
	--dpk-map-road-major: #ccd8e2;       /* Trunk / primary / secondary / tertiary */
	--dpk-map-motorway: #bfcedb;
	--dpk-map-casing: #dde5ec;           /* Outline for minor roads */
	--dpk-map-casing-major: #c4d1dc;
	--dpk-map-casing-motorway: #a5b8c8;
	--dpk-map-rail: #dae2e8;
	--dpk-map-boundary: #bcc7d0;
	--dpk-map-label: #39424b;            /* Label text — NOT muted (see above) */
	--dpk-map-label-halo: #fff;

	/* ------------------------------------------------------------ Utility */
	--dpk-color-muted: #5c6470;          /* Secondary/status text */
	/* Form-control boundary: must meet WCAG 1.4.11 (≥3:1) against the white field
	   fill and the page, since the border is what identifies the control. The
	   decorative --dpk-color-divider is for grouping (cards, chips) only. */
	--dpk-field-border: #878787;
	--dpk-focus: var( --dpk-color-accent );
	--dpk-radius: 6px;

	font-family: var( --dpk-font-family, inherit );
	font-weight: var( --dpk-fw-default );
	/* Explicit, not inherited: this is what the firewall below hands every line of
	   text whose rule doesn't set its own. 1.4 is what the widget was designed
	   against (Twenty Twenty-Five's inherited ratio, measured 2026-08-12); leaving
	   it to the theme let production's `line-height: normal` (≈1.15) through. */
	line-height: 1.4;
	color: var( --dpk-color-text );
	display: block;
	max-width: var( --dpk-locator-max );
	margin: 0 auto;
}

.dpk-locator * {
	box-sizing: border-box;
}

/* The `hidden` attribute must always win: several locator elements set an author
   `display` (flex/grid/inline-flex) that would otherwise override the UA
   `[hidden]{display:none}` — e.g. a collapsed panel body or the not-yet-wired
   view toggle. (The map clears its own `hidden` attribute on reveal, so it is
   unaffected once shown.) */
.dpk-locator [hidden] {
	display: none !important;
}

/* ============================================================== THEME FIREWALL */

/* Themes style bare ELEMENTS, and those rules reach inside the widget: the
   production theme ships `h3 { font-size: 55px; line-height: 61px }`,
   `p, li { font-size: 18px; font-weight: 500; color: #555 }` and
   `h1–h6, p { margin: 0 0 20px }` — so the seat-type list blew up to 18px, every
   site name sat on a 61px line box, and stray 20px margins opened under headings.
   This block turns those element-level rules back into INHERITANCE: everything
   here resolves to what `.dpk-locator` itself establishes, and the widget's own
   class rules then set the real values on top.

   `:where()` keeps every selector at exactly 0-1-0 (the lone `.dpk-locator`
   class), which is the load-bearing part: it BEATS any theme element selector
   (`h3`, `p a` — classes outrank elements) while TYING the widget's own
   single-class rules, all of which come later in this file (or in
   locator-map.css/print.css, which enqueue after it) and so win on source order.
   Nothing below this block needs extra specificity to override it.

   Consequences to keep in mind:
   - Headings must carry an explicit `line-height` in their own rule (they do:
     1.125, the ratio the design was approved at) — inherit would hand them the
     body's 1.4.
   - Any NEW p/li/heading style must state its own margins and sizes; there is no
     theme default to lean on any more. That's the point.
   - Leaflet's attribution links keep their colors: leaflet.css targets
     `.leaflet-container a` (0-1-1), which outranks this. */
.dpk-locator :where( h1, h2, h3, h4, h5, h6, p, ul, ol, li, legend, label, a ) {
	margin: 0;
	font-family: inherit;
	font-size: inherit;
	font-weight: inherit;
	line-height: inherit;
	color: inherit;
}

/* Form controls don't inherit fonts by default (the UA gives each its own), and
   several here rely on the cascade for their face. The widget's own rules keep
   sizing them; only the family is forced through. */
.dpk-locator :where( button, input, select, textarea ) {
	font-family: inherit;
}

/* ====================================================================== LAYOUT */

/* The breakpoint is the CONTAINER's width, not the viewport's. Page builders wrap
   the shortcode in rows of arbitrary width (production caps its row at 55% of the
   page), so "how wide is the window" says nothing about how much room the widget
   actually has — a 1280px laptop there yields a ~620px column, which the old
   `@media ( min-width: 900px )` confidently laid out as two panels with a 500px
   sidebar. Every width query below is therefore an `@container` against the
   wrapper `.dpk-locator-container` (templates/locator.php — the section cannot be
   its own query container).

   THE THRESHOLD IS 750px OF CONTAINER: the narrowest two-panel that still works —
   a sidebar squeezed to its 420px floor plus a 320px map, with a little slack.
   Vertical (`max-height`) conditions stay on `@media`: vertical room really is
   the viewport's.

   Browsers without container queries (pre-2023) drop these blocks entirely and
   get the single-column presentation at every width — the accessible baseline,
   same as no-JS.

   JS follows the SAME threshold by reading `--dpk-wide` below (set here, in CSS,
   so there is exactly one definition) instead of its own matchMedia. */
.dpk-locator-container {
	container-type: inline-size;
	container-name: dpk-locator;
	/* The same escape `.dpk-locator` performs with its own max-width: block themes
	   cap every direct child of the content column at the theme's content size
	   (Twenty Twenty-Five: 645px) via zero-specificity `:where()` rules, and any
	   author declaration outranks that. Without this the WRAPPER gets capped, the
	   container measures 645px, and the breakpoint below can never see "wide".
	   The value mirrors --dpk-locator-max (defined on the section, out of reach
	   here) — keep the two in sync. */
	max-width: 1356px;
	margin: 0 auto;
}

@container dpk-locator ( width >= 750px ) {
	.dpk-locator {
		--dpk-wide: 1;
	}
}

/* Two-panel grid: enhancement only (JS adds `is-enhanced`; `has-map` means a map
   container is present). Wide containers only. */
@container dpk-locator ( width >= 750px ) {
	.dpk-locator.is-enhanced.has-map {
		display: grid;
		/* The sidebar CEDES width before the layout breaks: at full design width it
		   holds its 500px, and in tighter containers (750–830px) it shrinks toward
		   its 420px floor so the map keeps a usable 320px minimum. */
		grid-template-columns: minmax( 420px, var( --dpk-sidebar-width ) ) minmax( 320px, 1fr );
		align-items: stretch;
	}
	.dpk-locator.is-enhanced.has-map .dpk-sidebar {
		grid-column: 1;
	}
	.dpk-locator.is-enhanced.has-map .dpk-map {
		grid-column: 2;
		margin: 0;
		height: 100%;
	}
	.dpk-locator.is-enhanced.has-map .dpk-map-canvas {
		height: 100%;
	}
}

/* Below the two-panel breakpoint only one pane shows at a time. By default (and
   with no JS) the map is hidden and the accessible list stands alone; the JS
   view toggle's `dpk-view-map` class swaps to the map and hides the list. */
@container dpk-locator ( width < 750px ) {
	.dpk-map {
		display: none;
	}
	.dpk-locator.dpk-view-map .dpk-map {
		display: block;
	}
	.dpk-locator.dpk-view-map .dpk-results-scroll {
		display: none;
	}
}

.dpk-sidebar {
	display: flex;
	flex-direction: column;
	min-width: 0;
	/* Allow the sidebar to shrink below its content within the capped grid so the
	   results list (not the whole widget) absorbs the overflow by scrolling. */
	min-height: 0;
}

/* The form is just a wrapper around the blue panel; the panel owns the layout. */
.dpk-search {
	display: block;
	margin: 0;
}

/* ================================================================ SEARCH PANEL */

.dpk-panel {
	background: var( --dpk-color-primary );
	color: var( --dpk-color-on-color );
	padding: var( --dpk-pad-panel );
	display: flex;
	flex-direction: column;
	gap: var( --dpk-gap );
}

.dpk-panel-heading {
	margin: 0;
	color: var( --dpk-color-on-color );
	font-weight: var( --dpk-fw-bold );
	line-height: 1.125; /* Explicit on every heading — see .dpk-site-name. */
}

.dpk-panel-find > .dpk-panel-heading {
	font-size: var( --dpk-fs-h1 );
}

.dpk-panel-filter > .dpk-panel-heading {
	font-size: var( --dpk-fs-h2 );
}

/* The "Find PreK" section used to carry a thin rule along its bottom, separating
   it from "Filter". Dropped 2026-07-24 (designer): the panel's own spacing already
   separates the two, and the rule cut across the blue field for no work. The
   padding stays — it is what keeps the gap the rule used to sit in. */
.dpk-panel-find {
	padding-bottom: var( --dpk-gap );
}

.dpk-panel-body {
	display: flex;
	flex-direction: column;
	gap: var( --dpk-gap );
	/* Tighter than --dpk-gap on purpose (designer, 2026-07-22): the space under a
	   section title reads as part of the title, so it wants less air than the gap
	   BETWEEN fields, which stays at --dpk-gap. */
	margin-top: 0.65rem;
}

/* Address search row: full-width input + square accent submit button. */
.dpk-field-address {
	margin: 0;
}

.dpk-search-row {
	display: flex;
	align-items: stretch;
}

#dpk-address {
	flex: 1 1 auto;
	min-width: 0;
	border: none;
	/* `type="search"`, so WebKit gives it the native pill shape unless appearance is
	   reset — and a rounded control CLIPS the focus bar below, which is what made
	   that bar look round-ended against a square field (Jennifer, 2026-07-24).
	   `border-radius: 0` alone does not do it: the rounding comes from the UA
	   appearance, not from the property. Also drops WebKit's inner shadow and its
	   own cancel button (we have a submit button of our own). */
	appearance: none;
	-webkit-appearance: none;
	border-radius: 0;
	padding: 0.6rem 0.75rem;
	font: inherit;
	font-size: var( --dpk-fs-placeholder );
	color: var( --dpk-color-text );
	background: #fff;
}

#dpk-address::placeholder {
	color: rgba( 0, 0, 0, 0.5 );
}

/* The address field opts OUT of the standard orange focus box (designer call,
   2026-07-24): an outline around the white field, inset in the blue panel and
   butted against the submit button, read as a stray box. Focus still HAS to be
   visible (WCAG 2.4.7), so it moves to a 3px accent bar inside the foot of the
   field — same accent, contained by the control instead of drawn around it, and
   ≈5.5:1 against the white fill (1.4.11 wants 3:1).
   `box-shadow` is dropped in forced-colors modes, so the outline comes back there. */
#dpk-address:focus-visible {
	outline: none;
	box-shadow: inset 0 -3px 0 0 var( --dpk-color-accent );
}

@media ( forced-colors: active ) {
	#dpk-address:focus-visible {
		outline: 2px solid Highlight;
		outline-offset: -2px;
	}
}

.dpk-submit {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 3rem;
	border: none;
	border-radius: 0;
	background: var( --dpk-color-accent );
	color: var( --dpk-color-on-color );
	cursor: pointer;
}

.dpk-submit .dpk-icon {
	width: var( --dpk-fs-placeholder );
	height: var( --dpk-fs-placeholder );
	fill: currentColor;
}

.dpk-submit:hover {
	filter: brightness( 0.93 );
}

/* Distance dropdown, inline on the address row. A white box between the address
   input and the accent submit button, separated by a thin divider, with a dark
   caret (native <select> kept for accessibility; only its box is decorated). */
.dpk-radius-inline {
	position: relative;
	flex: 0 0 auto;
	display: flex;
	align-items: stretch;
	background: #fff;
	/* The divider between the address field and the distance control is the
	   boundary that separates two interactive controls, so it uses the
	   AA field-border token (≥3:1, WCAG 1.4.11), not the decorative divider. */
	border-left: 1px solid var( --dpk-field-border );
}

.dpk-radius-inline select {
	appearance: none;
	-webkit-appearance: none;
	border: none;
	/* Both halves are needed, and each fixes what the other cannot — the same pairing
	   #dpk-address carries above, for the same reason. `appearance: none` alone leaves
	   WebKit's UA `border-radius: 5px` standing on a <select> (MEASURED in WebKit 26:
	   computed radius 5px with appearance already none), and a rounded control CLIPS
	   the inset focus bar below into a pill — which is what Safari was drawing under
	   "10 mi" while Chrome and Firefox showed a square bar. Verify this in WebKit, not
	   Chromium: Blink drops the radius with the appearance and shows nothing wrong. */
	border-radius: 0;
	background: transparent;
	padding: 0.6rem 1.9rem 0.6rem 0.75rem;
	font: inherit;
	font-size: var( --dpk-fs-placeholder );
	font-weight: var( --dpk-fw-default );
	color: var( --dpk-color-text );
	cursor: pointer;
}

/* Same focus treatment as the address field beside it (designer call,
   2026-07-24): no orange box drawn around the control — the search row is one
   visual bar, and a ring around the middle segment of it looked like a stray box.
   Focus becomes a 3px accent bar inset at the foot of the segment, so the
   indicator travels along the bar as focus moves. Still meets 2.4.7, and ≈5.5:1
   on the white fill against the 3:1 that 1.4.11 asks. `box-shadow` is dropped in
   forced-colors modes, so the outline comes back there.
   The leading `.dpk-locator` is load-bearing: without it this selector TIES the
   FOCUS section's `.dpk-locator select:focus-visible` (both 0-2-1) and loses on
   source order, since that rule comes later in the file. */
.dpk-locator .dpk-radius-inline select:focus-visible {
	outline: none;
	box-shadow: inset 0 -3px 0 0 var( --dpk-color-accent );
}

@media ( forced-colors: active ) {
	.dpk-locator .dpk-radius-inline select:focus-visible {
		outline: 2px solid Highlight;
		outline-offset: -2px;
	}
}

.dpk-radius-inline::after {
	content: "";
	position: absolute;
	right: 0.7rem;
	top: 50%;
	width: 0;
	height: 0;
	transform: translateY( -25% );
	border-left: 5px solid transparent;
	border-right: 5px solid transparent;
	border-top: 6px solid var( --dpk-color-accent );
	pointer-events: none;
}

/* ===================================================================== FILTERS */

/* Two-column filter grid: Seat Type on the left (its longer list defines the
   block height), Extended Care top-right, and the Reset link tucked into the empty
   space beneath Extended Care — bottom-aligned — to reclaim vertical space.
   Distance moved onto the address row (search-form.php). Collapses to one column on
   mobile. */
.dpk-filters {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var( --dpk-gap );
	align-items: start;
}

/* Seat Type spans both rows so its height governs the block; Extended Care and the
   Reset link stack in the right column (care top, reset bottom-aligned). */
.dpk-filter-seat-types {
	grid-column: 1;
	grid-row: 1 / span 2;
}

.dpk-filter-care {
	grid-column: 2;
	grid-row: 1;
}

/* Filter group labels (Extended Care, Seat Type). */
.dpk-panel legend {
	color: var( --dpk-color-filter-label );
	font-size: var( --dpk-fs-h3 );
	font-weight: var( --dpk-fw-bold );
	padding: 0;
	margin: 0 0 0.25rem;
}

/* On the blue panel the fieldsets are unboxed (label + controls only). */
.dpk-panel .dpk-filter {
	border: none;
	padding: 0;
	margin: 0;
}

/* Checkbox options (Before/After Care, Seat Type list). */
.dpk-panel .dpk-checkbox {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0 0 0.1rem;
	color: var( --dpk-color-on-color );
	font-size: var( --dpk-fs-checkbox );
	/* The designer asked for "600 / semi-bold" here. 600 is not a face the kit
	   ships (Regular 400 / Demi 700 / Heavy 800), so it would snap to Demi anyway
	   — we name the real face instead. See the font-weight gotcha in CLAUDE.md. */
	font-weight: var( --dpk-fw-demi );
	cursor: pointer;
}

.dpk-panel input[type="checkbox"] {
	accent-color: var( --dpk-color-accent );
	/* `color` does not inherit into form controls — the UA gives them their own
	   black. That left the focus ring (now `currentColor`) painting black here while
	   every other control on the blue panel rings white. Inheriting the panel's white
	   puts them back in step; the tick itself is drawn from accent-color, not this. */
	color: inherit;
	width: 1rem;
	height: 1rem;
	flex: 0 0 auto;
	margin: 0;
}

.dpk-reset {
	grid-column: 2;
	grid-row: 2;
	justify-self: start;
	align-self: end; /* Bottom-align under Extended Care to fill the dead space. */
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
	margin: 0;
	color: var( --dpk-color-on-color );
	font-size: var( --dpk-fs-small );
	font-weight: var( --dpk-fw-demi );
	/* Uppercased in CSS, not by changing the link text — keeps the translated
	   string and the accessible name intact (same approach as the action links). */
	text-transform: uppercase;
	text-decoration: none;
}

.dpk-reset .dpk-icon {
	fill: currentColor;
}

.dpk-reset:hover {
	text-decoration: underline;
}

/* ============================================================ COLLAPSE TOGGLES */

/* Injected by JS: the panel heading becomes a real button controlling its body. */
.dpk-collapse-toggle {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	width: 100%;
	padding: 0;
	border: none;
	background: none;
	color: inherit;
	font: inherit;
	font-size: inherit;
	font-weight: inherit;
	text-align: left;
	cursor: pointer;
}

.dpk-collapse-icon {
	width: 0.85em;
	height: 0.85em;
	fill: currentColor;
	flex-shrink: 0;
}

/* ============================================================== RESULTS REGION */

.dpk-results-section {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	min-height: 0;
	background: #fff;
	/* Vertical padding only: the header, status, and cards carry their own
	   horizontal padding so a selected card's background can bleed full-width.
	   No bottom padding — the list scrolls to the panel's bottom edge. */
	padding: 14px 0 0;
	border: 1px solid var( --dpk-color-divider );
	border-top: none;
}

/* Horizontally inset the fixed chrome to match the card content indent. */
.dpk-results-header,
.dpk-view-switch,
.dpk-no-results {
	padding-left: var( --dpk-pad-results );
	padding-right: var( --dpk-pad-results );
}

.dpk-results-header {
	display: flex;
	justify-content: space-between;
	/* `center`, not `baseline`: the header's second child is now the view-style
	   switch — a box with no text of its own, so a baseline would align its
	   bottom edge to the heading's and hang it below the row. */
	align-items: center;
	gap: var( --dpk-gap );
}

.dpk-results-heading {
	margin: 0;
	font-size: var( --dpk-fs-h1 );
	font-weight: var( --dpk-fw-bold );
	line-height: 1.125; /* Explicit on every heading — see .dpk-site-name. */
	color: var( --dpk-color-primary );
}

/* The header's right-hand controls: the view-style switch, then the print link.
   One box so the pair moves as a unit — in list view the header becomes a grid
   band and this is the single cell that carries both (see LIST VIEW below).
   No gap: the three cells abut and share their hairlines (Jennifer, 2026-07-30). */
.dpk-results-tools {
	display: inline-flex;
	flex: 0 0 auto;
	align-items: center;
}

/* Results-header view-style switch (JS-injected — no-JS gets the plain list, so
   there is no view to choose). Two icon-only cells in a hairline accent box: the
   selected view is accent-filled with a white icon, the other white with an
   accent icon (designer comp, 2026-07-24). Square corners, no gap — the cells
   share one border. */
.dpk-view-style-switch {
	display: inline-flex;
	flex: 0 0 auto;
	border: 1px solid var( --dpk-color-accent );
}

.dpk-view-style-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 38px;
	padding: 0;
	border: none;
	background: #fff;
	/* The icon is `fill: currentColor`, so this recolors it in both states. */
	color: var( --dpk-color-accent );
	font-size: 1.15rem; /* Sizes the 1em icon (~18px). */
	cursor: pointer;
}

/* The divider between the cells; the box itself supplies the outer edges. */
.dpk-view-style-btn + .dpk-view-style-btn {
	border-left: 1px solid var( --dpk-color-accent );
}

.dpk-view-style-btn[aria-pressed="true"] {
	background: var( --dpk-color-accent );
	color: var( --dpk-color-on-color );
}

/* Hover previews the selected state — the print link's treatment, adopted here for
   all three cells (Jennifer, 2026-07-30). On the cell that is already pressed this
   changes nothing; on the other it shows what picking it would look like. Not
   `:focus`: the fill flips currentColor to white, and the focus ring is drawn IN
   currentColor (see FOCUS). */
.dpk-view-style-btn:hover {
	background: var( --dpk-color-accent );
	color: var( --dpk-color-on-color );
}

/* The printable-view link (JS-injected, D38). Same cell size and hairline frame as
   the switch, abutting it so the three icons read as one row of controls — but it
   stays its OWN element outside the switch's `role="group"`, because it is an
   action, not a third view to be in: nothing here is ever "pressed", and a link
   inside a group of toggles would say otherwise.
   LIST VIEW ONLY: it is hidden in map view, where the header is already busy
   (Jennifer, 2026-07-30). Keyed on the map value rather than on `="list"` so a
   locator with map="none" — which never gets the attribute, or a switch — still
   shows it. `display: none` also takes it out of the a11y tree, so map view is
   left with no phantom control. */
.dpk-print-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* Sized to the SWITCH's outer box, not to one of its cells: the cells are 44×38
	   inside a 1px frame, so the frame stands 40px tall and each cell shows a 44px
	   field. Matching that here means 40 tall, and 45 wide — 44 of field plus this
	   box's own right border (border-box; its left edge is the switch's right
	   border, which it shares). At 44×38 it sat 2px short of the switch. */
	width: 45px;
	height: 40px;
	border: 1px solid var( --dpk-color-accent );
	/* The switch's own right edge already draws this line — a second one beside it
	   would paint 2px where every other divider in the box is 1px. */
	border-left: none;
	background: #fff;
	/* The icon is `fill: currentColor`, so this colors it. */
	color: var( --dpk-color-accent );
	font-size: 1.15rem; /* Sizes the 1em icon (~18px). */
	text-decoration: none;
}

/* …unless there is no switch to lean on (map="none"), where it is the only control
   in the cluster and needs its own left edge. */
.dpk-results-tools > .dpk-print-link:first-child {
	border-left: 1px solid var( --dpk-color-accent );
}

.dpk-locator[data-dpk-view-style="map"] .dpk-print-link {
	display: none;
}

/* Hover only (not `:focus`): the fill flips currentColor to white, and the focus
   ring is drawn IN currentColor — see the FOCUS section, where this link takes
   the same inset ring the switch cells do. */
.dpk-print-link:hover {
	background: var( --dpk-color-accent );
	color: var( --dpk-color-on-color );
}

/* Mobile List/Map view switch (JS-injected). Two 50/50 buttons; the active view
   is accent-filled, the inactive one white with an accent outline. Hidden on
   desktop (both panes show) — revealed in the mobile media query below. */
.dpk-view-switch {
	display: none;
	margin: var( --dpk-gap-results-details ) 0;
}

.dpk-view-btn {
	flex: 1 1 50%;
	height: 40px;
	border: 1px solid var( --dpk-color-accent );
	background: #fff;
	color: var( --dpk-color-accent );
	font: inherit;
	font-size: var( --dpk-fs-checkbox );
	font-weight: var( --dpk-fw-bold );
	text-transform: uppercase;
	cursor: pointer;
}

.dpk-view-btn--map {
	border-left: none;
}

.dpk-view-btn[aria-pressed="true"] {
	background: var( --dpk-color-accent );
	color: var( --dpk-color-on-color );
}

/* "Showing N sites…" line — the last element of the fixed chrome, so it marks the
   boundary between that chrome and the scrolling list. The 2px primary-blue rule
   that used to draw the divide is gone (designer, 2026-07-22): a soft drop shadow
   now does that job instead.
   The shadow lives HERE rather than on a wrapper around the heading + status
   because it is offset downward — the only edge it paints on is the bottom one,
   which is this element's, so a wrapper would render identically while costing a
   markup change in both the template and the JS renderer.
   `position: relative` + `z-index` are REQUIRED, not decoration: .dpk-results-scroll
   below is itself positioned, so as a static box this element's shadow would paint
   *under* the list and be invisible. Full-bleed (no horizontal margin) so the
   shadow spans the panel; the text inset comes from padding. */
.dpk-status {
	position: relative;
	z-index: 1;
	margin: 5px 0;
	padding: 0 var( --dpk-pad-results ) 15px;
	box-shadow: 0 6px 10px var( --dpk-color-scroll-track );
	color: var( --dpk-color-text );
	font-size: var( --dpk-fs-site-info );
}

/* The one status that is a NOTICE rather than a report: the address did not
   resolve, so the list fell back to every site (D57). Colour is the flag, in the
   brand orange — the palette has no orange heading, `--dpk-color-accent` is the
   only orange in it, and it measures 5.07:1 on white (AA for body text).
   Colour is deliberately NOT the only signal: the sentence itself says what
   happened and is announced through the live region, so 1.4.1 is satisfied
   without it. Weight is left alone — the accent already separates this line from
   the black report above it, and bolding shouted.
   Set by both the template and setStatus() in locator.js; keep the two in step. */
.dpk-status.is-notice {
	color: var( --dpk-color-accent );
}

/* DESKTOP MAP VIEW ONLY: close the gap under "Search Results" (Jennifer,
   2026-07-28 — it read as roughly twice the space it needed).
   The gap is not typographic. `.dpk-results-header` is a centred flex row whose
   height comes from the 40px view-style switch, not from the 24.75px heading, so
   ~7.6px of pure centring slack hangs under the heading's text before this element's
   own 5px margin even starts — measured 19.75px of white between the two lines' ink.
   The status pulls back up into that slack (its box still clears the heading's by
   2.6px, so nothing overlaps), landing the ink gap at ~10px.
   BOTH halves of the scope are load-bearing. The attribute is only set when the
   switch exists at all (map="none" and no-JS never get one), and the media query is
   what keeps this off MOBILE — the attribute is set there too, but the switch is
   `display: none` in narrow containers, so the header is only as tall as its heading and
   there is no slack to reclaim; -5px would close the gap outright. List view has its
   own one-band rules further down. */
@container dpk-locator ( width >= 750px ) {
	.dpk-locator[data-dpk-view-style="map"] .dpk-status {
		margin-top: -5px;
		/* Keep the text out of the controls' column. That -5px is what makes this
		   necessary: it lifts this full-bleed line's box INTO the header's, so the
		   first line's top overlaps the view switch and print link by exactly those
		   5px. It went unnoticed while the line read "Showing 49 sites." — short
		   enough never to reach across — but the status now names the resolved
		   address (D46), which runs the panel's full width and passes under them.
		   Reserving the column here (rather than dropping the -5px, which the
		   designer asked for, or re-parenting the status into the header, which is
		   an aria-live region best left where it is) makes the text wrap early and
		   respect their space. `--dpk-tools-w` is measured and published by
		   locator.js; the 0px fallback is the no-JS case, where no controls exist
		   and the line is free to use the full width. */
		padding-right: calc( var( --dpk-pad-results ) + var( --dpk-tools-w, 0px ) + var( --dpk-gap ) );
	}
}

/* Scrolling results area. On desktop it flex-fills whatever height the widget cap
   leaves after the search panel + (possibly expanded) Filter, and scrolls inside
   it — so a taller panel shrinks the list rather than growing the whole widget. */
.dpk-results-scroll {
	flex: 1 1 auto;
	overflow-y: auto;
	min-height: 0;
	/* REQUIRED, not cosmetic: makes this the containing block for the absolutely
	   positioned descendants inside the list — every `.dpk-sr-only` span and each
	   `.dpk-show-on-map` button (~250 of them across 49 cards). `overflow` only
	   clips descendants it actually contains, so while this box was `static` those
	   elements resolved against a *theme* wrapper far outside it, escaped the
	   clip, and reported static positions up to ~10,500px down — inflating
	   documentElement.scrollHeight to ~11,200px and letting the whole PAGE scroll
	   miles past the footer into white space.
	   Safe because nothing that escapes sets top/left/right/bottom: the sr-only
	   pattern relies on its static position (+ clip), and the `|` pseudo-separators
	   are already contained by `.dpk-actions a { position: relative }`. */
	position: relative;
	/* Keep wheel/touch scroll inside the list: at the top/bottom edge don't chain
	   the scroll out to the whole page. */
	overscroll-behavior: contain;
}

/* Scrollbar styling has TWO mutually exclusive paths, and sending both to the same
   browser is why this silently did nothing in Safari: WebKit ignores every
   `::-webkit-scrollbar` rule on an element that also specifies the standard
   `scrollbar-width`/`scrollbar-color` (Safari 18+ supports the standard props and
   opts out of the legacy pseudo-elements). This container carried
   `scrollbar-width: thin` from an earlier phase, so the pseudo-element rules below
   had been dead in Safari all along.
   So: hand the standard properties ONLY to engines with no `::-webkit-scrollbar`
   support (Firefox), and leave WebKit/Blink to the pseudo-elements. */
@supports not selector( ::-webkit-scrollbar ) {
	.dpk-results-scroll {
		scrollbar-width: thin;
		/* thumb, then trough. */
		scrollbar-color: var( --dpk-color-divider ) var( --dpk-color-scroll-track );
	}
}

/* Style the NATIVE scrollbar only — never overlay anything on top of it. An
   absolutely-positioned strip on an ancestor paints ABOVE a descendant's
   scrollbar (a scrollbar renders with its own element's background layer, not
   above positioned descendants of ancestors), which hides the thumb entirely and
   leaves a dead gray column. That was tried and reverted; don't reintroduce it.
   Note these rules apply only where the platform draws CLASSIC scrollbars —
   macOS falls back to unstyleable overlay scrollbars when driven by a trackpad
   alone, in which case this degrades to the OS default. */
.dpk-results-scroll::-webkit-scrollbar {
	width: 14px;
}

.dpk-results-scroll::-webkit-scrollbar-track {
	background: var( --dpk-color-scroll-track );
}

/* Thumb widened 6px → 8px by trimming its inset border 4px → 3px; the border is
   drawn in the track color so it reads as padding inside the trough rather than a
   white gap cut through it. */
.dpk-results-scroll::-webkit-scrollbar-thumb {
	background: var( --dpk-color-divider );
	border-radius: 999px;
	border: 3px solid var( --dpk-color-scroll-track );
	background-clip: padding-box;
}

@container dpk-locator ( width >= 750px ) {
	/* Fix the WHOLE two-panel widget at this height by bounding the sidebar (search
	   + expandable Filter + results). The results list flex-scrolls within whatever
	   space the panel leaves, so expanding Filter shrinks the list rather than growing
	   the widget past the cap. The map is a grid item that stretches to the sidebar's
	   height. (Capping the grid *container* instead wouldn't work — an auto-sized grid
	   row ignores the container's max-height and overflows.)
	   min-height == max-height so a short/empty result list can't collapse the sidebar
	   — and with it the stretched map — into a squished horizontal sliver. */
	.dpk-locator.is-enhanced.has-map .dpk-sidebar {
		min-height: var( --dpk-widget-max-height );
		max-height: var( --dpk-widget-max-height );
	}
	/* No side map (map="none" or no JS): the single accessible column keeps its own
	   scroll cap so a long result set doesn't run the page off. */
	.dpk-locator:not( .has-map ) .dpk-results-scroll {
		max-height: var( --dpk-widget-max-height );
	}
}

/* ================================================================ RESULT CARDS */

.dpk-results {
	list-style: none;
	margin: 0;
	padding: 0;
}

.dpk-site {
	padding: var( --dpk-pad-card ) var( --dpk-pad-results );
	border: none;
	border-radius: 0;
}

/* On desktop the whole record is a click target that shows the site on the map
   (JS-injected behaviour, present only when a map is). */
@container dpk-locator ( width >= 750px ) {
	.dpk-locator.has-map .dpk-results .dpk-site {
		cursor: pointer;
	}
}

.dpk-site--active {
	background: var( --dpk-color-selected-bg );
}

/* Name (left) + distance (right) on one row, then 6px, then the divider rule,
   then 10px before details. */
.dpk-site-header {
	display: flex;
	justify-content: space-between;
	/* Sit the distance on the name's LAST line, just above the rule. Plain `baseline`
	   aligns to the FIRST line, so a name that wrapped to two lines left the distance
	   stranded ~22px up, reading as vertically centred against the title block
	   (Jennifer, 2026-07-24).
	   Two declarations, not one: `last baseline` is the typographically correct answer
	   (the distance shares the last line's baseline, so single-line cards render
	   exactly as before), but engines that don't support it drop the declaration —
	   without the `flex-end` beneath it they would fall back to `normal`/stretch and
	   the distance would stretch to the title's full height. */
	align-items: flex-end;
	align-items: last baseline;
	gap: var( --dpk-gap );
	margin: 0 0 var( --dpk-gap-after-divider );
	padding-bottom: var( --dpk-gap-after-name );
	border-bottom: 1px solid var( --dpk-color-divider );
}

.dpk-site-name {
	margin: 0;
	font-size: var( --dpk-fs-h2 );
	font-weight: var( --dpk-fw-bold );
	/* Explicit because the firewall hands headings the body's 1.4 otherwise; 1.125
	   is the ratio the design was approved at (and what production's theme blew up
	   to a 61px line box before the firewall). Same value on every heading rule. */
	line-height: 1.125;
	color: var( --dpk-color-accent );
}

.dpk-distance {
	flex: 0 0 auto;
	margin: 0;
	font-size: var( --dpk-fs-site-info );
	font-weight: var( --dpk-fw-bold );
	color: var( --dpk-color-accent );
	white-space: nowrap;
}

/* Two-column card info on desktop: address / phone (primary) on the left,
   extended care / seat types (secondary) on the right. Single column on mobile
   and no-JS. */
.dpk-site-info {
	display: grid;
	grid-template-columns: 1fr;
	/* Base size for the block, matching the rows inside it, so any child that does
	   not set its own size stays in step. It used to be load-bearing: while
	   --dpk-gap-info-list was an `em`, a `gap` resolved it against THIS element, so
	   omitting this grew the gap from 8.75px to 11.41px. The token is `rem` now, so
	   the gap no longer depends on it — keep the em trap in mind before making any
	   of these gaps relative again. */
	font-size: var( --dpk-fs-site-info );
	/* Single column: the two groups sit on top of each other, so the block needs a
	   row gap BETWEEN them or the last row of `primary` would butt right up against
	   the first row of `secondary`. Zeroed again in wide containers, where the groups become
	   side-by-side columns and there is only one row. */
	row-gap: var( --dpk-gap-info-list );
}

/* The rows are spaced by the groups' own `gap`, not per-row margins. Margins here
   meant the last row of each group had to be zeroed so it wouldn't stack with the
   actions' spacing below — and that zeroing was wrong in one column, where
   `primary`'s last row (the phone) is NOT the last row of the block and does still
   need a gap under it. Measured symptom: rows ran 8.75px / 0 / 8.75px, so the phone
   and extended-care lines collided. `gap` sizes the space BETWEEN rows and never
   adds a trailing one, so it is correct in both layouts without a special case. */
.dpk-site-info-primary,
.dpk-site-info-secondary {
	display: flex;
	flex-direction: column;
	gap: var( --dpk-gap-info-list );
	min-width: 0;
}

/* A Site with neither extended care nor seat types still renders the wrapper (one
   of the 49 does). Left in flow it is a zero-height grid item that the row-gap above
   still spaces away from — measured 21.75px over the actions where a normal card has
   13px.

   `:empty` alone does NOT catch it: the PHP template indents the wrapper's contents,
   so the "empty" div still holds a whitespace text node, and CSS `:empty` counts
   those. `:not(:has(*))` asks the question actually meant — no ELEMENT children —
   and matches whether the card came from PHP (whitespace) or from the JS
   renderItem() (usually none). `:empty` is kept as the cheaper first match. */
.dpk-site-info-secondary:empty,
.dpk-site-info-secondary:not( :has( * ) ) {
	display: none;
}

@container dpk-locator ( width >= 750px ) {
	.dpk-site-info {
		/* Two side-by-side columns = a single grid row, so no row gap to give. */
		row-gap: 0;
		/* Even columns: the right column now carries one short extended-care line
		   plus the seat types rather than the old three-line hours block, so the
		   extra width it used to need goes back to the left column — which keeps
		   more street lines on one line, saving vertical space.
		   minmax(0,…) lets each track shrink below its content instead of overflowing. */
		grid-template-columns: minmax( 0, 1fr ) minmax( 0, 1fr );
		column-gap: 0.5rem;
	}
}

.dpk-address,
.dpk-extended-care,
.dpk-phone,
.dpk-seat-line {
	display: flex;
	align-items: flex-start;
	/* No margin: the groups' `gap` owns the spacing between rows
	   (--dpk-gap-info-list, 0.4rem — designer, 2026-07-27). Keeping it as gap rather
	   than a trailing margin is what lets `.dpk-actions` below own the space under
	   the block, with no last-row exception to maintain. */
	margin: 0;
	font-size: var( --dpk-fs-site-info );
	/* Medium, not Regular (Jennifer, 2026-07-30) — a real face in the brand kit, so
	   this is a visible step and not a request that collapses back onto 400. The
	   `.dpk-popup-toggle` buttons wrapped around two of these lines carry
	   `font: inherit`, so they follow without a rule of their own. */
	font-weight: var( --dpk-fw-medium );
	line-height: 1.25;
}

/* Address stacks the street on line 1 and "City, State Zip" on line 2; the pin
   icon aligns to the first line (same pattern as the other icon rows). */
.dpk-address-lines {
	display: flex;
	flex-direction: column;
	min-width: 0;
}

.dpk-address-line {
	display: block;
}

/* ---------------------------------------------- Card popup (JS enhancement) */

/* JS wraps a card line — the street, or the extended-care options — in this
   button, which opens the shared popup on that line's detail (the full address,
   or the hours). The line keeps the content's size, color and weight, and carries
   the same underline-at-rest treatment as the other card info links (designer
   call, 2026-07-30, superseding the underline-on-hover of 2026-07-24): underlined
   by default, and on hover the underline drops away and the text takes the accent.
   Keyboard users get the standard `:focus-visible` ring from the FOCUS section
   below. Sized to its text (not stretched by the flex row/column) so the click
   target and the focus ring hug the line itself. */
.dpk-popup-toggle {
	align-self: flex-start;
	max-width: 100%;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	font: inherit;
	color: inherit;
	text-align: left;
	text-decoration: underline;
	text-decoration-color: currentColor;
	text-underline-offset: 0.15em;
	cursor: pointer;
	transition: color var( --dpk-hover-ease ) ease, text-decoration-color var( --dpk-hover-ease ) ease;
}

/* Fading the underline's COLOUR, not switching the line off — see .dpk-phone a. */
.dpk-popup-toggle:hover {
	color: var( --dpk-color-accent );
	text-decoration-color: transparent;
}

/* One popup per locator, reused by every card, parked at the end of the section
   so it inherits the `--dpk-*` tokens (dashboard overrides included). JS sets
   top/left; where the popover API exists the element is also promoted to the top
   layer, so the results scroller can never clip it.
   The `:not(.is-open)` rule is what hides it in BOTH paths, and it must be an
   AUTHOR rule: the UA's `[popover]:not(:popover-open){display:none}` loses to any
   author `display` declaration, and `hidden` is unusable here for the same reason
   in reverse (`.dpk-locator [hidden]{display:none !important}` would beat the
   popover's open state). */
.dpk-card-popup:not( .is-open ) {
	display: none;
}

.dpk-card-popup {
	position: fixed;
	z-index: 1000;
	width: max-content;
	max-width: min( 22rem, calc( 100vw - 1rem ) );
	margin: 0;
	padding: 0.85rem 2.25rem 0.85rem 1rem;
	border: 1px solid var( --dpk-color-divider );
	border-radius: var( --dpk-radius );
	background: #fff;
	box-shadow: 0 6px 20px rgba( 0, 0, 0, 0.18 );
	color: var( --dpk-color-text );
	font-size: var( --dpk-fs-site-info );
	line-height: 1.35;
}

/* The popup takes focus when it opens (it is a `role="dialog"`), so it needs a
   ring of its own — a plain <div> is not covered by the FOCUS section's
   a/button/input/select rule, and the UA default is a blue that belongs to no part
   of this palette. `:focus`, not `:focus-visible`: the focus here is always
   programmatic, and a mouse user needs to see where the popup put their focus.
   The offset is NEGATIVE by the width of the border, so the ring lands ON the
   popup's own 1px edge rather than floating outside it: the standard +2px offset
   leaves a white gap that reads as a second, detached box (Jennifer, 2026-07-24).
   Everything else keeps the standard offset — a ring hugging a line of text needs
   the breathing room; a ring on a bordered box does not.
   The leading `.dpk-locator` is load-bearing (same trap as the distance select):
   without it this TIES the FOCUS section's `.dpk-locator :focus{outline:none}` reset
   at 0-2-0 and loses on source order, and the dialog would open with no ring at all. */
.dpk-locator .dpk-card-popup:focus {
	outline: 1px solid currentColor;
	outline-offset: -1px;
}

.dpk-card-popup-address-text {
	display: flex;
	flex-direction: column;
	margin: 0;
}

/* Hours body: one labelled line per care type — Before Care / Regular Hours /
   After Care — which is how the original design laid them out on the card itself
   before D28 moved them in here. These three rules are that block's, restored. */
.dpk-hours-lines {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	min-width: 0;
}

.dpk-hours-line {
	margin: 0;
}

.dpk-hours-label {
	font-weight: var( --dpk-fw-demi );
}

.dpk-hours-label::after {
	content: ":";
}

.dpk-card-popup-close {
	position: absolute;
	top: 0.35rem;
	right: 0.35rem;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 28px;
	height: 28px;
	padding: 0;
	border: 0;
	background: none;
	color: var( --dpk-color-text );
	cursor: pointer;
}

.dpk-card-popup-close .dpk-icon {
	width: 11px;
	height: 11px;
}

/* Copy + Directions read as one row of action links, styled like .dpk-actions. */
.dpk-card-popup-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.9rem;
	margin-top: 0.75rem;
	font-size: var( --dpk-fs-small );
}

.dpk-card-popup-copy,
.dpk-card-popup-directions {
	display: inline-flex;
	align-items: center;
	gap: 0.3em;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	font: inherit;
	font-weight: var( --dpk-fw-bold );
	color: var( --dpk-color-accent );
	text-transform: uppercase;
	letter-spacing: 0.02em;
	text-decoration: none;
	cursor: pointer;
}

.dpk-card-popup-copy:hover,
.dpk-card-popup-directions:hover {
	text-decoration: underline;
}

.dpk-card-popup-directions .dpk-icon {
	width: 1em;
	height: 1em;
	opacity: 0.4;
}

/* Copy confirmation: an accent checkmark that appears after the button's label
   once the address is on the clipboard (designer call, 2026-07-24 — it confirms
   the copy without costing the popup a line of height). Full-strength accent, not
   the 0.4 fade the leading link icons carry: this one is the feedback, not
   decoration beside a label that already says it. It is still `aria-hidden`
   (Icons emits every icon that way) — the announcement is the sr-only status
   region below, which is what AT users get instead. */
.dpk-card-popup-check {
	width: 0.95em;
	height: 0.95em;
	color: var( --dpk-color-accent );
}

.dpk-card-popup-copy:not( .is-copied ) .dpk-card-popup-check {
	display: none;
}

/* Copy feedback for assistive tech (and, on failure, for everyone). Always
   rendered (an empty <p> is zero-height) — a live region has to be in the
   accessibility tree before its text changes to be announced, so this is never
   toggled with `hidden` or `display`; JS adds/removes `.dpk-sr-only` instead. */
.dpk-card-popup-status {
	margin: 0;
	font-size: var( --dpk-fs-small );
	color: var( --dpk-color-muted );
}

.dpk-card-popup-status:not( :empty ) {
	margin-top: 0.5rem;
}

/* Card info links read as the content they sit in — same size, weight and color
   — underlined at rest so they are identifiable without relying on color alone
   (1.4.1), and on hover the underline drops away and the text takes the accent
   (designer call, 2026-07-30), easing over --dpk-hover-ease.
   The underline is faded via `text-decoration-color: transparent` rather than
   removed with `text-decoration: none`, because `text-decoration-line` is a
   DISCRETE property — it would snap at the halfway point while the colour was
   still easing. As a colour, the underline can cross-fade with the text, and
   keeping the line in the box the whole time means nothing can reflow. */
.dpk-phone a {
	color: inherit;
	text-decoration: underline;
	text-decoration-color: currentColor;
	text-underline-offset: 0.15em;
	transition: color var( --dpk-hover-ease ) ease, text-decoration-color var( --dpk-hover-ease ) ease;
}

.dpk-phone a:hover {
	color: var( --dpk-color-accent );
	text-decoration-color: transparent;
}

/* Seat types are the one info row that is NOT interactive — no popup, no link —
   so they stay at Regular while the rows around them sit at Medium. The weight is
   the cue that there is nothing here to click (designer, 2026-07-30); it is not the
   ONLY cue, since the links also carry an underline the seat list doesn't. */
.dpk-seat-line {
	font-weight: var( --dpk-fw-default );
}

/* Seat types render as an inline, comma-separated list after the tag icon. */
.dpk-seat-types {
	display: inline;
	list-style: none;
	margin: 0;
	padding: 0;
	font-size: inherit;
}

.dpk-seat-types li {
	display: inline;
}

.dpk-seat-types li:not( :last-child )::after {
	content: ", ";
}

/* Action links (More Details | Directions | Visit the Website), 12px, accent,
   with divider pipes. On an active card the links take the primary color. */
.dpk-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	margin: var( --dpk-gap-before-actions ) 0 0;
	font-size: var( --dpk-fs-small );
}

.dpk-actions a {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: 0.3em;
	color: var( --dpk-color-accent );
	font-weight: var( --dpk-fw-bold );
	text-transform: uppercase;
	letter-spacing: 0.02em;
	/* `!important` on both this and the :hover below, matching force with force:
	   these links live inside a <p>, and the production theme ships
	   `p a { text-decoration: underline !important }` — which no amount of
	   specificity can beat without an important of our own. The firewall can't
	   help here either (importants win the cascade before specificity is even
	   consulted). `.dpk-links a` needs none of this: those sit in <li>. */
	text-decoration: none !important;
}

.dpk-actions a:hover {
	text-decoration: underline !important;
}

/* The "|" separator sits in the left margin as an absolutely-positioned pseudo,
   so it is NOT part of the link's own box and a focused link's outline no longer
   wraps the divider (it belongs to neither adjacent link). */
.dpk-actions a:not( :first-child ) {
	margin-left: 1.2em;
}

/* The rule itself is a DRAWN box, not a "|" glyph. The glyph ran 12.1px against
   9.1px caps and centred 1.2px below them (it spans the em box, which reserves
   descender space the all-caps labels never use) — and a font swap would resize
   it unpredictably. An empty box gives exact control of both length and position:
   cap-height tall, centred on the cap centre (the link box centre sits 0.06em
   lower, hence the extra nudge). It's also cleaner for assistive tech, since
   generated *text* content can be announced. */
.dpk-actions a:not( :first-child )::before {
	content: "";
	position: absolute;
	left: -0.65em;
	top: 50%;
	width: 1px;
	height: 0.76em;
	transform: translateY( calc( -50% - 0.06em ) );
	background: var( --dpk-color-divider );
}

.dpk-site--active .dpk-site-name,
.dpk-site--active .dpk-distance,
.dpk-site--active .dpk-actions a {
	color: var( --dpk-color-primary );
}

/* Associated links (e.g. "Virtual Tour"): styled like the action links — accent,
   bold, uppercase — and laid out the same way, as ONE wrapping row separated by
   drawn pipes (Jennifer, 2026-07-23). Two tours now read as siblings on a line
   rather than as a stack; the group still begins on its own line below
   .dpk-actions, since it is a separate block-level <ul>. A tour link carries a
   play icon (added in the markup) to signal a video; other links match but are
   iconless. `row-gap` only shows once the row wraps. */
.dpk-links {
	list-style: none;
	margin: var( --dpk-gap-before-links ) 0 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	row-gap: 0.4rem;
	font-size: var( --dpk-fs-small );
}

/* Separator mechanics copied from .dpk-actions, with one improvement available
   here: the <li> (not the <a>) carries the pseudo, so the divider is outside the
   focusable box by construction and a focused link's outline can never wrap it. */
.dpk-links li {
	position: relative;
}

.dpk-links li:not( :first-child ) {
	margin-left: 1.2em;
}

.dpk-links li:not( :first-child )::before {
	content: "";
	position: absolute;
	left: -0.65em;
	top: 50%;
	width: 1px;
	height: 0.76em;
	transform: translateY( calc( -50% - 0.06em ) );
	background: var( --dpk-color-divider );
}

.dpk-links a {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
	color: var( --dpk-color-accent );
	font-weight: var( --dpk-fw-bold );
	text-transform: uppercase;
	letter-spacing: 0.02em;
	text-decoration: none;
}

.dpk-links a:hover {
	text-decoration: underline;
}

/* On an active card the links take the primary color (matches .dpk-actions). */
.dpk-site--active .dpk-links a {
	color: var( --dpk-color-primary );
}

.dpk-no-results {
	color: var( --dpk-color-muted );
	font-size: var( --dpk-fs-site-info );
}

/* ======================================================================= ICONS */

/* Decorative inline SVGs (Frontend\Icons). Size with their adjacent text and
   inherit its color by default (fill: currentColor). */
.dpk-icon {
	width: 1em;
	height: 1em;
	fill: currentColor;
	flex-shrink: 0;
	vertical-align: -0.125em;
}

/* Site-info content icons take the muted divider color. The rows align to
   flex-start (so a multi-line address or seat list keeps the icon by the first
   line); this top margin drops the icon to sit centered against that first text
   line rather than riding above it. */
.dpk-address .dpk-icon,
.dpk-phone .dpk-icon,
.dpk-extended-care .dpk-icon,
.dpk-seat-line .dpk-icon {
	fill: var( --dpk-color-divider );
	margin-right: 0.5em;
	margin-top: 0.2em;
}

/* Leading link icons (earth-americas / directions / circle-play).
   Designer call, 2026-07-23, SUPERSEDING the measured cap-height alignment shipped
   in 7f07405 (0.8em @ -0.1em): back to a full 1em on the flex centre with no nudge,
   plus 40% opacity so the icon reads lighter than its label — the same
   light-icon/dark-text pattern as the site-info icons above. Optically the larger
   glyph is carried by the fade rather than by being pulled onto the caps.
   The fade is safe for contrast: these icons are decorative (aria-hidden) and every
   one of them sits beside a text label that carries the meaning, so WCAG 1.4.11
   does not apply to them. */
.dpk-actions a .dpk-icon,
.dpk-links a .dpk-icon {
	width: 1em;
	height: 1em;
	transform: translateY( 0 );
	opacity: 0.4;
}

/* ===================================================================== UTILITY */

/* Visually hidden but available to assistive tech (labels, button names). */
.dpk-sr-only {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect( 0, 0, 0, 0 );
	white-space: nowrap;
	border: 0;
}

/* ==================================================================== LIST VIEW */

/* The results-header switch sets `data-dpk-view-style` on the section; "map" is the
   default two-panel layout above and needs no rules. "list" drops the map and
   re-flows the same markup wide: the Filter block moves BESIDE the search instead of
   under it, and the cards run in columns.
   Wide-container-only, because the switch itself is (in narrow containers the mobile List/Map switch
   owns this choice) — so every rule here sits inside the breakpoint.
   Several of these override rules that carry `.is-enhanced.has-map`; the selectors
   below repeat those classes to outrank them rather than tie and lose on source
   order (the specificity trap noted in CLAUDE.md). */
@container dpk-locator ( width >= 750px ) {

	/* Out of the two-panel grid: one full-width column. */
	.dpk-locator.is-enhanced.has-map[data-dpk-view-style="list"] {
		display: block;
	}

	.dpk-locator.is-enhanced.has-map[data-dpk-view-style="list"] .dpk-map {
		display: none;
	}

	/* The sidebar is now the whole widget. It KEEPS the height cap it gets above,
	   so the cards still scroll inside the widget rather than running the page
	   long — the comp shows that inner scrollbar. */

	/* Search left, Filter right — the panel's own stacking axis is all that changes.
	   `wrap` is the release valve for the narrow end of the desktop range: once the
	   address field has shrunk to its floor and the filters still don't fit, the two
	   SECTIONS break onto separate rows (search above filters, as in map view) rather
	   than the panel overflowing the widget. The filter groups themselves stay on one
	   line throughout — that is the arrangement worth protecting. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-panel {
		flex-direction: row;
		flex-wrap: wrap;
		align-items: flex-start;
		/* Doubled gap on the HORIZONTAL axis only — that is the one separating two
		   side-by-side sections. Once wrapped they stack, and the vertical distance
		   wants the stacked panel's own rhythm instead: --dpk-gap here plus the 16px
		   .dpk-panel-find already carries below itself comes to the same 32px map
		   view uses between the search field and "Filter". The `gap` shorthand set
		   both, which made that 48px (Jennifer, 2026-07-24). */
		column-gap: calc( var( --dpk-gap ) * 2 );
		row-gap: var( --dpk-gap );
	}

	/* When the row gets tight, the ADDRESS FIELD gives up width — not the filters
	   (Jennifer, 2026-07-24). Stacking the filter groups costs a whole row of panel
	   height and reads as a broken layout, whereas the address field just gets
	   shorter and stays perfectly usable; `#dpk-address` is already `flex: 1 1 auto;
	   min-width: 0` inside its row, so the squeeze lands on the input rather than on
	   the distance dropdown or the submit button.
	   Find is therefore the flexible one, capped so it never grows beyond the width it
	   has as a sidebar. The floor is where "Enter Address or ZIP Code" starts to clip:
	   below 370px the placeholder truncates, so that is where the panel wraps instead.
	   370 is MEASURED, not derived — rendering the string into a probe span and adding
	   the padding predicts 350, which is ~20px short of where the input actually
	   clips. Re-measure by setting the placeholder as the input's value and comparing
	   scrollWidth to clientWidth; trust that over any text-width arithmetic. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-panel-find {
		flex: 1 1 auto;
		min-width: 370px;
		max-width: var( --dpk-sidebar-width );
	}

	/* `min-width: max-content` is what actually protects the filters: as a flex item
	   its automatic minimum would otherwise let it be squeezed below its content, and
	   the groups inside would wrap. It still grows into spare space so Reset stays
	   pinned to the far right. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-panel-filter {
		flex: 1 1 auto;
		min-width: max-content;
	}

	/* The word "Filter" comes off the panel (designer, 2026-07-27): laid out as a
	   row, each group already announces itself with its own legend ("Seat Type",
	   "Extended Care"), so the section heading was labelling the obvious and costing
	   a line.
	   VISUALLY only — the sr-only pattern, not `display: none`. The <h3> is a
	   structural landmark: screen-reader users navigate this panel by heading, and
	   removing it from the a11y tree would leave the filter controls with no heading
	   between "Find PreK" and "Search Results". Map view keeps it visible; there it
	   is also the disclosure button's label (D35). */
	.dpk-locator[data-dpk-view-style="list"] .dpk-panel-filter .dpk-panel-heading {
		position: absolute;
		width: 1px;
		height: 1px;
		padding: 0;
		margin: -1px;
		overflow: hidden;
		clip: rect( 0, 0, 0, 0 );
		white-space: nowrap;
		border: 0;
	}

	/* Filter groups in a row, Reset trailing at the far end. `nowrap` is the point:
	   these must stay on one line and let the search shrink instead.
	   The gutter matches the one between the search panel and the filter panel
	   (designer, 2026-07-27) so "Seat Type" and "Extended Care" read as two distinct
	   groups rather than one field of checkboxes — the same separation, doing the
	   same job one level down. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-filters {
		display: flex;
		flex-wrap: nowrap;
		align-items: flex-start;
		column-gap: calc( var( --dpk-gap ) * 2 );
	}

	/* Keep each option on one line — a wrapped "Durham Head Start" would defeat the
	   point of protecting the filter block's width. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-panel .dpk-checkbox {
		white-space: nowrap;
	}

	/* Clear the stacked layout's explicit grid placements — they are meaningless in
	   a flex row and would otherwise sit here as dead declarations. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-filter-seat-types,
	.dpk-locator[data-dpk-view-style="list"] .dpk-filter-care,
	.dpk-locator[data-dpk-view-style="list"] .dpk-reset {
		grid-column: auto;
		grid-row: auto;
	}

	/* Seat Type's four options in two columns, as the comp shows, so the row stays
	   two checkboxes tall. The legend spans both so it still reads as the group's
	   heading. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-filter-seat-types {
		display: grid;
		grid-template-columns: repeat( 2, auto );
		column-gap: var( --dpk-gap );
	}

	.dpk-locator[data-dpk-view-style="list"] .dpk-filter-seat-types legend {
		grid-column: 1 / -1;
	}

	/* Push Reset to the end of the row and drop it to the baseline of the tallest
	   group, where the comp puts it. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-reset {
		margin-left: auto;
		align-self: flex-end;
	}

	/* ONE header band instead of two stacked lines: "Search Results", the status
	   ("Showing 49 sites.") and the view switch share a row (designer, 2026-07-27).
	   The second line was costing the list ~30px of the height the widget cap
	   (D34) has to ration.

	   The status is a sibling AFTER .dpk-results-header in the DOM and stays there:
	   it is an aria-live region, and re-parenting a live region on every view switch
	   risks a spurious re-announcement of text the user did not just change. So the
	   SECTION becomes the grid and the header wrapper goes `display: contents` —
	   its two children join that grid beside the status with no DOM change at all.
	   Safe on this element specifically: it is a plain div with no role. (Browsers
	   historically dropped display:contents elements that DID carry semantics — a
	   list, a table, a button — out of the a11y tree.)

	   Two rows: the band, then the scroller. The `1fr` row plus the scroller's own
	   `min-height: 0` reproduce exactly what `flex: 1 1 auto` gave it under the
	   column flex above, so the height cap still lands on the LIST rather than
	   growing the widget. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-results-section {
		display: grid;
		grid-template-columns: auto 1fr auto;
		grid-template-rows: auto 1fr;
		column-gap: var( --dpk-gap );
		/* The band's depth below its content. EVERY cell in the row has to carry it,
		   because the row is only as deep as its tallest cell + that cell's own bottom
		   spacing — putting it on the text alone left the 40px switch (much taller than
		   ~25px of text) governing the row and sitting flush on the first card. */
		--dpk-band-pad-bottom: 15px;
	}

	/* The wrapper's box disappears — and its horizontal padding with it, so the
	   heading and the switch carry their own edge inset below. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-results-header {
		display: contents;
	}

	/* `align-self: baseline` on the two TEXT cells (not `align-items` on the grid):
	   they share a baseline so the 14px status sits on the 22px heading's, instead of
	   centering against its cap height. Set grid-wide it would also apply to the
	   scroller and the ::before below, which must stretch — a baseline-aligned empty
	   box collapses to the baseline and would paint the divider through the middle of
	   the band. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-results-heading {
		grid-area: 1 / 1;
		align-self: baseline;
		padding-left: var( --dpk-pad-results );
		/* Vertically centre the TEXT against the switch (Jennifer, 2026-07-27 — it read
		   as floating high). A baseline group in grid hugs the row's start, so both
		   labels sat at the top of a band whose height comes from the 40px switch.
		   This padding drags the whole group down: the heading has the larger baseline
		   offset, so it defines where the group's baseline sits, and the status follows
		   it exactly. MEASURED at 8px — the heading's cap-height centre then lands
		   0.08px off the switch's centre; re-measure if either font size changes.
		   Why not `align-self: center` on the two cells instead — it fails twice over:
		   the row's height includes the switch's 15px bottom margin, so centring in it
		   overshoots the switch's centre by 7.2px, and centring each cell separately
		   de-syncs the two baselines by 2.9px (22px and 14px text put their baselines
		   at different depths in an equally-centred box). */
		padding-top: 8px;
	}

	/* No longer its own full-bleed line: in the band the status is the middle cell,
	   so it drops the horizontal padding and the margins that spaced it vertically.
	   Its bottom padding is the band inset for the TEXT side of the row. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-status {
		grid-area: 1 / 2;
		align-self: baseline;
		margin: 0;
		padding: 0 0 var( --dpk-band-pad-bottom );
		box-shadow: none;
	}

	.dpk-locator[data-dpk-view-style="list"] .dpk-results-tools {
		grid-area: 1 / 3;
		/* Centered, not baseline: a box with no text of its own baseline-aligns on its
		   bottom margin edge, which would hang it below the row.
		   The inset goes on the MARGIN, not padding: the controls inside are bordered
		   (the switch's two cells share one hairline frame, the print link has its
		   own), so padding would grow those frames instead of the space under them. As
		   the tallest cell it is what the row measures, so this margin is what actually
		   sets the band's depth. */
		align-self: center;
		margin-right: var( --dpk-pad-results );
		margin-bottom: var( --dpk-band-pad-bottom );
	}

	/* The shadow dividing the fixed chrome from the scrolling list. It lived on
	   .dpk-status while that was a full-width line; as one auto-width cell its shadow
	   would now stop where the text does, so a pseudo-element spanning the band paints
	   the same falloff across the full width. `z-index` for the reason the status
	   needed it too: .dpk-results-scroll is positioned, so a static box's shadow would
	   paint under the list and disappear. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-results-section::before {
		content: "";
		grid-area: 1 / 1 / 2 / -1;
		position: relative;
		z-index: 1;
		box-shadow: 0 6px 10px var( --dpk-color-scroll-track );
		pointer-events: none;
	}

	.dpk-locator[data-dpk-view-style="list"] .dpk-results-scroll {
		grid-area: 2 / 1 / 3 / -1;
	}

	/* The cards themselves are untouched — only the track they sit in changes, and
	   the widget keeps the width and height cap it has in map view.
	   auto-fill + a 400px floor lets the column count follow whatever width the
	   theme gives the widget rather than any one page's measurements: two columns
	   until a third fits without squeezing a card below 400px.
	   The card padding alone left the rows and columns reading as one crowded block,
	   so both gaps are set explicitly on top of it. The floor counts the card's own
	   padding (400 = ~360 of content + 2×20), so it stays a floor on CONTENT width as
	   the gutter changes. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-results {
		display: grid;
		grid-template-columns: repeat( auto-fill, minmax( 400px, 1fr ) );
		column-gap: var( --dpk-gap-list-columns );
		row-gap: var( --dpk-gap-list-rows );
		/* Stretch (the grid default) so every card in a row matches the tallest one:
		   with a shadow on each card, ragged heights read as broken rather than
		   organic. The card distributes that height internally — see below. */
		align-items: stretch;
		/* Room for the card shadow to land, on all four sides because the shadow is
		   unoffset (designer, 2026-07-27) — the scroll container clips it (setting
		   overflow-y forces overflow-x to `auto` too), so without this the outermost
		   cards would have their shadows sheared off while every interior card kept
		   one. 8px covered the reach of the blur; 20px matches the column and row
		   gaps so the frame around the grid is the same distance as the gutters
		   between the cards (Jennifer, 2026-07-29), and it now lines the cards up
		   with the results header's own 20px text inset instead of sitting 12px
		   inside it. */
		padding: 20px;
	}

	/* Give each card a soft edge so the grid reads as discrete cards rather than one
	   field of text. Shadow only: no border (too hard a line for "set them off a
	   little") and no background, since the card already sits on the panel's white.
	   Unoffset and evenly spread on all four sides (designer, 2026-07-27) — the card
	   reads as sitting in its own halo rather than lit from one corner, which is why
	   the grid's padding above is symmetric now too. The color is a step deeper than
	   the tint the down-and-right version used: spread over four edges instead of
	   pooled on two, that lighter track tint went nearly invisible.
	   Map view keeps its flat cards — in the narrow sidebar they stack directly against
	   each other, where per-card shadows would read as banding. */
	.dpk-locator[data-dpk-view-style="list"] .dpk-results .dpk-site {
		box-shadow: 0 0 8px var( --dpk-color-card-shadow );
		/* Take the height the row stretched us to and spend it in the MIDDLE, so the
		   action links land on the card's bottom edge and line up across the row
		   instead of floating at whatever height the address block happened to end.
		   Header and actions keep their natural size; only the info block grows. */
		display: flex;
		flex-direction: column;
	}

	.dpk-locator[data-dpk-view-style="list"] .dpk-results .dpk-site-info {
		flex: 1 1 auto;
		/* The info block is itself a grid. Left to stretch, its single row would
		   absorb the extra height and pull the address and seat-type lines apart;
		   packing to the start keeps the slack as empty space above the actions. */
		align-content: start;
	}

	/* With no map on screen, the card's click-to-locate affordance leads nowhere.
	   The click handler bails out in list view too (locator-map.js) — this only stops
	   the pointer from advertising it. */
	.dpk-locator.has-map[data-dpk-view-style="list"] .dpk-results .dpk-site {
		cursor: auto;
	}
}

/* ============================================================= FOCUS / MOTION */

/* Take focus styling away from the THEME first. Twenty Twenty-Five (and other
   block themes built on the same global-styles output) ships
   `:where(.wp-site-blocks :focus){outline-width:2px;outline-style:solid}` — note
   `:focus`, not `:focus-visible`, and no color, so it inherits `currentColor`.
   The effect inside the locator was that *clicking* any control boxed it in a 2px
   ring — accent orange on the popup's Copy/Directions, blue on a site name — which
   is not what a mouse user should get (Jennifer, 2026-07-24). `:where()` has zero
   specificity, so this plain class rule beats it, and the `:focus-visible` rule
   below (higher specificity) still owns keyboard focus.
   Gated on `@supports selector( :focus-visible )` so an engine without it keeps
   the theme's ring rather than losing focus indication altogether — this must never
   leave a control with no visible focus (WCAG 2.4.7). */
@supports selector( :focus-visible ) {
	.dpk-locator :focus {
		outline: none;
	}
}

/* A hairline ring in the control's OWN text color (Jennifer, 2026-07-24), replacing
   the 2px accent one. `currentColor` means it recolors itself per context — orange
   on an accent link, white on the blue panel, dark on body text — so it always has
   the same contrast against its background that the text it rings does. That keeps
   1.4.11 (≥3:1) satisfied wherever the palette is, which a single fixed color could
   not promise on both the white list and the blue panel.
   NOTE: 1px meets WCAG 2.1 AA (2.4.7 asks for a visible indicator, not a size), which
   is what this project targets. WCAG 2.2's 2.4.11 Focus Appearance — AA in 2.2 — asks
   for the area of a 2px perimeter, which a 1px ring is exactly half of. Revisit this
   line if the target ever moves to 2.2. */
.dpk-locator a:focus-visible,
.dpk-locator button:focus-visible,
.dpk-locator input:focus-visible,
.dpk-locator select:focus-visible {
	outline: 1px solid currentColor;
	outline-offset: 2px;
}

/* The view-style buttons still need the ring drawn INSIDE. The general rule offsets
   2px outward, which on these lands in the white results header — and the selected
   cell's currentColor is white, so the ring would be white-on-white and invisible
   (WCAG 2.4.7 / 1.4.11). Inset, it sits on the cell's own fill instead: white on the
   filled cell, orange on the white one. The leading `.dpk-locator` is REQUIRED, not tidiness:
   without it this TIES `.dpk-locator button:focus-visible` (0-2-0) and loses on source
   order. -4px keeps the ring clear of the 1em icon. */
.dpk-locator .dpk-view-style-btn:focus-visible,
.dpk-locator .dpk-print-link:focus-visible {
	outline: 1px solid currentColor;
	outline-offset: -4px;
}

/* The results heading is ONLY ever a programmatic focus target (tabindex=-1): a
   search moves focus here so screen-reader users land on the fresh results, but it
   must never show a visible focus ring (a submit shouldn't visibly outline the
   heading). It's not in the tab order, so suppressing the ring costs no keyboard
   affordance. */
.dpk-results-heading:focus {
	outline: none;
}

@media ( prefers-reduced-motion: reduce ) {
	.dpk-locator * {
		scroll-behavior: auto !important;
		transition: none !important;
		animation: none !important;
	}
}

/* ================================================================== RESPONSIVE */

/* Mobile: single column, larger interior padding, filters stack. */
@container dpk-locator ( width < 750px ) {
	.dpk-locator {
		--dpk-pad-panel: 30px;
		--dpk-pad-results: 30px;
	}

	.dpk-filters {
		grid-template-columns: 1fr;
	}

	.dpk-filter-care,
	.dpk-filter-seat-types,
	.dpk-reset {
		grid-column: 1;
		grid-row: auto;
	}

	/* Back to a normal in-flow link at the foot of the stacked filters. */
	.dpk-reset {
		justify-self: start;
		align-self: start;
	}

	/* The List/Map switch is a mobile-only affordance. */
	.dpk-view-switch {
		display: flex;
	}

	/* …and the header's controls are the desktop-only counterpart: the two switches
	   would otherwise stack here offering the same choice twice (Jennifer,
	   2026-07-24). `display: none` also takes them out of the a11y tree, so no
	   phantom buttons remain in the tab order.
	   The print link goes with them (D38) — it was asked for as a desktop control,
	   and the printable view stays reachable at `?dpk_print=1` regardless. */
	.dpk-results-tools {
		display: none;
	}
}
