/* ===========================================================================
   Components — glassmorphic.

   Authored as one file rather than one file per component: this theme has no
   build step, so fifteen files would mean fifteen requests.

   Two rules hold throughout:
   1. No raw colours, font sizes or spacing values. If a value is missing it
      belongs in tokens.css.
   2. A glass surface only ever floats over a ground this theme controls, so
      the composite behind every glyph is known. Glass over an arbitrary
      photograph always gets a scrim first.
   =========================================================================== */

/* --- eyebrow + rule ------------------------------------------------------ */

.eyebrow {
	font-size: var(--text-xs);
	font-weight: 650;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--text-quiet-heading);
	margin-bottom: var(--space-2xs);
}
.section--inverse .eyebrow,
.panel--dark .eyebrow,
.glass--dark .eyebrow { color: var(--decor-warm); }

.waterline { color: var(--decor-warm); height: 8px; opacity: 0.85; }
.waterline svg { width: 100%; height: 8px; }

.section-head {
	display: flex;
	flex-wrap: wrap;
	align-items: end;
	justify-content: space-between;
	gap: var(--space-sm) var(--space-lg);
	margin-bottom: var(--space-lg);
}
.section-head p { max-width: 46ch; color: var(--text-muted); margin-top: var(--space-2xs); }
.section--inverse .section-head p { color: var(--text-inverse); opacity: 0.85; }

/* --- button --------------------------------------------------------------
   Solid, deliberately. Buttons must never be uncertain against what is behind
   them, and a translucent button over moving content is exactly that. The
   glass idiom shows up here as sheen and ambient shadow, not transparency.

   Retailer buttons share one treatment so neither reads as recommended.    */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2xs);
	padding: var(--space-xs) var(--space-md);
	min-height: 2.75rem;
	border: 1px solid transparent;
	border-radius: var(--radius-md);
	background: var(--action-primary-bg);
	color: var(--action-primary-text);
	box-shadow: var(--glass-sheen-dark), var(--shadow-raised);
	font-size: var(--text-sm);
	font-weight: 600;
	line-height: var(--leading-snug);
	text-decoration: none;
	transition: background var(--duration) var(--ease), color var(--duration) var(--ease),
		border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease),
		transform var(--duration-fast) var(--ease);
}
.btn:hover {
	background: var(--action-primary-bg-hover);
	color: var(--action-primary-text);
	box-shadow: var(--glass-sheen-dark), var(--glass-shadow-lifted);
	transform: translateY(-1px);
}
.btn:active { transform: translateY(1px); box-shadow: var(--shadow-raised); }
.btn .icon { flex: none; }

.btn--accent { background: var(--action-accent-bg); color: var(--action-accent-text); }
.btn--accent:hover { background: var(--action-accent-bg-hover); }

/* The one translucent button, and only because it sits on our own panels
   where the composite is known. */
.btn--secondary {
	background: var(--glass-tint-strong);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	color: var(--action-quiet-text);
	border-color: var(--border-control);
	box-shadow: var(--glass-sheen), var(--shadow-raised);
}
.btn--secondary:hover {
	background: var(--action-primary-bg);
	color: var(--action-primary-text);
	border-color: var(--action-primary-bg);
}

.btn--inverse { background: var(--surface-raised); color: var(--action-quiet-text); }
.btn--inverse:hover { background: var(--surface-page); color: var(--action-quiet-text); }

.btn--outline-inverse {
	background: rgb(255 255 255 / 0.12);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	color: var(--text-inverse);
	border-color: var(--glass-border-dark);
	box-shadow: var(--glass-sheen-dark);
}
.btn--outline-inverse:hover { background: var(--surface-raised); color: var(--action-quiet-text); }

.btn--lg { padding: var(--space-sm) var(--space-lg); font-size: var(--text-base); }
.btn--block { width: 100%; }

.btn[aria-disabled="true"],
.btn.is-disabled {
	background: var(--action-disabled-bg);
	color: var(--action-disabled-text);
	border-color: var(--border-subtle);
	box-shadow: none;
	transform: none;
	pointer-events: none;
}

/* Loading. Label hides rather than being replaced, so the button keeps its
   width and nothing around it shifts. */
.btn[data-loading="true"] { position: relative; color: transparent; pointer-events: none; }
.btn[data-loading="true"]::after {
	content: "";
	position: absolute;
	width: 1.1em;
	height: 1.1em;
	border: 2px solid var(--action-primary-text);
	border-top-color: transparent;
	border-radius: var(--radius-pill);
	animation: tw-spin 700ms linear infinite;
}
@keyframes tw-spin { to { transform: rotate(360deg); } }

.linkish {
	display: inline-flex;
	align-items: center;
	gap: var(--space-3xs);
	padding-block: var(--space-3xs);
	font-weight: 600;
	font-size: var(--text-sm);
	color: var(--text-link);
	text-decoration: none;
	border-bottom: 1.5px solid var(--decor-warm);
}
.linkish:hover { gap: var(--space-2xs); border-color: var(--action-accent-bg); }
.section--inverse .linkish,
.glass--dark .linkish { color: var(--text-inverse); }

/* --- chip ----------------------------------------------------------------
   Frosted pills over the page ground, which is ours — so translucency is safe
   here, and it is where the idiom pays off most visibly.                   */

.chip {
	display: inline-flex;
	align-items: center;
	gap: var(--space-3xs);
	padding: var(--space-3xs) var(--space-xs);
	min-height: 2.25rem;
	border: 1px solid var(--border-control);
	border-radius: var(--radius-pill);
	background: var(--glass-tint);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	box-shadow: var(--glass-sheen);
	font-size: var(--text-xs);
	font-weight: 550;
	color: var(--text-default);
	text-decoration: none;
	transition: background var(--duration) var(--ease), color var(--duration) var(--ease),
		border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}
a.chip:hover,
button.chip:hover {
	background: var(--glass-tint-strong);
	border-color: var(--border-strong);
	box-shadow: var(--glass-sheen), var(--shadow-raised);
}

.chip--active {
	background: var(--action-primary-bg);
	border-color: var(--action-primary-bg);
	color: var(--action-primary-text);
	box-shadow: var(--glass-sheen-dark);
}
a.chip--active:hover { background: var(--action-primary-bg-hover); color: var(--action-primary-text); }

.chip__count {
	font-size: var(--text-2xs);
	font-weight: 600;
	color: var(--text-muted);
	background: var(--glass-tint-sunken);
	border-radius: var(--radius-pill);
	padding-inline: var(--space-3xs);
}
.chip--active .chip__count { background: rgb(255 255 255 / 0.20); color: var(--action-primary-text); }

.chips { display: flex; flex-wrap: wrap; gap: var(--space-2xs); }

/* --- field ---------------------------------------------------------------
   Near-opaque. Text a visitor is typing must not compete with whatever is
   behind the field, and focus goes fully solid.

   `.form__row` is the contact form's own class, emitted by the plugin. The
   field component answers to both names rather than the plugin being edited
   to suit a theme — the plugin outlives the theme.                         */

.field, .form__row { display: grid; gap: var(--space-3xs); }
:is(.field, .form__row) label {
	font-size: var(--text-xs);
	font-weight: 650;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-muted);
}
:is(.field, .form__row) .req { color: var(--text-accent); }

:is(.field, .form__row) :is(input[type="text"], input[type="email"], input[type="url"], input[type="tel"],
	input[type="search"], textarea, select) {
	width: 100%;
	padding: var(--space-xs) var(--space-sm);
	min-height: 2.75rem;
	border: 1px solid var(--border-control);
	border-radius: var(--radius-md);
	background: var(--glass-tint-strong);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	box-shadow: var(--glass-sheen);
	color: var(--text-default);
	font-size: var(--text-base);
	transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease),
		background var(--duration) var(--ease);
}
:is(.field, .form__row) textarea { min-height: 9rem; resize: vertical; }
:is(.field, .form__row) :is(input, textarea, select)::placeholder { color: var(--text-muted); opacity: 1; }

:is(.field, .form__row) :is(input, textarea, select):focus-visible {
	background: var(--surface-raised);
	border-color: var(--action-accent-bg);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--action-accent-bg) 24%, transparent);
	outline: none;
}

/* Inline validation, so the error is attached to the control that caused it
   rather than only summarised at the top of the form. */
:is(.field, .form__row)[data-invalid="true"] :is(input, textarea, select) { border-color: var(--state-danger); }
.field__error {
	display: flex;
	align-items: center;
	gap: var(--space-3xs);
	font-size: var(--text-xs);
	font-weight: 600;
	color: var(--state-danger);
}
.field__hint { font-size: var(--text-xs); color: var(--text-muted); }

.honeypot { position: absolute !important; left: -9999px !important; }

/* --- notice --------------------------------------------------------------
   Opaque. A message about something going wrong is the worst possible place
   to make text harder to read.                                             */

