/**
 * Hatchline front end.
 *
 * Direction and tokens come from DESIGN.md. Every visual decision is a custom
 * property so an implementer can restyle without touching this file.
 *
 * Two layers: a base layer that must work with no JavaScript, and rules scoped
 * to .is-hatchline-enhanced that only apply once the script has initialised.
 * If the script never runs, or throws, the base layer is what the visitor gets.
 */

.hatchline-root {
	/* Surface */
	--hatchline-paper: #F7F8F7;
	/* The input's own surface, so a field reads as a field against the panel
	   behind it rather than blending into it. */
	--hatchline-field: #FFFFFF;
	--hatchline-ink: #16202A;
	--hatchline-ink-soft: #5A6B7A;
	--hatchline-rule: #C9D2D8;

	/* Interaction */
	--hatchline-focus: #16202A;
	--hatchline-hover-lift: rgba(22, 32, 42, .08);

	/* Type */
	--hatchline-font-body: inherit;
	--hatchline-font-data: inherit;

	/* Geometry */
	--hatchline-radius: 2px;
	--hatchline-hairline: 1px;
	--hatchline-space: 8px;

	box-sizing: border-box;
	color: var(--hatchline-ink);
	font-family: var(--hatchline-font-body);
	position: relative;
}

.hatchline-root *,
.hatchline-root *::before,
.hatchline-root *::after {
	box-sizing: inherit;
}

/* ---------- Finder (search + count) ---------- */

/* The field and the count it drives are one block. They used to be siblings of
   everything else, which in the side-by-side layout stranded the count above
   the map, nowhere near the control that changes it. */
.hatchline-finder {
	border-bottom: var(--hatchline-hairline) solid var(--hatchline-rule);
	margin-bottom: calc(var(--hatchline-space) * 2);
	padding-bottom: calc(var(--hatchline-space) * 2);
}

/* Root-qualified and forced, like the other controls in this file. A host
   theme that styles bare `form` elements leaks its own inset into this one,
   and the field then sits a few pixels right of the count and the rows beneath
   it -- close enough to read as a mistake rather than a choice. A plain
   `.hatchline-search { padding: 0 }` was not enough to win against it in
   testing, which is the same reason the input and buttons here carry
   !important: isolating an embedded widget's own chrome from a theme's
   element-level rules, not a style-fight shortcut. */
.hatchline-root .hatchline-search {
	/* Transparent too: the same themes paint bare forms white, which drew a
	   white band behind the label and hint and left the field itself looking
	   like the odd one out against it. */
	background: transparent !important;
	border: 0 !important;
	display: grid;
	gap: calc(var(--hatchline-space) * 0.75);
	margin: 0 !important;
	padding: 0 !important;
}

.hatchline-search__label {
	color: var(--hatchline-ink-soft);
	font-family: var(--hatchline-font-data);
	font-size: .75rem;
	letter-spacing: .08em;
	text-transform: uppercase;
}

/* The icon and the clear button live inside the field's box, so the whole
   thing reads as one control rather than an input with decorations beside it. */