.notice {
	padding: var(--space-sm) var(--space-md);
	border-radius: var(--radius-md);
	border: 1px solid var(--border-subtle);
	border-left: 3px solid var(--state-info);
	background: var(--state-info-surface);
	box-shadow: var(--shadow-raised);
	font-size: var(--text-sm);
}
.notice--success { border-left-color: var(--state-success); background: var(--state-success-surface); }
.notice--error { border-left-color: var(--state-danger); background: var(--state-danger-surface); }
.notice--warning { border-left-color: var(--state-warning); background: var(--state-warning-surface); }

/* --- card ---------------------------------------------------------------- */

.card {
	position: relative;
	display: flex;
	flex-direction: column;
	border-radius: var(--radius-lg);
	overflow: hidden;
	background: var(--glass-tint);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	border: 1px solid var(--glass-border);
	box-shadow: var(--glass-shadow), var(--glass-sheen);
	transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease),
		transform var(--duration) var(--ease), background var(--duration) var(--ease);
}
.card:hover,
.card:focus-within {
	background: var(--glass-tint-strong);
	border-color: var(--border-control);
	box-shadow: var(--glass-shadow-lifted), var(--glass-sheen);
	transform: translateY(-3px);
}

/* Product photography is opaque and sits inside the pane, not behind it —
   a blurred fly is a useless fly. */
.card__media {
	position: relative;
	aspect-ratio: 1 / 1;
	background: var(--surface-raised);
	overflow: hidden;
}
.card__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: opacity var(--duration) var(--ease), transform 420ms var(--ease);
}
.card__media img.card__alt { position: absolute; inset: 0; opacity: 0; }
.card:hover .card__alt,
.card:focus-within .card__alt { opacity: 1; }
.card:hover .card__media img,
.card:focus-within .card__media img { transform: scale(1.03); }

.card__body {
	display: flex;
	flex-direction: column;
	gap: var(--space-3xs);
	padding: var(--space-sm);
	flex: 1;
}
.card__kicker {
	font-size: var(--text-2xs);
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--text-quiet-heading);
	font-weight: 650;
}
.card__title { font-size: var(--text-md); line-height: var(--leading-snug); margin: 0; }
.card__title a { text-decoration: none; }
.card__title a::after { content: ""; position: absolute; inset: 0; }
.card__meta { font-size: var(--text-xs); color: var(--text-muted); }
.card__foot {
	margin-top: auto;
	padding-top: var(--space-2xs);
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-2xs);
	border-top: 1px solid var(--border-subtle);
	font-size: var(--text-xs);
	color: var(--text-muted);
}
.card__cta {
	display: inline-flex;
	align-items: center;
	gap: var(--space-3xs);
	font-weight: 650;
	color: var(--text-link);
}
.card__cta .icon { transition: transform var(--duration) var(--ease); }
.card:hover .card__cta .icon,
.card:focus-within .card__cta .icon { transform: translateX(3px); }

.card__where {
	display: flex;
	gap: var(--space-2xs);
	font-size: var(--text-2xs);
	font-weight: 650;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-quiet-heading);
}

/* A badge floated on the photograph. The ground here is a photo we do not
   control, so it takes the strong dark tint. */
.card__badge {
	position: absolute;
	top: var(--space-2xs);
	left: var(--space-2xs);
	z-index: 1;
	padding: var(--space-3xs) var(--space-2xs);
	border-radius: var(--radius-pill);
	background: var(--glass-tint-dark-strong);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	border: 1px solid var(--glass-border-dark);
	box-shadow: var(--glass-sheen-dark);
	color: var(--text-inverse);
	font-size: var(--text-2xs);
	font-weight: 650;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

/* --- grid ---------------------------------------------------------------- */

/* Card size is the difference between a catalog and a contact sheet. At a
   10.5rem minimum the shop rendered six columns of 188px at 1440, which is too
   small to read a fly at and made long titles wrap to three lines. The minimum
   only grows past the tablet threshold, so phones keep two per row. */
.grid {
	display: grid;
	gap: var(--space-sm);
	grid-template-columns: repeat(auto-fill, minmax(min(100%, 10.5rem), 1fr));
}
@media (min-width: 900px) {
	.grid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr)); }
}

/* Curated rows use auto-FIT, search results use auto-fill.
   The difference matters when the row under-fills: only four flies carry the
   featured flag, so auto-fill left them in the first four of seven tracks with
   a third of the row empty, which reads as a rendering fault. On search results
   a ragged last row is normal and expected, so those keep auto-fill. */
.grid--fit {
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 10.5rem), 1fr));
}
@media (min-width: 900px) {
	.grid--fit { grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); }
}
/* ...but a single fly must not become one enormous card. Article cards are
   exempt: they carry a 16:9 cover and read well wide, and capping them left
   two journal posts huddled in the corner of an otherwise empty row.

   The exemption is on .card--post rather than on every child, because search
   results use this same grid and can return flies. Exempting `> *` let a
   one-result search render a product card the full width of the page, with a
   photograph blown up to about 1000px. */
.grid--fit > * { max-width: 22rem; }
.grid--3.grid--fit > .card--post { max-width: none; }
@media (min-width: 900px) { .grid { gap: var(--space-md); } }

/* --- panel --------------------------------------------------------------- */

.panel {
	border-radius: var(--radius-lg);
	padding: var(--space-md);
	background: var(--glass-tint);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	border: 1px solid var(--glass-border);
	box-shadow: var(--glass-shadow), var(--glass-sheen);
}
.panel > h2, .panel > h3 { font-size: var(--text-lg); margin-bottom: var(--space-2xs); }
.panel--dark {
	background: var(--glass-tint-dark-panel);
	border-color: var(--glass-border-dark);
	box-shadow: var(--glass-shadow), var(--glass-sheen-dark);
	color: var(--text-inverse);
}
.panel--dark :is(h2, h3, h4) { color: var(--text-inverse); }

.checklist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2xs); }
.checklist li { display: flex; gap: var(--space-2xs); align-items: start; }
.checklist .icon { color: var(--text-accent); flex: none; margin-top: var(--space-3xs); }

/* --- header + nav --------------------------------------------------------
   The header is the one surface where glass earns its keep outright: it
   floats over scrolling content and the blur is what tells you so.        */

.site-header {
	position: sticky;
	top: 0;
	z-index: 100;
	background: var(--glass-tint-header);
	-webkit-backdrop-filter: var(--glass-blur-strong);
	backdrop-filter: var(--glass-blur-strong);
	border-bottom: 1px solid var(--glass-border);
	box-shadow: var(--glass-sheen);
	transition: background var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}
/* Once the page has scrolled the header has real content behind it, so it
   thickens. Toggled by a class from JS, not by scroll-linked animation. */
.site-header.is-stuck {
	background: var(--glass-tint-bar);
	box-shadow: var(--glass-shadow), var(--glass-sheen);
}

.site-header__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-md);
	min-height: var(--header-height);
}

.brand { display: inline-flex; align-items: center; gap: var(--space-2xs); text-decoration: none; }
.brand img { height: 2.25rem; width: auto; }
.brand__word {
	font-family: var(--font-display);
	font-size: var(--text-md);
	font-weight: 600;
	letter-spacing: -0.01em;
	color: var(--text-heading);
	line-height: var(--leading-tight);
}

.nav { display: none; }
.nav ul { display: flex; align-items: center; gap: var(--space-2xs); margin: 0; padding: 0; list-style: none; }
.nav a {
	display: block;
	padding: var(--space-2xs) var(--space-xs);
	border-radius: var(--radius-pill);
	font-size: var(--text-sm);
	font-weight: 550;
	color: var(--text-default);
	text-decoration: none;
	transition: background var(--duration) var(--ease), color var(--duration) var(--ease);
}
.nav a:hover { background: var(--glass-tint-strong); color: var(--text-heading); }
.nav .current-menu-item > a,
.nav .current_page_item > a { color: var(--text-heading); font-weight: 650; }
.nav .current-menu-item > a { background: var(--glass-tint-sunken); }

.nav-toggle {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2xs);
	padding: var(--space-2xs) var(--space-xs);
	min-height: 2.75rem;
	border: 1px solid var(--border-control);
	border-radius: var(--radius-pill);
	background: var(--glass-tint-strong);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	box-shadow: var(--glass-sheen);
	font-size: var(--text-xs);
	font-weight: 650;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-heading);
}

/* Mobile drawer. Strong tint, because at full height it carries every nav
   label and must not depend on what happens to be underneath. */
.nav-drawer {
	position: fixed;
	inset: var(--header-height) 0 0;
	z-index: 99;
	padding: var(--space-md) var(--gutter) var(--space-xl);
	overflow-y: auto;
	background: var(--glass-tint-bar);
	-webkit-backdrop-filter: var(--glass-blur-strong);
	backdrop-filter: var(--glass-blur-strong);
	border-top: 1px solid var(--glass-border);
}
.nav-drawer[hidden] { display: none; }
.nav-drawer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3xs); }
.nav-drawer a {
	display: block;
	padding: var(--space-sm);
	border-radius: var(--radius-md);
	border: 1px solid transparent;
	font-size: var(--text-md);
	font-family: var(--font-display);
	color: var(--text-heading);
	text-decoration: none;
}
.nav-drawer a:hover { background: var(--glass-tint); border-color: var(--glass-border); }

@media (min-width: 900px) {
	.nav { display: block; }
	.nav-toggle, .nav-drawer { display: none; }
}

/* --- hero ----------------------------------------------------------------
   The scrim is not decoration. It is what makes the dark glass card over the
   photograph have a computable worst case.                                 */

.hero { position: relative; overflow: hidden; isolation: isolate; }
/* No featured image means no scrim, so the card would be dark glass on cream —
   the same 3.74:1 trap. The section goes solid dark instead. */
.hero--plain { background: var(--surface-inverse); }
.hero--plain .hero__card {
	background: rgb(255 255 255 / 0.06);
	border-color: var(--glass-border-dark);
}
.hero__media { position: absolute; inset: 0; z-index: -2; }
.hero__media img { width: 100%; height: 100%; object-fit: cover; }
.hero__scrim {
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--scrim-hero);
}
.hero__inner { padding-block: var(--section-hero); }

.hero__card {
	max-width: 40rem;
	padding: var(--space-lg);
	border-radius: var(--radius-xl);
	background: var(--glass-tint-dark);
	-webkit-backdrop-filter: var(--glass-blur-strong);
	backdrop-filter: var(--glass-blur-strong);
	border: 1px solid var(--glass-border-dark);
	box-shadow: var(--glass-shadow-lifted), var(--glass-sheen-dark);
	color: var(--text-inverse);
}
.hero__card :is(h1, h2) { color: var(--text-inverse); }
.hero__card p { color: var(--text-inverse); opacity: 0.9; max-width: 46ch; }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-2xs); margin-top: var(--space-md); }

/* Small stat pills sitting on the hero glass. */
.hero__stats { display: flex; flex-wrap: wrap; gap: var(--space-2xs); margin-top: var(--space-md); }
.hero__stat {
	padding: var(--space-2xs) var(--space-xs);
	border-radius: var(--radius-pill);
	background: rgb(255 255 255 / 0.12);
	border: 1px solid var(--glass-border-dark);
	font-size: var(--text-2xs);
	font-weight: 650;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-inverse);
}

/* --- cover (interior page headers) --------------------------------------- */

.cover { position: relative; overflow: hidden; isolation: isolate; }
.cover--plain { background: var(--surface-sunken); }
.cover__inner { padding-block: var(--section-cover); }
.cover__title { margin-bottom: var(--space-2xs); }
.cover__lede { max-width: 56ch; color: var(--text-muted); font-size: var(--text-md); }

.breadcrumb {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-3xs);
	margin-bottom: var(--space-sm);
	font-size: var(--text-xs);
	color: var(--text-muted);
}
.breadcrumb a { color: var(--text-link); text-decoration: none; }
.breadcrumb a:hover { text-decoration: underline; }
.breadcrumb span[aria-hidden] { color: var(--decor-warm); }

/* --- gallery ------------------------------------------------------------- */

.gallery { display: grid; gap: var(--space-2xs); }
.gallery__main {
	position: relative;
	aspect-ratio: 1 / 1;
	border-radius: var(--radius-lg);
	overflow: hidden;
	background: var(--surface-raised);
	border: 1px solid var(--glass-border);
	box-shadow: var(--glass-shadow), var(--glass-sheen);
}
.gallery__main img { width: 100%; height: 100%; object-fit: cover; }
.gallery__thumbs { display: flex; flex-wrap: wrap; gap: var(--space-2xs); }
.gallery__thumb {
	width: 4.5rem;
	aspect-ratio: 1 / 1;
	padding: 0;
	border-radius: var(--radius-md);
	overflow: hidden;
	border: 1px solid var(--border-subtle);
	background: var(--surface-raised);
	transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease),
		transform var(--duration) var(--ease);
}
.gallery__thumb img { width: 100%; height: 100%; object-fit: cover; }
.gallery__thumb:hover { transform: translateY(-2px); box-shadow: var(--shadow-raised); }
.gallery__thumb[aria-current="true"] {
	border-color: var(--action-accent-bg);
	box-shadow: 0 0 0 2px color-mix(in srgb, var(--action-accent-bg) 40%, transparent);
}

/* --- variant picker ------------------------------------------------------ */

.picker { display: grid; gap: var(--space-2xs); }
.picker__heading {
	font-size: var(--text-xs);
	font-weight: 650;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-muted);
}
.picker__options { display: flex; flex-wrap: wrap; gap: var(--space-2xs); }
.picker__option {
	min-width: 3rem;
	padding: var(--space-2xs) var(--space-xs);
	min-height: 2.75rem;
	border-radius: var(--radius-md);
	border: 1px solid var(--border-control);
	background: var(--glass-tint);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	box-shadow: var(--glass-sheen);
	font-size: var(--text-sm);
	font-weight: 600;
	color: var(--text-default);
	transition: background var(--duration) var(--ease), color var(--duration) var(--ease),
		border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}
.picker__option:hover { background: var(--glass-tint-strong); border-color: var(--border-strong); }
.picker__option[aria-checked="true"] {
	background: var(--action-primary-bg);
	border-color: var(--action-primary-bg);
	color: var(--action-primary-text);
	box-shadow: var(--glass-sheen-dark);
}
.picker__option[disabled] {
	background: var(--action-disabled-bg);
	color: var(--action-disabled-text);
	border-color: var(--border-subtle);
	box-shadow: none;
	cursor: not-allowed;
	text-decoration: line-through;
}

/* --- buy ----------------------------------------------------------------- */

/* Markup comes from tw_buy_buttons() in the plugin: two .btn children and a
   .buy__note, so the layout is defined here around that shape.

   Both retailers get the identical treatment. They are two halves of one
   decision, and making either louder would tell the visitor something untrue
   about where to buy. */
.buy { display: grid; gap: var(--space-2xs); }
@media (min-width: 600px) {
	.buy { grid-template-columns: 1fr 1fr; }
	.buy__note { grid-column: 1 / -1; }
}
/* :where() keeps these at zero specificity so the disabled state, which is
   .btn.is-disabled, still wins. Written as .buy .btn--amazon they tie on
   specificity, come later in the file, and a retailer link that does not exist
   yet renders as a live bronze button. */
.buy :where(.btn--amazon, .btn--walmart) {
	background: var(--action-accent-bg);
	color: var(--action-accent-text);
}
.buy :where(.btn--amazon, .btn--walmart):hover { background: var(--action-accent-bg-hover); }

.buy__note {
	display: flex;
	align-items: center;
	gap: var(--space-3xs);
	font-size: var(--text-xs);
	color: var(--text-muted);
}
.buy__note .icon { flex: none; color: var(--text-quiet-heading); }

/* Sticky mobile buy bar. Floats over content, so glass again does real work.
   Switches at the same 900px threshold as the nav — no width gets a hamburger
   without a buy affordance. */
.buybar {
	position: fixed;
	inset: auto 0 0;
	z-index: 90;
	padding: var(--space-2xs) var(--gutter);
	padding-bottom: max(var(--space-2xs), env(safe-area-inset-bottom));
	background: var(--glass-tint-bar);
	-webkit-backdrop-filter: var(--glass-blur-strong);
	backdrop-filter: var(--glass-blur-strong);
	border-top: 1px solid var(--glass-border);
	box-shadow: var(--glass-shadow-lifted), var(--glass-sheen);
}
.buybar__row { display: flex; gap: var(--space-2xs); }
.buybar .btn { flex: 1; }
@media (min-width: 900px) { .buybar { display: none; } }

/* --- facets -------------------------------------------------------------- */

.shopbar {
	position: sticky;
	top: var(--header-height);
	z-index: 80;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-2xs) var(--space-sm);
	padding: var(--space-2xs) var(--space-sm);
	margin-bottom: var(--space-md);
	border-radius: var(--radius-lg);
	background: var(--glass-tint-bar);
	-webkit-backdrop-filter: var(--glass-blur-strong);
	backdrop-filter: var(--glass-blur-strong);
	border: 1px solid var(--glass-border);
	box-shadow: var(--glass-shadow), var(--glass-sheen);
}
.shopbar__count { font-size: var(--text-sm); color: var(--text-muted); }
.shopbar__count strong { color: var(--text-strong); font-weight: 650; }

.facets { display: grid; gap: var(--space-md); }
.facets__group { display: grid; gap: var(--space-2xs); }
.facets__legend {
	font-size: var(--text-xs);
	font-weight: 650;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--text-quiet-heading);
}

/* Pending state. The results are stale until the new page lands, so they dim
   and stop taking clicks — and screen readers get told via aria-busy.
   Scoped to .results: the video button also carries aria-busy, and a global
   position:relative would shuffle anything whose layout depended on being
   out of flow. */