.hatchline-search__field {
	align-items: center;
	display: flex;
	gap: calc(var(--hatchline-space) * 0.75);
	background: var(--hatchline-field, #fff);
	border: var(--hatchline-hairline) solid var(--hatchline-rule);
	border-radius: var(--hatchline-radius);
	padding: 0 calc(var(--hatchline-space) * 1.5);
	transition: border-color 120ms ease, box-shadow 120ms ease;
}

/* Focus lands on the input, but the ring belongs on the field: a ring drawn
   around the input alone sits inside the border and reads as a mistake. */
.hatchline-search__field:focus-within {
	border-color: var(--hatchline-focus);
	box-shadow: 0 0 0 3px var(--hatchline-focus-soft, rgba(0, 0, 0, .08));
}

.hatchline-search__icon {
	color: var(--hatchline-ink-soft);
	flex: none;
	height: 1.125rem;
	width: 1.125rem;
}

/* .hatchline-root-qualified throughout this file's interactive controls, and
   background/color carry !important: found on Twenty Twenty-One, whose own
   button reset is `button:not(:hover):not(:active):not(.has-background)`
   -- three chained :not() pseudo-classes each contribute class-level
   specificity, for three classes plus the `button` type, comfortably
   outranking any reasonable ancestor-class chain of ours. !important is the
   correct tool for isolating a self-contained embedded widget's own chrome
   from a host theme's element-level resets, not a style-fight shortcut. */
.hatchline-root .hatchline-search__input {
	background: transparent !important;
	border: 0 !important;
	border-radius: 0;
	color: var(--hatchline-ink) !important;
	flex: 1 1 auto;
	font-family: var(--hatchline-font-body);
	/* Never below 16px: smaller triggers zoom-on-focus in iOS Safari. */
	font-size: 1rem;
	min-width: 0;
	padding: calc(var(--hatchline-space) * 1.25) 0;
	width: 100%;
}

.hatchline-root .hatchline-search__input:focus,
.hatchline-root .hatchline-search__input:focus-visible {
	/* The field carries the ring; the input inside it must not draw a second. */
	box-shadow: none !important;
	outline: none !important;
}

/* The type="search" clear affordance is inconsistent between browsers and
   cannot be styled, so the component ships its own. */
.hatchline-root .hatchline-search__input::-webkit-search-cancel-button {
	-webkit-appearance: none;
	appearance: none;
}

.hatchline-root .hatchline-search__clear {
	align-items: center;
	background: transparent !important;
	border: 0;
	border-radius: 50%;
	color: var(--hatchline-ink-soft) !important;
	cursor: pointer;
	display: flex;
	flex: none;
	height: 1.5rem;
	justify-content: center;
	padding: 0;
	width: 1.5rem;
}

.hatchline-root .hatchline-search__clear:hover {
	background: var(--hatchline-hover-lift) !important;
	color: var(--hatchline-ink) !important;
}

.hatchline-search__clear svg {
	height: 1rem;
	width: 1rem;
}

.hatchline-search__clear[hidden] {
	display: none;
}

.hatchline-search__hint {
	color: var(--hatchline-ink-soft);
	font-size: .875rem;
	margin: 0;
}

.hatchline-root .hatchline-search__submit {
	background: var(--hatchline-ink) !important;
	border: 0;
	border-radius: var(--hatchline-radius);
	color: var(--hatchline-paper) !important;
	cursor: pointer;
	font-family: var(--hatchline-font-data);
	font-size: .75rem;
	justify-self: start;
	letter-spacing: .08em;
	padding: var(--hatchline-space) calc(var(--hatchline-space) * 2);
	text-transform: uppercase;
}

/* The script can filter live, so the submit control becomes redundant. It is
   hidden only once the script has actually initialised, never by default. */
.is-hatchline-enhanced .hatchline-search__submit {
	display: none;
}

/* Visible to a screen reader, not on screen. Themes usually define this, but
   the component cannot depend on one that does. */
.hatchline-root .screen-reader-text {
	border: 0;
	clip-path: inset(50%);
	height: 1px;
	overflow: hidden;
	position: absolute;
	white-space: nowrap;
	width: 1px;
}

/* ---------- Count ---------- */

.hatchline-count {
	color: var(--hatchline-ink-soft);
	font-family: var(--hatchline-font-data);
	font-size: .8125rem;
	margin: calc(var(--hatchline-space) * 1.5) 0 0;
}

/* ---------- List ---------- */

.hatchline-list {
	list-style: none;
	margin: 0;
	padding: 0;
	/* Containing block for the desktop detail panel. Without this the panel
	   resolves against .hatchline-root and covers the search form and count
	   line too, rather than overlaying just the list rail. */
	position: relative;
}

.hatchline-row {
	border-bottom: var(--hatchline-hairline) solid var(--hatchline-rule);
}

.hatchline-row:last-child {
	border-bottom: 0;
}

.hatchline-row.is-hatchline-filtered {
	display: none;
}

.hatchline-row__disclosure {
	margin: 0;
}

/* Two children: the text block, and the button. The button centres against
   however many lines the text runs to, which is what makes one rule align it
   correctly in the narrow list and the wide one alike. */
.hatchline-row__trigger {
	align-items: center;
	cursor: pointer;
	display: flex;
	gap: calc(var(--hatchline-space) * 2);
	justify-content: space-between;
	list-style: none;
	/* Matches the finder's own inset, so the field, the count and every row
	   share one left edge down the panel. */
	padding: calc(var(--hatchline-space) * 1.75) calc(var(--hatchline-space) * 2);
	transition: background-color 120ms ease;
}

.hatchline-row__trigger::-webkit-details-marker {
	display: none;
}

.hatchline-row__trigger:hover {
	background-color: var(--hatchline-hover-lift);
}

.hatchline-row__trigger:focus-visible {
	outline: 2px solid var(--hatchline-focus);
	outline-offset: -2px;
}

/* min-width:0 lets a flex item shrink below its content width; without it a
   long market name refuses to wrap and forces the row wider. */
.hatchline-row__body {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	gap: calc(var(--hatchline-space) / 2);
	min-width: 0;
}

.hatchline-row__name {
	font-size: 1.0625rem;
	font-weight: 600;
	line-height: 1.3;
	overflow-wrap: anywhere;
}

.hatchline-row__meta {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: calc(var(--hatchline-space) * 0.75);
	min-width: 0;
}

.hatchline-row__status {
	align-items: center;
	color: var(--hatchline-ink-soft);
	display: inline-flex;
	font-family: var(--hatchline-font-data);
	font-size: .75rem;
	gap: calc(var(--hatchline-space) / 2);
	letter-spacing: .06em;
	text-transform: uppercase;
}

.hatchline-row__region {
	align-items: center;
	color: var(--hatchline-ink-soft);
	display: inline-flex;
	font-size: .8125rem;
	min-width: 0;
	opacity: .8;
}

/* Separates status from region without putting a character into either one's
   accessible name, where it would be announced as punctuation. */
.hatchline-row__region::before {
	background: currentColor;
	border-radius: 50%;
	content: "";
	display: inline-block;
	flex: none;
	height: 3px;
	margin-inline-end: calc(var(--hatchline-space) / 2);
	opacity: .6;
	width: 3px;
}

.hatchline-row__action {
	flex: none;
}

.hatchline-row--featured .hatchline-row__name::after {
	color: var(--hatchline-ink-soft);
	content: "\2605";
	font-size: .75rem;
	margin-left: calc(var(--hatchline-space) / 2);
}

/* ---------- Swatches ---------- */

.hatchline-swatch {
	background-color: var(--hatchline-swatch-color, var(--hatchline-rule));
	border: var(--hatchline-hairline) solid var(--hatchline-rule);
	border-radius: var(--hatchline-radius);
	display: inline-block;
	flex: 0 0 auto;
	height: 16px;
	vertical-align: middle;
	width: 16px;
}

.hatchline-swatch--hatched {
	background-color: transparent;
	background-image: repeating-linear-gradient(
		45deg,
		var(--hatchline-swatch-color) 0,
		var(--hatchline-swatch-color) 2px,
		transparent 2px,
		transparent 4px
	);
}

.hatchline-swatch--dotted {
	background-color: transparent;
	background-image: radial-gradient(var(--hatchline-swatch-color) 1px, transparent 1.5px);
	background-size: 4px 4px;
}

/* Filled like every other swatch. The "blank" style once meant "painted in the
   surface colour", which on a map means invisible -- a status nobody can see is
   not a status. The map now paints it in its own colour like any other, so the
   key does too; a key that shows an empty box beside a filled shape is a key
   for a different map. */
.hatchline-swatch--blank {
	background-color: var(--hatchline-swatch-color, var(--hatchline-rule));
}

/* ---------- Detail ---------- */

.hatchline-detail {
	background: var(--hatchline-paper);
	border-top: var(--hatchline-hairline) solid var(--hatchline-rule);
	padding: calc(var(--hatchline-space) * 2) var(--hatchline-space);
}

.hatchline-root .hatchline-detail__close {
	background: transparent !important;
	border: var(--hatchline-hairline) solid var(--hatchline-rule);
	border-radius: var(--hatchline-radius);
	color: var(--hatchline-ink-soft) !important;
	cursor: pointer;
	display: none;
	font-family: var(--hatchline-font-data);
	font-size: .75rem;
	letter-spacing: .08em;
	padding: calc(var(--hatchline-space) / 2) var(--hatchline-space);
	position: absolute;
	right: var(--hatchline-space);
	text-transform: uppercase;
	top: var(--hatchline-space);
}

/* Only meaningful once the detail is a panel. Without the script the detail is
   inline and closing it is what the summary already does. */
.is-hatchline-enhanced .hatchline-detail__close {
	display: block;
}

.hatchline-detail__close:focus-visible,
.hatchline-cta:focus-visible,
.hatchline-search__input:focus-visible,
.hatchline-search__submit:focus-visible,
.hatchline-no-results__reset:focus-visible,
.hatchline-detail__title:focus-visible {
	outline: 2px solid var(--hatchline-focus);
	outline-offset: 2px;
}

.hatchline-detail__title {
	font-size: 1.25rem;
	margin: 0 0 calc(var(--hatchline-space) / 2);
}

.hatchline-detail__title:focus {
	outline: none;
}

.hatchline-detail__status {
	align-items: center;
	color: var(--hatchline-ink-soft);
	display: flex;
	font-family: var(--hatchline-font-data);
	font-size: .75rem;
	gap: calc(var(--hatchline-space) / 2);
	letter-spacing: .08em;
	margin: 0 0 var(--hatchline-space);
	text-transform: uppercase;
}

.hatchline-detail__body {
	color: var(--hatchline-ink-soft);
	margin-bottom: calc(var(--hatchline-space) * 2);
}

.hatchline-detail__body > :first-child {
	margin-top: 0;
}

.hatchline-detail__body > :last-child {
	margin-bottom: 0;
}

/* ---------- CTA ---------- */

/* No hardcoded border/accent color, deliberately. --hatchline-cta-color is
   set at runtime by hatchline-frontend.js, which reads the computed color of
   a plain <a> planted in document.body -- the host theme's own brand/link
   color, on whatever theme this is, without the plugin knowing or guessing
   it. A page-builder container can reset link color for its own descendants
   (confirmed on a real install: a bare <a> placed inside such a container
   picked up the browser's default blue instead of the theme's brand color),
   so the probe deliberately lives at the body level, not inside the plugin's
   own DOM subtree. Without JS the var is unset and this falls back to
   --hatchline-ink-soft.
   Label text stays on --hatchline-ink rather than riding the same accent
   color: a detected brand color is frequently light/pastel (confirmed on a
   real install -- a soft blue-grey), and text in that color on a light
   button reads under the 4.5:1 contrast floor this project holds everywhere
   else. The accent shows up as the border at rest and as a filled
   background on hover/focus, which is where a bright or pale brand color
   reads as intentional rather than as illegible label text. */
.hatchline-root .hatchline-cta {
	background: transparent;
	border: 1.5px solid var(--hatchline-cta-color, var(--hatchline-ink-soft));
	border-radius: var(--hatchline-radius);
	color: var(--hatchline-ink);
	display: inline-block;
	font-family: var(--hatchline-font-data);
	font-size: .8125rem;
	letter-spacing: .08em;
	padding: calc(var(--hatchline-space) * 1.5) calc(var(--hatchline-space) * 2);
	text-decoration: none;
	text-transform: uppercase;
	transition: background-color 120ms ease, color 120ms ease;
}

/* A tint, not a full invert: text stays on --hatchline-ink no matter how
   light or dark the detected accent turns out to be on a given theme, so
   contrast never depends on an unknown brand color's luminance. Browsers
   without color-mix() just skip the declaration and keep the transparent
   background from the base rule -- a plainer but still legible fallback. */
.hatchline-root .hatchline-cta:hover,
.hatchline-root .hatchline-cta:focus {
	background: color-mix( in srgb, var(--hatchline-cta-color, var(--hatchline-ink-soft)) 15%, var(--hatchline-paper) );
}

/* Compact variant: the same control inline in a row,
   so a visitor who already knows they want a market doesn't have to open
   the disclosure first. */
.hatchline-root .hatchline-cta--inline {
	flex-shrink: 0;
	font-size: .75rem;
	padding: calc(var(--hatchline-space) / 2) var(--hatchline-space);
}

/* ---------- Empty and no-results ---------- */

.hatchline-empty,
.hatchline-no-results {
	background: var(--hatchline-paper);
	border: var(--hatchline-hairline) solid var(--hatchline-rule);
	border-radius: var(--hatchline-radius);
	margin-bottom: var(--hatchline-space);
	padding: calc(var(--hatchline-space) * 2);
}

.hatchline-no-results[hidden] {
	display: none;
}

.hatchline-no-results__message {
	margin: 0 0 var(--hatchline-space);
}

.hatchline-no-results__reset {
	color: var(--hatchline-ink);
	display: inline-block;
	font-family: var(--hatchline-font-data);
	font-size: .8125rem;
	margin-right: var(--hatchline-space);
}

/* ---------- Enhanced panel, desktop ---------- */

@media (min-width: 48em) {
	.is-hatchline-enhanced .hatchline-row__disclosure[open] .hatchline-detail {
		border: var(--hatchline-hairline) solid var(--hatchline-rule);
		bottom: 0;
		left: 0;
		overflow-y: auto;
		position: absolute;
		right: 0;
		top: 0;
		z-index: 2;
	}
}

/* ---------- Enhanced panel, mobile sheet ---------- */

@media (max-width: 47.99em) {
	.is-hatchline-enhanced .hatchline-row__disclosure[open] .hatchline-detail {
		bottom: 0;
		left: 0;
		overflow-y: auto;
		padding-top: calc(var(--hatchline-space) * 5);
		position: fixed;
		right: 0;
		top: 0;
		z-index: 999;
	}
}

/* Not scoped to .hatchline-root: this applies to body while the sheet is open. */
body.hatchline-scroll-locked {
	overflow: hidden;
}

/* ---------- Motion ---------- */

/* The !important here is the one sanctioned exception to this file's no-!important
   rule: an accessibility override has to beat whatever the host theme sets. */
@media (prefers-reduced-motion: reduce) {
	.hatchline-root *,
	.hatchline-root *::before,
	.hatchline-root *::after {
		animation-duration: .01ms !important;
		animation-iteration-count: 1 !important;
		scroll-behavior: auto !important;
		transition-duration: .01ms !important;
	}
}

/* ==========================================================================
   Map
   ==========================================================================

   The map is an enhancement of the list, never a replacement. It ships hidden
   and only the script reveals it, so a visitor without JavaScript sees the
   list and no empty frame. Everything below therefore assumes the script ran.
   ========================================================================== */

.hatchline-map {
	margin-top: calc(var(--hatchline-space) * 3);
}

.hatchline-map[hidden] {
	display: none;
}

/* Town markers are pins: tip on the place, head above it. Fill comes from JS
   (each territory's own status colour); this supplies the outline that keeps a
   pin readable against a same-colour or busy state fill, and the hover and
   focus affordance.

   Nothing here changes the marker's size on hover. The circular markers this
   replaced set a fixed hover radius, which *shrank* every marker bigger than
   that radius out from under the pointer: hover ended, the marker sprang back
   to full size, the pointer was inside it again, and it flickered in a loop.
   The hit area is also its own constant-size shape, so hover cannot move the
   thing being hovered. */
.hatchline-town-marker {
	cursor: pointer;
}

.hatchline-town-marker:focus-visible {
	outline: none;
}

/* Scoped under .hatchline-map__svg on purpose. The region rule above is
   `.hatchline-map__svg path`, which is more specific than a lone class and so
   would repaint the pin's outline in the border grey at a third of its width.
   Two classes outrank one class plus one element. */
.hatchline-map__svg .hatchline-town-marker__pin {
	stroke: var(--hatchline-paper);
	/* The pin is scaled to the map's units; its outline should not be. */
	vector-effect: non-scaling-stroke;
	stroke-width: 1;
	pointer-events: none;
	transition: stroke-width 120ms ease;
}

.hatchline-map__svg .hatchline-town-marker__core {
	fill: var(--hatchline-paper);
	pointer-events: none;
}

/* Invisible, constant, and the only part that takes pointer events. */
.hatchline-map__svg .hatchline-town-marker__hit {
	fill: transparent;
	stroke: none;
}

.hatchline-map__svg .hatchline-town-marker:hover .hatchline-town-marker__pin,
.hatchline-map__svg .hatchline-town-marker:focus-visible .hatchline-town-marker__pin {
	stroke-width: 2.5;
}

@media (prefers-reduced-motion: reduce) {
	.hatchline-map__svg .hatchline-town-marker__pin { transition: none; }
}

.hatchline-root .hatchline-map__toggle {
	background: transparent !important;
	border: var(--hatchline-hairline) solid var(--hatchline-rule);
	border-radius: var(--hatchline-radius);
	color: var(--hatchline-ink) !important;
	cursor: pointer;
	font-family: var(--hatchline-font-data);
	font-size: .75rem;
	letter-spacing: .08em;
	padding: var(--hatchline-space) calc(var(--hatchline-space) * 2);
	text-transform: uppercase;
	width: 100%;
}

.hatchline-map__toggle:focus-visible {
	outline: 2px solid var(--hatchline-focus);
	outline-offset: 2px;
}

.hatchline-map__frame {
	/* Reserve the aspect ratio before the SVG arrives so loading it does not
	   shift the page. 975x610 is the generated viewBox. */
	aspect-ratio: 975 / 610;
	margin-top: var(--hatchline-space);
	width: 100%;
}

.hatchline-map__svg {
	display: block;
	height: auto;
	width: 100%;
}

.hatchline-map__status {
	color: var(--hatchline-ink-soft);
	font-family: var(--hatchline-font-data);
	font-size: .75rem;
	letter-spacing: .08em;
	margin: var(--hatchline-space) 0 0;
	min-height: 1em;
	text-transform: uppercase;
}

/* ---------- Regions ---------- */

.hatchline-map__svg path {
	fill: var(--hatchline-paper);
	stroke: var(--hatchline-rule);
	stroke-linejoin: round;
	stroke-width: .5;
	transition: fill 120ms ease, stroke 120ms ease;
}

/* A state with no territories. Not a market, so it is also not focusable and
   not in the tab order -- that part is enforced in markup, not here. */
.hatchline-map__svg path:not([data-hatchline-status]) {
	fill: var(--hatchline-paper);
	pointer-events: none;
}

.hatchline-map__svg path[data-hatchline-status] {
	cursor: pointer;
	fill: var(--hatchline-region-color, var(--hatchline-rule));
}

/* Every region fill is assigned inline by the script: a flat colour, or a
   pattern it builds for that status's colour. None of it can be declared here,
   because a stylesheet cannot name an id that does not exist until runtime and
   one shared id could only ever paint one colour. The rule that used to paint
   "blank" statuses in the surface colour is gone with them -- it made those
   regions invisible, and it lost to the inline fill anyway. */

.hatchline-map__svg path[data-hatchline-status]:hover,
.hatchline-map__svg path.is-hatchline-region-active {
	stroke: var(--hatchline-ink);
	stroke-width: 1.5;
}

.hatchline-map__svg path[data-hatchline-status]:focus {
	outline: none;
	stroke: var(--hatchline-focus);
	stroke-width: 2.5;
}

.hatchline-map__svg path[data-hatchline-status]:focus-visible {
	stroke: var(--hatchline-focus);
	stroke-width: 2.5;
}

.hatchline-map__svg path[aria-pressed="true"] {
	stroke: var(--hatchline-ink);
	stroke-width: 2;
}

/* ---------- Legend ---------- */

.hatchline-legend {
	border-top: var(--hatchline-hairline) solid var(--hatchline-rule);
	display: flex;
	flex-wrap: wrap;
	gap: var(--hatchline-space) calc(var(--hatchline-space) * 3);
	list-style: none;
	margin: calc(var(--hatchline-space) * 2) 0 0;
	padding: calc(var(--hatchline-space) * 1.5) 0 0;
}

.hatchline-legend__item {
	align-items: center;
	display: flex;
	gap: calc(var(--hatchline-space) / 2);
}

.hatchline-legend__label {
	color: var(--hatchline-ink-soft);
	font-family: var(--hatchline-font-data);
	font-size: .75rem;
	letter-spacing: .08em;
	text-transform: uppercase;
}

/* ---------- Load sweep ---------- */

/* West to east. The delay comes from data-hatchline-sweep, a 0..1 centroid
   position baked in at generation time and copied to a custom property by the
   script, so no geometry maths happens at runtime. */
@keyframes hatchline-region-in {
	from { opacity: 0; }
	to   { opacity: 1; }
}

.is-hatchline-sweeping .hatchline-map__svg path {
	animation: hatchline-region-in 120ms ease both;
	animation-delay: calc(var(--hatchline-sweep, 0) * 240ms);
}

/* The reduced-motion block earlier in this file collapses animation-duration,
   but `both` fill mode would still hold the from-state opacity:0 briefly. Force
   the finished state so suppressing the sweep can never leave a blank map. */
@media (prefers-reduced-motion: reduce) {
	.is-hatchline-sweeping .hatchline-map__svg path {
		animation: none !important;
		opacity: 1 !important;
	}
}

/* ---------- Desktop layout ---------- */

@media (min-width: 48em) {
	.hatchline-map__toggle {
		display: none;
	}

	/* Except when it is the retry control: a failed map must be recoverable at
	   every width, not only where the toggle happens to have a job. */
	.hatchline-map.is-hatchline-map-failed .hatchline-map__toggle {
		display: block;
	}

	.hatchline-map__frame {
		margin-top: 0;
	}
}

/* ==========================================================================
   Inquiry form
   ========================================================================== */

.hatchline-inquiry__market {
	color: var(--hatchline-ink-soft);
	font-family: var(--hatchline-font-data);
	font-size: .8125rem;
	letter-spacing: .08em;
	margin: 0 0 calc(var(--hatchline-space) * 2);
	text-transform: uppercase;
}

.hatchline-inquiry__market strong {
	color: var(--hatchline-ink);
}

.hatchline-inquiry__form {
	background: var(--hatchline-paper);
	border: var(--hatchline-hairline) solid var(--hatchline-rule);
	border-radius: var(--hatchline-radius);
	display: grid;
	gap: calc(var(--hatchline-space) * 3);
	max-width: 34rem;
	padding: calc(var(--hatchline-space) * 3);
}

.hatchline-inquiry__group {
	border: 0;
	display: grid;
	gap: calc(var(--hatchline-space) * 1.5);
	margin: 0;
	padding: 0;
}

.hatchline-field {
	display: grid;
	gap: calc(var(--hatchline-space) / 2);
}

.hatchline-field__label {
	color: var(--hatchline-ink);
	font-family: var(--hatchline-font-body);
	font-size: .9375rem;
	font-weight: 600;
}

.hatchline-field__required {
	text-transform: none;
}

.hatchline-root .hatchline-field__input {
	background: var(--hatchline-paper) !important;
	border: var(--hatchline-hairline) solid var(--hatchline-rule);
	border-radius: var(--hatchline-radius);
	color: var(--hatchline-ink) !important;
	font-family: var(--hatchline-font-body);
	/* Never below 16px: smaller triggers zoom-on-focus in iOS Safari. */
	font-size: 1rem;
	padding: calc(var(--hatchline-space) * 1.25);
	width: 100%;
}

.hatchline-field__input:focus-visible {
	outline: 2px solid var(--hatchline-focus);
	outline-offset: 2px;
}

.hatchline-field--error .hatchline-field__input {
	border-color: var(--hatchline-limited, #B45309);
	border-width: 2px;
}

.hatchline-field__error {
	color: var(--hatchline-limited, #B45309);
	font-size: .875rem;
	margin: 0;
}

.hatchline-field__error:empty {
	display: none;
}

.hatchline-inquiry__summary {
	border-left: 3px solid var(--hatchline-limited, #B45309);
	margin-bottom: calc(var(--hatchline-space) * 2);
	padding: var(--hatchline-space) calc(var(--hatchline-space) * 1.5);
}

.hatchline-inquiry__summary p {
	margin: 0;
}

.hatchline-inquiry__summary:focus-visible {
	outline: 2px solid var(--hatchline-focus);
	outline-offset: 2px;
}

.hatchline-inquiry__sent {
	border-left: 3px solid var(--hatchline-available, #0F7B6C);
	font-size: 1.125rem;
	margin: 0;
	padding: var(--hatchline-space) calc(var(--hatchline-space) * 1.5);
}

.hatchline-inquiry__form .hatchline-cta {
	border: 0;
	cursor: pointer;
	justify-self: start;
}

/* Honeypot. Positioned off-screen rather than display:none, which bots detect
   and skip. It is also aria-hidden and out of the tab order, so nothing that
   reads or tabs the page can reach it. */
.hatchline-hp {
	height: 1px;
	left: -9999px;
	overflow: hidden;
	position: absolute;
	top: auto;
	width: 1px;
}

/* ==========================================================================
   Layout: map first, list in a modal
   ==========================================================================

   The first attempt put a scrolling list rail beside the map. With 52 states
   that is a long scrollbar next to a small map, and the component was still
   very tall. The reference implementation this product is measured against
   puts search and map first and opens the full list on demand, which is also
   what the client reacted to. So: search, then a large map, with the list
   behind a "Browse all markets" button.

   Without JavaScript the list is simply visible below the map, as before -- the
   modal only exists once the script has initialised.
   ========================================================================== */

.hatchline-root .hatchline-browse {
	background: transparent !important;
	border: var(--hatchline-hairline) solid var(--hatchline-rule);
	border-radius: var(--hatchline-radius);
	color: var(--hatchline-ink) !important;
	cursor: pointer;
	display: none;
	font-family: var(--hatchline-font-data);
	font-size: .75rem;
	letter-spacing: .08em;
	margin-bottom: var(--hatchline-space);
	padding: var(--hatchline-space) calc(var(--hatchline-space) * 2);
	text-transform: uppercase;
}

.is-hatchline-enhanced .hatchline-browse {
	display: inline-block;
}

.hatchline-browse:focus-visible {
	outline: 2px solid var(--hatchline-focus);
	outline-offset: 2px;
}

/* Map leads. */
.is-hatchline-enhanced .hatchline-map {
	margin-top: var(--hatchline-space);
	order: -1;
}

@media (min-width: 48em) {
	.is-hatchline-enhanced .hatchline-map__frame {
		margin-inline: auto;
		max-width: 60rem;
	}
}

/* The list becomes a centered modal once the script is running. */
@media (min-width: 48em) {
	.is-hatchline-enhanced .hatchline-list {
		background: #fff;
		border: var(--hatchline-hairline) solid var(--hatchline-rule);
		border-radius: var(--hatchline-radius);
		box-shadow: 0 8px 32px rgba(22, 32, 42, .18);
		inset: 0;
		margin: auto;
		max-height: 80vh;
		max-width: 34rem;
		opacity: 0;
		overflow-y: auto;
		position: fixed;
		transform: scale(.96);
		transition: opacity 180ms ease, transform 180ms ease;
		visibility: hidden;
		z-index: 999999;
	}

	.is-hatchline-enhanced.is-hatchline-modal-open .hatchline-list {
		opacity: 1;
		transform: scale(1);
		visibility: visible;
	}

	.is-hatchline-enhanced .hatchline-list .hatchline-search {
		background: #fff;
		border-bottom: var(--hatchline-hairline) solid var(--hatchline-rule);
		padding: calc(var(--hatchline-space) * 1.5);
	}
}

/* On narrow screens the modal is a full-height sheet. */
@media (max-width: 47.99em) {
	.is-hatchline-enhanced .hatchline-list {
		background: #fff;
		bottom: 0;
		left: 0;
		overflow-y: auto;
		position: fixed;
		right: 0;
		top: 0;
		transform: translateY(100%);
		transition: transform 180ms ease;
		z-index: 999999;
	}

	.is-hatchline-enhanced.is-hatchline-modal-open .hatchline-list {
		transform: translateY(0);
	}
}

/* Dimmer behind the modal. z-index deliberately very high (not just above our
   own modal): a host theme's own sticky/fixed header can carry an arbitrary
   z-index -- one real theme observed using z-index:95 on a position:fixed
   nav bar still painted over a z-index:1000 modal, because there is no
   universal "safe" small number when the host page's stacking is unknown.
   !important is not used here since nothing in this codebase sets z-index
   on these selectors elsewhere, but the value itself is the defensive
   measure. */
.hatchline-scrim {
	background: rgba(22, 32, 42, .35);
	inset: 0;
	opacity: 0;
	pointer-events: none;
	position: fixed;
	transition: opacity 180ms ease;
	z-index: 999998;
}

.is-hatchline-modal-open .hatchline-scrim {
	opacity: 1;
	pointer-events: auto;
}

.hatchline-root .hatchline-modal-close {
	background: var(--hatchline-paper) !important;
	border: 0;
	border-bottom: var(--hatchline-hairline) solid var(--hatchline-rule);
	color: var(--hatchline-ink) !important;
	cursor: pointer;
	display: none;
	font-family: var(--hatchline-font-data);
	font-size: .75rem;
	letter-spacing: .08em;
	padding: calc(var(--hatchline-space) * 1.5);
	text-align: left;
	text-transform: uppercase;
	width: 100%;
}

.is-hatchline-enhanced .hatchline-modal-close {
	display: block;
}

/* One sticky header holding the close button and the pinned finder.
   They cannot each be independently sticky at top:0 -- sibling sticky
   elements do not stack, they overlap -- so this wrapper is the only
   sticky element and the two children are positioned in normal flow
   inside it. */
.is-hatchline-enhanced .hatchline-list__header {
	background: var(--hatchline-paper);
	position: sticky;
	top: 0;
	z-index: 1;
}

/* Inside the list the finder is the panel's header, so its own bottom rule is
   the divider above the first row -- it needs no extra gap under it. */
.is-hatchline-list-header .hatchline-finder,
.hatchline-list__header .hatchline-finder {
	margin-bottom: 0;
	padding: calc(var(--hatchline-space) * 2);
}

/* The detail panel opens over the modal, so it needs to sit above it. */
.is-hatchline-enhanced .hatchline-row__disclosure[open] .hatchline-detail {
	z-index: 1001;
}

@media (prefers-reduced-motion: reduce) {
	.hatchline-list,
	.hatchline-scrim {
		transition: none !important;
	}
}

/* Preview-mode banner. Only ever rendered for someone who can edit
   territories, so it never reaches a visitor. */
.hatchline-preview-notice {
	background: #FFF4E5;
	border-left: 3px solid var(--hatchline-limited, #B45309);
	color: #16202A;
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	font-size: .8125rem;
	margin: 0 0 1rem;
	padding: .75rem 1rem;
}


/* ===========================================================================
   Side-by-side: map and list together.

   Replaces both earlier attempts. Showing the list in the page pushed the map
   down the moment a visitor clicked a state; showing it as a dialog covered
   the very thing they had just clicked. Both were the same problem -- 272 rows
   cannot live in normal flow, and overlaying is not the answer either.

   Side by side solves it: the list is its own scroll container next to the
   map, so filtering it changes nothing about the page's geometry. Selecting a
   state updates the panel beside it, with the map still visible.

   Only above 62em, where there is genuinely room for two columns. Below that
   the existing stacked behaviour and its dialog remain, which is correct on a
   phone.
   =========================================================================== */

/* Side by side, keyed on the component's own width rather than the viewport's.
   A theme can hand this a 650px content column inside a 1360px page; splitting
   that on the basis of screen width produces a 300px map, which is worse than
   not splitting at all.
   
   The measurement is done in JS, which sets is-hatchline-split, rather than by
   an @container query -- a container query styles a container's *descendants*,
   and the element that needs to become a grid here is the container itself.
   Nothing is lost: the split layout is enhancement-only anyway, gated behind
   is-hatchline-enhanced. */
.is-hatchline-enhanced.is-hatchline-split {
	display: grid;
	grid-template-columns: minmax(0, 1.15fr) minmax(20rem, 0.85fr);
	grid-template-areas:
		"map     list"
		"legend  list";
	/* The two columns are separate objects, not two halves of one panel;
	   24px read as a seam rather than a gap. */
	gap: 0 calc(var(--hatchline-space) * 6);
	align-items: start;
}

.is-hatchline-split .hatchline-map { grid-area: map; margin: 0; }
.is-hatchline-split .hatchline-legend-wrap { grid-area: legend; }

/* The list stops being a dialog entirely at this width. */
.is-hatchline-split .hatchline-list {
	grid-area: list;
	background: transparent;
	border: var(--hatchline-hairline) solid var(--hatchline-rule);
	border-radius: var(--hatchline-radius);
	box-shadow: none;
	inset: auto;
	margin: 0;
	max-height: min(38rem, 80vh);
	max-width: none;
	opacity: 1;
	overflow-y: auto;
	position: static;
	transform: none;
	visibility: visible;
	z-index: auto;
}

/* Everything that only existed to manage the dialog. */
.is-hatchline-split .hatchline-scrim,
.is-hatchline-split .hatchline-modal-close,
.is-hatchline-split .hatchline-browse {
	display: none;
}

/* The rows need no layout of their own here. The trigger is a two-child flex
   row -- text block, button -- which lays out the same at any width, so the
   grid of named areas this used to carry is simply gone rather than
   rewritten. That grid existed only to guess the alignment back after the
   markup had scattered six children across one line.

   The no-results block spans the whole component rather than sitting in the
   list column, since it replaces the list rather than appearing inside it. */
.is-hatchline-split .hatchline-no-results {
	grid-area: list;
}



/* The legend now keys both the shapes and the markers, so it says so. */
.hatchline-legend__caption {
	color: var(--hatchline-ink-soft);
	font-size: .875em;
	margin: calc(var(--hatchline-space) * 1.5) 0 calc(var(--hatchline-space) * 0.5);
}

.hatchline-legend__pin {
	flex: none;
	display: block;
}