.results[aria-busy="true"] {
	position: relative;
	opacity: 0.45;
	pointer-events: none;
	transition: opacity var(--duration) var(--ease);
}
.results[aria-busy="true"]::after {
	content: "";
	position: absolute;
	top: var(--space-lg);
	left: 50%;
	width: 1.75rem;
	height: 1.75rem;
	transform: translateX(-50%);
	border: 2px solid var(--border-control);
	border-top-color: transparent;
	border-radius: var(--radius-pill);
	animation: tw-spin 700ms linear infinite;
}

.empty {
	display: grid;
	gap: var(--space-sm);
	justify-items: center;
	text-align: center;
	padding: var(--space-xl) var(--space-md);
	border-radius: var(--radius-lg);
	background: var(--glass-tint);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	border: 1px dashed var(--border-control);
}
.empty p { max-width: 44ch; color: var(--text-muted); }

/* --- pagination ---------------------------------------------------------- */

.pagination { display: flex; flex-wrap: wrap; gap: var(--space-2xs); justify-content: center; margin-top: var(--space-lg); }
.pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.75rem;
	min-height: 2.75rem;
	padding-inline: var(--space-2xs);
	border-radius: var(--radius-md);
	border: 1px solid var(--border-control);
	background: var(--glass-tint);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	box-shadow: var(--glass-sheen);
	font-size: var(--text-sm);
	font-weight: 600;
	color: var(--text-default);
	text-decoration: none;
}
.pagination .page-numbers:hover { background: var(--glass-tint-strong); }
.pagination .page-numbers.current {
	background: var(--action-primary-bg);
	border-color: var(--action-primary-bg);
	color: var(--action-primary-text);
}
.pagination .page-numbers.dots { border-color: transparent; background: none; box-shadow: none; }

/* --- video facade --------------------------------------------------------
   Nothing is requested from the provider until the play button is pressed.
   The spinner covers the gap between the click and the iframe painting.    */

.video {
	position: relative;
	aspect-ratio: 16 / 9;
	border-radius: var(--radius-lg);
	overflow: hidden;
	background: var(--surface-inverse);
	border: 1px solid var(--glass-border-dark);
	box-shadow: var(--glass-shadow-lifted);
}
.video img, .video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; object-fit: cover; }

/* Class names follow tw_video() in the plugin. */
.video__btn {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	gap: var(--space-sm);
	width: 100%;
	padding: var(--space-md);
	align-content: center;
	background: var(--scrim-video);
}
.video__ring {
	display: grid;
	place-items: center;
	width: 4.5rem;
	height: 4.5rem;
	border-radius: var(--radius-pill);
	background: var(--glass-tint-dark-strong);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	border: 1px solid var(--glass-border-dark);
	box-shadow: var(--glass-shadow-lifted), var(--glass-sheen-dark);
	color: var(--text-inverse);
	transition: transform var(--duration) var(--ease), background var(--duration) var(--ease);
}
.video__btn:hover .video__ring { transform: scale(1.08); background: var(--action-accent-bg); }

.video__label {
	max-width: 34ch;
	font-family: var(--font-display);
	font-size: var(--text-md);
	line-height: var(--leading-snug);
	color: var(--text-inverse);
	text-shadow: var(--shadow-video-label);
}

/* Between the click and the iframe painting there is a real gap on a slow
   connection. The ring becomes the spinner rather than sitting inert. */
.video[data-loading="true"] .video__ring {
	border-top-color: transparent;
	animation: tw-spin 700ms linear infinite;
}
.video[data-loading="true"] .video__btn svg { display: none; }

/* --- footer -------------------------------------------------------------- */

.site-footer {
	margin-top: var(--space-2xl);
	background: var(--surface-inverse);
	color: var(--text-inverse);
	position: relative;
	isolation: isolate;
}
.site-footer::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--bloom-footer);
}
.site-footer :is(h2, h3, h4) { color: var(--text-inverse); }
.site-footer a { color: var(--text-inverse); }

.footer__grid {
	display: grid;
	gap: var(--space-lg);
	padding-block: var(--space-xl);
}
@media (min-width: 600px) { .footer__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px) { .footer__grid { grid-template-columns: 1.4fr 1fr 1fr 1fr; } }

.footer__title {
	font-family: var(--font-ui);
	font-size: var(--text-xs);
	font-weight: 650;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--decor-warm);
	margin-bottom: var(--space-2xs);
}
.footer__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2xs); }
.footer__list a { font-size: var(--text-sm); text-decoration: none; opacity: 0.88; }
.footer__list a:hover { opacity: 1; text-decoration: underline; }

.footer__bar {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2xs) var(--space-md);
	align-items: center;
	justify-content: space-between;
	padding-block: var(--space-sm);
	border-top: 1px solid var(--glass-border-dark);
	font-size: var(--text-xs);
	opacity: 0.85;
}
/* Its own badge, not a phrase inside the copyright line's dimmed opacity -
   that made a live link look disabled. Real product footers give the builder
   credit its own small, deliberate treatment: label muted, name and icon
   full-strength, the icon nudging on hover the same way .linkish does. */
.footer__credit {
	display: inline-flex;
	align-items: center;
	gap: var(--space-3xs);
	padding: var(--space-3xs) var(--space-2xs);
	border-radius: var(--radius-pill);
	border: 1px solid var(--glass-border-dark);
	color: var(--text-inverse);
	text-decoration: none;
	font-size: var(--text-xs);
	line-height: 1;
	transition: border-color var(--duration) var(--ease), background var(--duration) var(--ease);
}
.footer__credit:hover,
.footer__credit:focus-visible {
	border-color: var(--decor-warm);
	background: rgb(255 255 255 / 0.06);
}
.footer__credit-label { opacity: 0.65; }
.footer__credit-name { font-weight: 650; }
.footer__credit .icon {
	flex: none;
	color: var(--decor-warm);
	transition: transform var(--duration) var(--ease);
}
.footer__credit:hover .icon,
.footer__credit:focus-visible .icon { transform: translate(2px, -2px); }

/* --- prose --------------------------------------------------------------- */

.prose > * + * { margin-top: var(--space-sm); }
.prose > :is(h2, h3) { margin-top: var(--space-lg); }
/* The reset strips list markers from any ul carrying a class, and WordPress
   gives every editor list one (wp-block-list). Inside prose that silently
   removed the bullets from anything the client writes, so they come back. */
.prose ul, .prose ol { padding-left: var(--space-md); display: grid; gap: var(--space-2xs); }
.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }
.prose li::marker { color: var(--decor-warm); }
.prose blockquote {
	margin-inline: 0;
	padding: var(--space-md);
	border-radius: var(--radius-lg);
	border-left: 3px solid var(--decor-warm);
	background: var(--glass-tint);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	font-family: var(--font-display);
	font-size: var(--text-md);
}
.prose img { border-radius: var(--radius-lg); }

/* Article figures. Almost all the fly photography is portrait - phone shots
   carrying EXIF rotation, and Amazon's are 1125x1500 - so at the full 64ch
   measure a 3:4 photo renders about 1000px tall and swallows the article it is
   meant to illustrate. Capping the height and letting the width follow keeps a
   product shot an illustration rather than an interruption, and there is no
   layout shift because the width/height attributes still set the aspect. */
.prose figure { margin-block: var(--space-md); }
.prose figure img {
	max-height: 28rem;
	width: auto;
	margin-inline: auto;
}
.prose figcaption {
	margin-top: var(--space-2xs);
	font-size: var(--text-sm);
	line-height: var(--leading-snug);
	color: var(--text-muted);
	text-align: center;
	text-wrap: pretty;
}

/* ===========================================================================
   Compositions — how the components arrange on each template.

   Every layout switch below happens at 900px, the one tablet threshold. That
   is the point of it: no width can produce a half-mobile, half-desktop page
   the way the previous build did between 768px and 992px.
   =========================================================================== */

/* --- announcement --------------------------------------------------------- */

.announce {
	padding-block: var(--space-2xs);
	background: var(--surface-inverse);
	color: var(--text-inverse);
	font-size: var(--text-xs);
	text-align: center;
}
.announce a { color: var(--decor-warm); }

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

.site-header__actions { display: flex; align-items: center; gap: var(--space-2xs); }
.header__cta { display: none; }
@media (min-width: 900px) { .header__cta { display: inline-flex; } }

.nav-drawer__foot { display: grid; gap: var(--space-sm); margin-top: var(--space-lg); }

.social { display: flex; gap: var(--space-2xs); margin-top: var(--space-sm); }
.social__link {
	display: grid;
	place-items: center;
	width: 2.5rem;
	height: 2.5rem;
	border-radius: var(--radius-pill);
	border: 1px solid var(--glass-border-dark);
	background: rgb(255 255 255 / 0.10);
	color: inherit;
}
.social__link:hover { background: rgb(255 255 255 / 0.20); }
.nav-drawer .social__link { border-color: var(--border-control); background: var(--glass-tint); }

/* --- trust row ------------------------------------------------------------ */

.trust {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-sm);
}
@media (min-width: 600px) { .trust { grid-template-columns: repeat(3, 1fr); } }
.trust li { display: flex; gap: var(--space-sm); align-items: start; }
.trust .icon { flex: none; color: var(--text-accent); margin-top: var(--space-3xs); }
.trust b { display: block; font-size: var(--text-sm); color: var(--text-heading); }
.trust span { font-size: var(--text-sm); color: var(--text-muted); }

/* --- founder band --------------------------------------------------------- */

.founder { display: grid; gap: var(--space-lg); align-items: center; }
@media (min-width: 900px) { .founder { grid-template-columns: 1fr 1fr; gap: var(--space-xl); } }
.founder__media img { width: 100%; border-radius: var(--radius-lg); box-shadow: var(--glass-shadow-lifted); }
.founder__body { display: grid; gap: var(--space-sm); align-content: start; }
.founder__body h2 { margin: 0; }

.pull { margin: 0; display: grid; gap: var(--space-sm); }
.pull p { font-family: var(--font-display); font-size: var(--text-lg); line-height: var(--leading-snug); }

/* --- fly page ------------------------------------------------------------- */

.fly { display: grid; gap: var(--space-lg); }
@media (min-width: 900px) {
	.fly { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-xl); align-items: start; }
	/* The gallery outruns the buy column on a tall screen; sticking it keeps
	   the photograph beside whichever variant is being chosen. */
	.fly__media { position: sticky; top: calc(var(--header-height) + var(--space-sm)); }
}
.fly__body { display: grid; gap: var(--space-sm); align-content: start; }
.fly__body h1 { margin: 0; }
.buyblock { display: grid; gap: var(--space-sm); margin-top: var(--space-2xs); }

.specs {
	display: grid;
	gap: var(--space-2xs);
	margin: 0;
	padding: var(--space-sm);
	border-radius: var(--radius-md);
	background: var(--glass-tint-sunken);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	border: 1px solid var(--glass-border);
}
@media (min-width: 600px) { .specs { grid-template-columns: repeat(2, 1fr); } }
.specs__row { display: flex; gap: var(--space-2xs); align-items: baseline; justify-content: space-between; }
.specs dt {
	font-size: var(--text-2xs);
	font-weight: 650;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--text-muted);
}
.specs dd { margin: 0; font-size: var(--text-sm); font-weight: 600; color: var(--text-strong); }

.selection { display: flex; flex-wrap: wrap; gap: var(--space-2xs); align-items: center; }
.selection__label {
	font-size: var(--text-2xs);
	font-weight: 650;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--text-quiet-heading);
	min-width: 6rem;
}

.picker__heading {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--space-3xs) var(--space-2xs);
}
.picker__label { flex: none; }
/* The readout is the current selection, not part of the label, so it drops its
   uppercase styling - run together they read as one long shouted string. */
.picker__readout {
	color: var(--text-strong);
	text-transform: none;
	letter-spacing: 0;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}

/* Panels go two-up at the same 900px threshold as everything else. */
.fly__panels { display: grid; gap: var(--space-md); }
@media (min-width: 900px) { .fly__panels { grid-template-columns: repeat(2, 1fr); align-items: start; } }

.reading { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2xs); }
.reading li { display: flex; flex-wrap: wrap; gap: var(--space-2xs); justify-content: space-between; align-items: baseline; }
.reading a { font-weight: 600; color: var(--text-link); text-decoration: none; }
.reading a:hover { text-decoration: underline; }
.reading span { font-size: var(--text-xs); color: var(--text-muted); }

/* Clear the sticky buy bar on phones, so the end of the page is not
   permanently half-covered. */
@media (max-width: 899px) {
	body.single-tw_fly .site-footer { padding-bottom: var(--space-xl); }
}

/* --- shop bar ------------------------------------------------------------- */

.shopbar__right { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2xs) var(--space-sm); }
.field--inline { display: block; }
.shopbar .field--inline select { min-width: 10rem; }

/* The search grew to fill the bar. Left at its intrinsic width it sat in the
   corner with a third of the toolbar empty between it and the sort, which read
   as an unfinished layout rather than a deliberate one. */
.shopbar__search { flex: 1 1 14rem; max-width: 28rem; }
.shopbar__search input { width: 100%; }

/* Separate the filters from the results. They were flush, so the last chip row
   sat directly on the first row of product photographs. */
.facets { margin-bottom: var(--space-lg); }

/* --- more filters --------------------------------------------------------
   A native disclosure: it works with no JavaScript, is keyboard operable and
   announces its own state, none of which a div and a click handler would give
   for free.                                                                */

.facets__more { border-top: 1px solid var(--border-subtle); padding-top: var(--space-sm); }
.facets__more > summary {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2xs);
	padding: var(--space-2xs) var(--space-xs);
	border-radius: var(--radius-pill);
	list-style: none;
	cursor: pointer;
	font-size: var(--text-xs);
	font-weight: 650;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-quiet-heading);
	transition: background var(--duration) var(--ease), color var(--duration) var(--ease);
}
.facets__more > summary::-webkit-details-marker { display: none; }
.facets__more > summary:hover { background: var(--glass-tint-strong); color: var(--text-heading); }
.facets__more > summary .icon { transition: transform var(--duration) var(--ease); }
.facets__more[open] > summary .icon { transform: rotate(90deg); }

.facets__panel { display: grid; gap: var(--space-md); padding-top: var(--space-sm); }

/* --- page templates ------------------------------------------------------- */

.page-band { margin: 0 0 var(--space-lg); }
/* The caption is a .wrap inside a 100vw-wide band, so the band needs to know
   where the viewport's scrollable width ends even when its own box is clipped. */
.page-band.full-bleed { margin-left: calc(50% - 50vw); }
.page-band img { width: 100%; max-height: 30rem; object-fit: cover; }
.page-band figcaption { font-size: var(--text-xs); color: var(--text-muted); padding-top: var(--space-2xs); }

.page-video { margin-bottom: var(--space-lg); }

.page-layout { display: grid; gap: var(--space-lg); }
@media (min-width: 900px) {
	/* Capped to what the two columns actually need, then centred.
	   Left to fill the full 78rem wrap, the prose stopped at its 64ch measure
	   around 720px while the aside began near 1030px, leaving a permanent
	   ragged gap between them and a large empty block under the aside. */
	.page-layout--aside {
		grid-template-columns: minmax(0, var(--measure)) 20rem;
		gap: var(--space-xl);
		align-items: start;
		justify-content: center;
		max-width: calc(var(--measure) + 20rem + var(--space-xl));
		margin-inline: auto;
	}
	.page-layout__aside { position: sticky; top: calc(var(--header-height) + var(--space-sm)); }
}
.page-layout--centred .page-layout__main { max-width: var(--measure); margin-inline: auto; }

/* The breadcrumb heads the content column, so it has to sit on the same
   left edge as the heading below it. */
.page-crumbs--centred { max-width: var(--measure); margin-inline: auto; }
@media (min-width: 900px) {
	.page-crumbs { max-width: calc(var(--measure) + 20rem + var(--space-xl)); margin-inline: auto; }
	/* After the rule above, not before: same specificity, so source order is
	   what decides which max-width the centred variant ends up with. */
	.page-crumbs--centred { max-width: var(--measure); }
}
.page-layout__aside { display: grid; gap: var(--space-sm); }
.page-layout__aside .panel--dark { display: grid; gap: var(--space-2xs); }

/* The journal reads at a larger size than the interface around it - 1.125rem
   to 1.25rem against the body's 1rem to 1.0625rem - because a 900-word article
   is read, not scanned. The column widens with it: at this size 50rem carries
   about the same 70-odd characters a line that 72ch did at the smaller type,
   so the measure stays comfortable while the page fills out. */
.entry {
	max-width: var(--measure-article);
	font-size: var(--text-article);
	line-height: 1.7;
}
.entry > .lede { font-size: 1.14em; line-height: 1.5; }

.entry__header { display: grid; gap: var(--space-2xs); margin-bottom: var(--space-md); }
/* The hero carries .wrap for its width, but `margin: 0 0 ...` is a shorthand:
   it re-set the `margin-inline: auto` that .wrap centres with, so the photograph
   sat hard against the left edge while the header and the text column stayed
   centred. It survived unnoticed because no post had a featured image until the
   journal was written, so this element had never rendered.

   It is also capped well below the 78rem wrap. A hero twice the width of the
   623px measure beneath it reads as two unrelated pages stacked; a little over
   half again is a breakout, which is what a hero should be. */
.entry__hero {
	width: min(78rem, 100% - (var(--gutter) * 2));
	margin: 0 auto var(--space-lg);
}
@media (min-width: 1200px) {
	/* Photograph, heading and both columns share one left and right edge. The
	   article drives its own track width, so the grid cannot clamp the text
	   narrower than the measure it is set to. */
	.entry-layout.page-layout--aside {
		grid-template-columns: minmax(0, var(--measure-article)) 20rem;
		max-width: calc(var(--measure-article) + 20rem + var(--space-xl));
	}
	.entry-crumbs { max-width: calc(var(--measure-article) + 20rem + var(--space-xl)); }
	.entry__hero { width: min(100% - (var(--gutter) * 2), calc(var(--measure-article) + 20rem + var(--space-xl))); }
}

/* --- patterns rail -------------------------------------------------------
   The flies an article links to, pulled from the copy itself. It also gives
   the journal page a second column, so a 701px measure stops sitting alone in
   the middle of a 1440px screen. */
.flylist { display: grid; gap: var(--space-3xs); }
.flylist a {
	display: grid;
	grid-template-columns: 3rem minmax(0, 1fr);
	gap: var(--space-2xs);
	align-items: center;
	padding: var(--space-3xs);
	border-radius: var(--radius-md);
	text-decoration: none;
}
.flylist a:hover { background: var(--surface-sunken); }
.flylist__media img { border-radius: var(--radius-sm); aspect-ratio: 1; object-fit: cover; }
.flylist__text { display: grid; gap: 0.1em; }
.flylist__name {
	font-size: var(--text-sm);
	font-weight: 600;
	line-height: var(--leading-snug);
	color: var(--text-heading);
}
.flylist__price { font-size: var(--text-xs); color: var(--text-muted); }

/* The rail waits for the 1200px breakpoint. The shared .page-layout--aside
   turns on at 900, which is right for page.php - its aside is four lines of
   marketing copy - but on an article it left the reading column about 429px,
   roughly 44 characters, for a 900-word piece. Below 1200 the rail drops under
   the text and the hero, heading and body all cap to the measure so they keep
   one shared edge. */
@media (max-width: 1199px) {
	.entry-crumbs { max-width: var(--measure-article); }
	.entry__hero { width: min(100% - (var(--gutter) * 2), var(--measure-article)); }
	.entry-layout.page-layout--aside {
		grid-template-columns: minmax(0, 1fr);
		max-width: var(--measure-article);
	}
}
.entry__hero img { width: 100%; border-radius: var(--radius-lg); box-shadow: var(--glass-shadow); }
.entry__hero figcaption {
	font-size: var(--text-xs);
	color: var(--text-muted);
	padding-top: var(--space-2xs);
	text-align: center;
}
.entry__tags { margin-top: var(--space-lg); }

/* --- journal cards -------------------------------------------------------- */

.grid--3 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr)); }

/* .grid--3 is declared after .grid--fit, so on its own it re-asserted auto-FILL
   and put two journal posts in the first two of four tracks. Two class names
   outrank one, which restores the fit behaviour for short listings. */
.grid--3.grid--fit { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
@media (min-width: 900px) {
	.grid--3.grid--fit { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }
}
.card__media--wide { aspect-ratio: 16 / 9; }
.card__excerpt { font-size: var(--text-sm); color: var(--text-muted); }

/* Typographic cover standing in for a photograph. Gradients are the one place
   raw hex appears outside tokens.css, because a four-stop decorative ramp used
   in a single component earns no semantic name. */
.artcover {
	display: grid;
	align-content: space-between;
	gap: var(--space-sm);
	width: 100%;
	height: 100%;
	padding: var(--space-sm);
	background: var(--surface-inverse);
	color: var(--text-inverse);
}
.artcover--river { background: var(--artcover-river); }
.artcover--deep { background: var(--artcover-deep); }
.artcover--drift { background: var(--artcover-drift); }
.artcover--charcoal { background: var(--artcover-charcoal); }
.artcover__eyebrow {
	font-size: var(--text-2xs);
	font-weight: 650;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--decor-warm);
}
.artcover__title {
	font-family: var(--font-display);
	font-size: var(--text-lg);
	line-height: var(--leading-snug);
	color: var(--text-inverse);
	margin: 0;
}
.artcover__title a { color: inherit; text-decoration: none; }
.artcover__title a::after { content: ""; position: absolute; inset: 0; }
.card--post { position: relative; }
.card--post .artcover { min-height: 11rem; }

/* --- search form ---------------------------------------------------------- */

.searchform { display: flex; flex-wrap: wrap; gap: var(--space-2xs); align-items: end; }
.searchform .field { flex: 1 1 14rem; }

/* --- empty states --------------------------------------------------------- */

.empty .icon { color: var(--text-quiet-heading); }
.empty--page { border-style: solid; }
.empty--page .hero__actions { justify-content: center; }

/* --- contact form --------------------------------------------------------- */

.twc-contact { max-width: var(--measure); }
.form { display: grid; gap: var(--space-sm); }
.form__cols { display: grid; gap: var(--space-sm); }
@media (min-width: 600px) { .form__cols { grid-template-columns: 1fr 1fr; } }
.form__hp { position: absolute !important; left: -9999px !important; }

/* Success replaces the form rather than sitting above a fresh blank copy. An
   empty form under a "message sent" notice reads as "send another one". */
.sent-card {
	display: grid;
	gap: var(--space-2xs);
	justify-items: start;
	padding: var(--space-lg);
	border-radius: var(--radius-lg);
	border: 1px solid var(--state-success);
	background: var(--state-success-surface);
	box-shadow: var(--shadow-raised);
}
.sent-card__mark {
	display: grid;
	place-items: center;
	width: 3rem;
	height: 3rem;
	border-radius: var(--radius-pill);
	background: var(--state-success);
	color: var(--surface-raised);
}
.sent-card__title { font-size: var(--text-lg); margin: 0; }
.sent-card__body { color: var(--text-default); }

/* ===========================================================================
   Structure components added in the page-structure pass.
   =========================================================================== */

/* --- how it works --------------------------------------------------------
   Numbered, because it is a sequence rather than three equal claims. The
   previous trust row asserted qualities; this explains the actual path, which
   is the thing a non-transactional catalog has to say early.               */

.steps {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-sm);
	counter-reset: step;
}
@media (min-width: 600px) { .steps { grid-template-columns: repeat(3, 1fr); } }

.steps li { position: relative; display: grid; gap: var(--space-2xs); align-content: start; }
.steps h3 { font-size: var(--text-md); margin: 0; }
.steps p { font-size: var(--text-sm); color: var(--text-muted); margin: 0; }

.steps__n {
	display: grid;
	place-items: center;
	width: 2.25rem;
	height: 2.25rem;
	border-radius: var(--radius-pill);
	background: var(--action-accent-bg);
	color: var(--action-accent-text);
	font-family: var(--font-display);
	font-size: var(--text-md);
	font-weight: 600;
	line-height: 1;
}

/* --- catalog entry cards -------------------------------------------------
   Anglers pick by what a fly IS before they pick by name, so the types are the
   route into twelve products rather than the grid alone.                   */

.types {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-sm);
	grid-template-columns: repeat(auto-fill, minmax(min(100%, 9rem), 1fr));
}

.type-card {
	position: relative;
	display: flex;
	flex-direction: column;
	border-radius: var(--radius-lg);
	overflow: hidden;
	background: var(--glass-tint);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	border: 1px solid var(--glass-border);
	box-shadow: var(--glass-shadow), var(--glass-sheen);
	transition: transform var(--duration) var(--ease), box-shadow var(--duration) var(--ease),
		border-color var(--duration) var(--ease);
}
.type-card:hover,
.type-card:focus-within {
	transform: translateY(-3px);
	border-color: var(--border-control);
	box-shadow: var(--glass-shadow-lifted), var(--glass-sheen);
}

.type-card__media {
	aspect-ratio: 4 / 3;
	background: var(--surface-raised);
	overflow: hidden;
}
.type-card__media img { width: 100%; height: 100%; object-fit: cover; }

.type-card__body { padding: var(--space-xs) var(--space-sm) var(--space-sm); display: grid; gap: var(--space-3xs); }
.type-card__title { font-size: var(--text-sm); margin: 0; line-height: var(--leading-snug); }
.type-card__title a { text-decoration: none; }
.type-card__title a::after { content: ""; position: absolute; inset: 0; }
.type-card__count { font-size: var(--text-2xs); color: var(--text-muted); margin: 0; }

/* --- quick facts ---------------------------------------------------------
   The three things that decide whether this is the right fly, above the buy.
   Distinct from .specs, which is the reference detail below it.            */

.facts {
	display: grid;
	gap: var(--space-2xs);
	margin: 0;
	padding: var(--space-sm) 0;
	border-top: 1px solid var(--border-subtle);
	border-bottom: 1px solid var(--border-subtle);
}
.facts__row { display: flex; flex-wrap: wrap; gap: var(--space-2xs) var(--space-sm); align-items: baseline; }
.facts dt {
	flex: 0 0 7rem;
	font-size: var(--text-2xs);
	font-weight: 650;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--text-quiet-heading);
}
.facts dd { margin: 0; font-size: var(--text-sm); font-weight: 600; color: var(--text-strong); }

/* --- pending listing -----------------------------------------------------
   Two disabled buttons are a dead end. This keeps a route to a purchase while
   the client is still adding listings.                                     */

.buyblock__pending { display: grid; gap: var(--space-sm); }
.buyblock__pending p { margin: 0; }
.buyblock__stores { display: grid; gap: var(--space-2xs); }
@media (min-width: 600px) { .buyblock__stores { grid-auto-flow: column; } }

/* --- feature panel -------------------------------------------------------
   The fishing notes, promoted out of a two-column grid cell. It is the reason
   to read this page rather than the retailer's listing.                    */

.panel--feature { padding: var(--space-lg); }
.panel--feature > h2 { font-size: var(--text-xl); margin-bottom: var(--space-sm); }
.panel--feature .prose ul { display: grid; gap: var(--space-2xs); }
.panel--feature .prose li { padding-left: var(--space-2xs); }
.panel--feature .prose li::marker { color: var(--decor-warm); }

/* --- article prev / next -------------------------------------------------- */

/* Bottom margin as well as top: the read-on cards sit between the article and
   the "Keep reading" band, and with only a top margin their lower edge ran
   straight into the change of background colour, reading as an overlap. */
.postnav {
	display: grid;
	gap: var(--space-2xs);
	margin-top: var(--space-lg);
	margin-bottom: var(--section-tight);
}
@media (min-width: 600px) { .postnav { grid-template-columns: 1fr 1fr; } }

.postnav__link {
	display: grid;
	gap: var(--space-3xs);
	padding: var(--space-sm) var(--space-md);
	border-radius: var(--radius-lg);
	background: var(--glass-tint);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	border: 1px solid var(--glass-border);
	box-shadow: var(--glass-sheen);
	text-decoration: none;
	transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}
.postnav__link:hover { border-color: var(--border-control); box-shadow: var(--shadow-raised); }
.postnav__link--next { text-align: right; grid-column: -2 / -1; }

.postnav__dir {
	font-size: var(--text-2xs);
	font-weight: 650;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--text-quiet-heading);
}
.postnav__title {
	font-family: var(--font-display);
	font-size: var(--text-md);
	line-height: var(--leading-snug);
	color: var(--text-heading);
}

/* ===========================================================================
   Commerce — price, unit price and availability.

   These are the signals that separate a shop from a brochure. Every fly in the
   catalog already carried a price; none of them showed it.
   =========================================================================== */

/* --- shop header ---------------------------------------------------------
   A category header, not a landing band. It was 369px tall with its text
   stopping 606px short of the right edge, putting the first product 786px
   down the page. The reassurance points fill that half and shorten the band. */

.cover--shop .cover__inner { padding-block: var(--section-tight); }

/* A category heading, not a hero. At --text-3xl it was sized for a landing
   page and pushed the products further down for no gain. */
.cover--shop .cover__title { font-size: var(--text-2xl); }

/* The band's own bottom padding and the results section's top padding stacked
   into a 96px gap between the header and the toolbar. */
.cover--shop + .section--tight { padding-top: var(--space-md); }

.shophead { display: grid; gap: var(--space-md); }
@media (min-width: 900px) {
	.shophead {
		grid-template-columns: minmax(0, 1fr) auto;
		gap: var(--space-xl);
		align-items: end;
	}
}
.shophead__intro { min-width: 0; }
.shophead .cover__lede { margin-top: var(--space-2xs); }

.shophead__points {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-2xs);
}
.shophead__points li {
	display: flex;
	align-items: center;
	gap: var(--space-2xs);
	font-size: var(--text-sm);
	color: var(--text-default);
}
.shophead__points .icon { flex: none; color: var(--text-accent); }

/* --- price on a card ------------------------------------------------------
   Sits directly above the footer row so the eye runs title → spec → price,
   which is the order a shopper reads a product card in.                    */

.card__price {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--space-3xs) var(--space-2xs);
	margin: 0;
	margin-top: var(--space-3xs);
}

.card__amount {
	font-family: var(--font-display);
	font-size: var(--text-md);
	font-weight: 650;
	line-height: 1;
	color: var(--text-strong);
	font-variant-numeric: tabular-nums;
}

.card__unit {
	font-size: var(--text-2xs);
	color: var(--text-muted);
	font-variant-numeric: tabular-nums;
}

/* A pattern with no listing says so. Blank and "not stocked" look identical,
   and the blank one reads as a rendering fault.

   Deliberately quiet: it is currently true of all twelve patterns, so at accent
   weight it repeated twelve times down the grid and out-shouted every price on
   the page. A status is not a call to action. */
.card__where--pending { color: var(--text-muted); }

/* Prices have to line up across a row, and a two-line title pushed them out of
   step. Reserving two lines on every title is what keeps the grid a grid. */
.card__title { min-height: calc(2 * var(--text-md) * var(--leading-snug)); }
.card__body { display: flex; flex-direction: column; }

/* --- price on the product page --------------------------------------------
   The headline figure, an availability line, and the per-fly maths. Placed
   between the lede and the quick facts, which is where a shopper looks.    */

.priceblock {
	display: grid;
	gap: var(--space-3xs);
	padding: var(--space-sm) 0;
}

.priceblock__amount {
	margin: 0;
	font-family: var(--font-display);
	font-size: var(--text-xl);
	font-weight: 650;
	line-height: 1;
	color: var(--text-strong);
	font-variant-numeric: tabular-nums;
}

.priceblock__unit {
	margin: 0;
	font-size: var(--text-sm);
	color: var(--text-muted);
	font-variant-numeric: tabular-nums;
}

.priceblock__avail {
	display: flex;
	align-items: center;
	gap: var(--space-3xs);
	margin: 0;
	margin-top: var(--space-3xs);
	font-size: var(--text-sm);
	font-weight: 600;
}
.priceblock__avail .icon { flex: none; }
.priceblock__avail.is-listed { color: var(--state-success); }
.priceblock__avail.is-pending { color: var(--text-accent); }

/* ===========================================================================
   Shop layout — filters beside the results.
   =========================================================================== */

.shop { display: grid; gap: var(--space-md); }
/* The sidebar waits for 1200px, not 900px. At 900 it left the results 524px
   wide, which is one product column - a filter panel that costs you two thirds
   of the grid is not a filter panel worth having. */
@media (min-width: 1200px) {
	.shop {
		grid-template-columns: 15rem minmax(0, 1fr);
		gap: var(--space-xl);
		align-items: start;
	}
	/* The column travels with the results rather than scrolling away from
	   them, which is the point of putting it beside the grid. */
	.shop__filters { position: sticky; top: calc(var(--header-height) + var(--space-sm)); }
}
.shop__results { min-width: 0; }

.filters { display: grid; gap: var(--space-md); }

.filters__head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--space-2xs);
	margin: 0;
	padding-bottom: var(--space-2xs);
	border-bottom: 1px solid var(--border-subtle);
	font-size: var(--text-xs);
	font-weight: 650;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--text-heading);
}
.filters__clear {
	font-size: var(--text-2xs);
	font-weight: 650;
	letter-spacing: 0.06em;
	color: var(--text-link);
}

/* In a column the chips stack rather than run in a line, so each reads as a
   choice in a list instead of a row of tags. */
@media (min-width: 1200px) {
	.shop__filters .chips { flex-direction: column; align-items: stretch; }
	.shop__filters .chip { justify-content: space-between; border-radius: var(--radius-md); }
}

/* ===========================================================================
   Product card — two actions, the way a shop card carries them.
   =========================================================================== */

.card__line {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--space-3xs) var(--space-2xs);
}
.card__line .card__meta { margin: 0; }
.card__price { margin: 0; }

.card__unit {
	margin: 0;
	font-size: var(--text-2xs);
	color: var(--text-muted);
	font-variant-numeric: tabular-nums;
}

.card__actions {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--space-2xs);
	margin-top: auto;
	padding-top: var(--space-sm);
}

/* A pattern with no listing gets one action, not a disabled second one
   pretending to be a button. */
.card__pending {
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: var(--text-2xs);
	font-weight: 650;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-muted);
}

.btn--sm {
	padding: var(--space-2xs) var(--space-xs);
	min-height: 2.5rem;
	font-size: var(--text-xs);
}

/* The stretched title link used to cover the whole card. With real actions in
   the footer it would sit on top of the buy button and swallow its clicks, so
   the card is no longer one big link - each action is its own target. */
.card__title a::after { content: none; }

/* ===========================================================================
   UX audit pass — header search, the unlisted state, footer legal.
   =========================================================================== */

/* --- header search -------------------------------------------------------
   Replaces a CTA that pointed at the same URL as the "Shop" nav item beside
   it. Search previously had no entry point outside the shop and the 404.   */

.header__search-toggle {
	display: none;
	align-items: center;
	gap: var(--space-2xs);
	padding: var(--space-2xs) var(--space-sm);
	min-height: 2.75rem;
	border: 1px solid var(--border-control);
	border-radius: var(--radius-pill);
	background: var(--glass-tint-strong);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	box-shadow: var(--glass-sheen);
	font-size: var(--text-xs);
	font-weight: 650;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-heading);
	text-decoration: none;
	transition: background var(--duration) var(--ease), border-color var(--duration) var(--ease);
}
.header__search-toggle:hover { background: var(--surface-raised); border-color: var(--border-strong); }
@media (min-width: 900px) { .header__search-toggle { display: inline-flex; } }

.header__search {
	padding-block: var(--space-sm);
	border-top: 1px solid var(--glass-border);
	background: var(--glass-tint-bar);
	-webkit-backdrop-filter: var(--glass-blur-strong);
	backdrop-filter: var(--glass-blur-strong);
}
.header__search .searchform { max-width: 34rem; margin-inline: auto; }

/* --- unlisted pattern ----------------------------------------------------
   Not a notice pretending to be a purchase. One honest statement and one
   action that works with nothing configured.                              */

.pending {
	display: grid;
	gap: var(--space-sm);
	padding: var(--space-md);
	border-radius: var(--radius-lg);
	border: 1px dashed var(--border-control);
	background: var(--glass-tint-sunken);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
}
.pending__note { margin: 0; font-size: var(--text-sm); color: var(--text-default); }
.pending__note strong { display: block; color: var(--text-strong); }
.pending__actions { display: grid; gap: var(--space-2xs); }
@media (min-width: 600px) { .pending__actions { grid-auto-flow: column; justify-content: start; } }

/* --- footer legal --------------------------------------------------------
   The disclosure is no longer optional, so it needs somewhere to live.    */

.footer__legal {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2xs) var(--space-md);
	align-items: baseline;
	justify-content: space-between;
	padding-block: var(--space-sm);
	border-top: 1px solid var(--glass-border-dark);
	font-size: var(--text-xs);
}

/* .disclosure defaults to --text-muted, which is calibrated for the cream page.
   On the dark footer that landed at 2.29:1, and a blanket opacity on the row
   pushed it lower still. Here it takes the inverse colour, and the dimming is
   applied to the text rather than the container so it can be measured: cream at
   82% over river-800 is 9.66:1. */
.footer__legal p { margin: 0; max-width: 68ch; color: var(--text-inverse); opacity: 0.82; }
.footer__legal .disclosure { color: var(--text-inverse); }
.footer__legal a { border-bottom: 1px solid var(--decor-warm); text-decoration: none; }

/* The disclosure also appears on the fly page, on a light ground. */
.disclosure { font-size: var(--text-xs); color: var(--text-muted); }
.fly__panels .disclosure { grid-column: 1 / -1; }

/* The footer only reserves room for the sticky buy bar when a fly actually
   has a listing, because only then does the bar exist. */
@media (max-width: 899px) {
	body.single-tw_fly.has-buybar .site-footer { padding-bottom: var(--space-xl); }
}

/* ===========================================================================
   Glass fallbacks — LAST in the cascade on purpose.

   These live at the end of the last stylesheet because they must override the
   component rules above, which set backdrop-filter and translucent
   backgrounds. Kept in base.css they lost silently: same specificity, earlier
   source order, so every component stayed frosted in exactly the conditions
   that call for solid.
   =========================================================================== */

/* The fallbacks below must name the real components, not just the .glass
   utility. Every frosted surface in this theme is a component — .card, .panel,
   .chip and the three bars — so listing only .glass would leave the entire
   interface translucent in exactly the situations that call for solid. */
.glass, .glass--strong, .glass--warm,
.card, .panel, .chip, .specs, .empty, .picker__option, .pagination .page-numbers,
	.type-card, .postnav__link, .facts, .pending, .header__search, .filters,
	.header__search-toggle,
.site-header, .shopbar, .buybar, .nav-drawer, .gallery__main,
.btn--secondary, .prose blockquote,
:is(.field, .form__row) :is(input, textarea, select) { --glass-fallback: var(--glass-solid); }

.glass--dark, .glass--dark-strong,
.panel--dark, .card__badge, .video__ring, .hero__card { --glass-fallback: var(--glass-solid-dark); }

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
	/* An unblurred translucent panel shows the content behind it straight
	   through the text. Go fully opaque rather than degrade to that. */
	.glass, .glass--strong, .glass--warm, .glass--dark, .glass--dark-strong,
	.card, .panel, .chip, .specs, .empty, .picker__option, .pagination .page-numbers,
	.type-card, .postnav__link, .facts, .pending, .header__search, .filters,
	.header__search-toggle,
	.site-header, .shopbar, .buybar, .nav-drawer, .gallery__main,
	.btn--secondary, .prose blockquote, .card__badge, .video__ring, .hero__card,
	:is(.field, .form__row) :is(input, textarea, select) {
		background-color: var(--glass-fallback);
	}
	.glass--sunken, .specs { background-color: var(--glass-solid-sunken); }
}

/* A stated accessibility preference, often set by people who find translucent
   interfaces hard to read. The blooms go too — they exist only to give the
   glass something to refract. */
@media (prefers-reduced-transparency: reduce) {
	body::before { display: none; }

	.glass, .glass--strong, .glass--warm, .glass--dark, .glass--dark-strong,
	.card, .panel, .chip, .specs, .empty, .picker__option, .pagination .page-numbers,
	.type-card, .postnav__link, .facts, .pending, .header__search, .filters,
	.header__search-toggle,
	.site-header, .shopbar, .buybar, .nav-drawer, .gallery__main,
	.btn--secondary, .prose blockquote, .card__badge, .video__ring, .hero__card,
	:is(.field, .form__row) :is(input, textarea, select) {
		background-color: var(--glass-fallback);
		backdrop-filter: none;
		-webkit-backdrop-filter: none;
	}
	.glass--sunken, .specs { background-color: var(--glass-solid-sunken); }
}

/* Windows high contrast strips backgrounds entirely, so a frosted panel
   dissolves into the page. Give every one of them a real border back. */
@media (forced-colors: active) {
	.glass, .glass--dark,
	.card, .panel, .chip, .specs, .empty, .picker__option, .pagination .page-numbers,
	.type-card, .postnav__link, .facts, .pending, .header__search, .filters,
	.header__search-toggle,
	.site-header, .shopbar, .buybar, .nav-drawer, .gallery__main,
	.card__badge, .video__ring, .hero__card, .btn {
		border: 1px solid CanvasText;
		backdrop-filter: none;
		-webkit-backdrop-filter: none;
	}
}

/* ===========================================================================
   Print — LAST in the file, after the glass fallbacks.

   A fly page printed as a reference card: photograph, name, sizes, what it
   imitates, and how to fish it. Everything that only exists to navigate a
   website is dropped, because on paper it navigates nothing.
   =========================================================================== */

@media print {
	/* Glass is a screen idiom. On paper a blurred translucent panel is just a
	   grey box that costs ink, so every surface goes flat white. */
	*, *::before, *::after {
		background: transparent !important;
		box-shadow: none !important;
		backdrop-filter: none !important;
		-webkit-backdrop-filter: none !important;
		text-shadow: none !important;
		color: var(--print-ink) !important;
	}

	body::before { display: none !important; }

	body {
		font-size: 11pt;
		line-height: 1.45;
	}

	/* Chrome that cannot be used on paper. */
	.site-header,
	.header__search,
	.nav-drawer,
	.buybar,
	.shopbar,
	.facets,
	.breadcrumb,
	.pagination,
	.postnav,
	.gallery__thumbs,
	.site-footer nav,
	.footer__grid,
	.skip-link,
	.announce,
	.picker__options,
	.video__btn {
		display: none !important;
	}

	/* Related patterns and the journal band are a browsing aid, not reference. */
	.section--accent,
	.card--post {
		display: none !important;
	}

	a { text-decoration: underline; }

	/* A printed link is only useful if you can read where it goes - but only
	   for real destinations, not in-page or javascript hrefs. */
	.entry a[href^="http"]::after,
	.prose a[href^="http"]::after {
		content: " (" attr(href) ")";
		font-size: 9pt;
		word-break: break-all;
	}

	/* One column. The two-up product layout wastes a page on paper. */
	.fly,
	.fly__panels,
	.page-layout--aside {
		display: block !important;
		max-width: none !important;
	}
	.fly__media { position: static !important; }
	.gallery__main { max-width: 90mm; border: 1px solid var(--print-rule) !important; }

	.panel,
	.specs,
	.facts,
	.pending {
		border: 1px solid var(--print-rule) !important;
		break-inside: avoid;
	}

	/* Never split a heading from what it introduces. */
	h1, h2, h3 { break-after: avoid; }
	.panel, .facts__row, .specs__row, .checklist li { break-inside: avoid; }

	/* Say where this came from, since the header is gone. */
	.site-footer::after {
		content: "tailwatersupply.com";
		display: block;
		padding-top: 6pt;
		border-top: 1px solid var(--print-rule);
		font-size: 9pt;
	}

	@page { margin: 15mm; }
}
