/*
 * pm-v2-controls — the shared search control and the button sheen.
 *
 * ONE stylesheet for the two cross-surface concerns that were previously smeared
 * across four files (header.css, home.css, surfaces.css, and the per-component
 * button blocks): search geometry and an opt-in sheen for download/copy/back-to-top.
 *
 * It is enqueued right after `pm-v2-layout` and before `pm-v2-header`, so both the
 * header's own rules and the per-surface sheets (home, surfaces) load AFTER it and
 * win any head-to-head they still have. That ordering is deliberate: this file is
 * the FLOOR (the cohesive bordered pill every `.pm-searchform` shares), and the
 * surface modifiers (`--hero`, `--surface`, …) may only ADD to it, never re-declare
 * the border/radius/height it owns.
 *
 * Everything is scoped to `.pm-v2` like every other child stylesheet.
 */

/* ============================================================== search form == */

/*
 * The form is one search shell, following the project's reference component: a clear
 * surface, stronger border, leading icon, flexible field and a separate rounded submit.
 * Every surface (homepage hero, archive/search, empty search and 404) shares this geometry;
 * its modifier may size the shell but does not rebuild the control.
 *
 * The focus indicator stays INSIDE the shell. This avoids the doubled/outside outline that
 * made the form appear to spill past its border while keeping a visible keyboard state.
 * The visually-hidden label remains inside the form but does not affect its flex layout.
 */
.pm-v2 .pm-searchform {
	position: relative;
	box-sizing: border-box;
	display: flex;
	align-items: center;
	gap: var(--sp-3);
	width: 100%;
	min-width: 0;
	padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-4);
	border: 1px solid var(--border-strong);
	border-radius: var(--r-lg);
	background-color: var(--surface);
	box-shadow: var(--shadow-sm);
}

.pm-v2 .pm-searchform:focus-within {
	border-color: var(--focus);
	box-shadow: inset 0 0 0 2px var(--focus), var(--shadow-sm);
}

.pm-v2 .pm-searchform__icon {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	color: var(--muted);
}


/*
 * Visually hidden label. The `<label>` stays a real, labelled-by element for screen
 * readers on every surface (the accessible name never depends on the placeholder);
 * the markup keeps it and this rule hides it visually, exactly as the header did.
 */
.pm-v2 .pm-searchform .pm-searchform__label,
.pm-v2 .pm-searchform label {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* The input owns no separate border or focus ring; the shell supplies both. */
.pm-v2 .pm-searchform .pm-searchform__input,
.pm-v2 .pm-searchform input[type="search"] {
	flex: 1 1 auto;
	min-width: 0;
	width: 100%;
	margin: 0;
	padding: 0;
	font: inherit;
	font-size: 1rem;
	color: var(--text);
	background-color: transparent;
	border: 0;
	border-radius: 0;
	outline: none;
	box-shadow: none;
	min-height: 48px;
}

.pm-v2 .pm-searchform__icon svg {
	width: 20px;
	height: 20px;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	vertical-align: middle;
}

.pm-v2 .pm-searchform .pm-searchform__input::placeholder,
.pm-v2 .pm-searchform input[type="search"]::placeholder {
	color: var(--muted);
	opacity: 1;
}

/*
 * The submit is a real 48px-tall button with a >=44px-wide touch target. Its own
 * rounded corners sit inside the shell padding, matching the reference control.
 *
 * `position: relative` + `overflow: hidden` keeps the control's children inside its
 * own box and prevents horizontal overflow.
 */
.pm-v2 .pm-searchform .pm-searchform__submit,
.pm-v2 .pm-searchform button[type="submit"],
.pm-v2 .pm-searchform input[type="submit"],
.pm-v2 .pm-searchform input[type="button"],
.pm-v2 .pm-searchform input[type="reset"] {
	position: relative;
	overflow: hidden;
	flex: 0 0 auto;
	align-self: center;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--sp-1);
	min-width: 44px;
	min-height: 48px;
	margin: 0;
	padding: 0 var(--sp-4);
	font: inherit;
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--primary-contrast);
	background-color: var(--primary);
	border: 0;
	border-radius: var(--r-md);
	cursor: pointer;
	transition: background-color var(--pm-ease);
}

.pm-v2 .pm-searchform .pm-searchform__submit:hover,
.pm-v2 .pm-searchform button[type="submit"]:hover,
.pm-v2 .pm-searchform input[type="submit"]:hover,
.pm-v2 .pm-searchform input[type="button"]:hover,
.pm-v2 .pm-searchform input[type="reset"]:hover,
.pm-v2 .pm-searchform .pm-searchform__submit:focus-visible,
.pm-v2 .pm-searchform button[type="submit"]:focus-visible,
.pm-v2 .pm-searchform input[type="submit"]:focus-visible,
.pm-v2 .pm-searchform input[type="button"]:focus-visible,
.pm-v2 .pm-searchform input[type="reset"]:focus-visible {
	background-color: var(--focus);
}

/*
 * Keyboard focus on the SEARCH button is drawn INSIDE the button, not outside it.
 * The shell already supplies an inset focus indicator via `:focus-within`; adding a
 * second outside outline would recreate the overlapping/truncated border this layout
 * is designed to avoid. The button adds a distinct inset ring for its own focus state.
 */
.pm-v2 .pm-searchform .pm-searchform__submit:focus-visible,
.pm-v2 .pm-searchform button[type="submit"]:focus-visible,
.pm-v2 .pm-searchform input[type="submit"]:focus-visible,
.pm-v2 .pm-searchform input[type="button"]:focus-visible,
.pm-v2 .pm-searchform input[type="reset"]:focus-visible {
	outline: none;
	box-shadow: inset 0 0 0 2px var(--primary-contrast);
}

.pm-v2 .pm-searchform .pm-searchform__submit:active,
.pm-v2 .pm-searchform button[type="submit"]:active,
.pm-v2 .pm-searchform input[type="submit"]:active,
.pm-v2 .pm-searchform input[type="button"]:active,
.pm-v2 .pm-searchform input[type="reset"]:active {
	background-color: var(--text);
}

.pm-v2 .pm-searchform .pm-searchform__submit:disabled,
.pm-v2 .pm-searchform button[type="submit"]:disabled,
.pm-v2 .pm-searchform input[type="submit"]:disabled {
	opacity: 0.55;
	cursor: not-allowed;
}

/* Submit/clear icons are compact; the leading search glyph keeps the reference 20px size. */
.pm-v2 .pm-searchform button svg {
	width: 16px;
	height: 16px;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	vertical-align: middle;
}

/* Native GP dialog: keep its markup, submit icon, colours and modal controller. */
.pm-v2 .search-modal-form {
	box-sizing: border-box;
	min-width: 0;
	padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-4);
	border: 1px solid var(--border-strong);
	border-radius: var(--r-lg);
	background-color: var(--gp-search-modal-bg-color, var(--surface));
	color: var(--gp-search-modal-text-color, var(--text));
	box-shadow: var(--shadow-sm);
}

.pm-v2 .search-modal-form:focus-within {
	border-color: var(--focus);
	box-shadow: inset 0 0 0 2px var(--focus), var(--shadow-sm);
}

.pm-v2 .search-modal-form .search-modal-fields {
	align-items: center;
	gap: var(--sp-3);
	min-width: 0;
}

.pm-v2 .search-modal-form .search-field,
.pm-v2 .search-modal-form .search-field:focus {
	box-sizing: border-box;
	flex: 1 1 auto;
	min-width: 0;
	width: 100%;
	height: 48px;
	min-height: 48px;
	margin: 0;
	padding: 0;
	font: inherit;
	font-size: 1rem;
	color: inherit;
	background-color: transparent;
	border: 0;
	border-radius: 0;
	outline: none;
	box-shadow: none;
}

.pm-v2 .search-modal-form .search-modal-fields button {
	box-sizing: border-box;
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	min-width: 44px;
	height: 48px;
	min-height: 48px;
	margin: 0;
	padding: 0;
	border-radius: var(--r-md);
}

.pm-v2 .search-modal-form .search-modal-fields button:focus-visible {
	outline: none;
	box-shadow: inset 0 0 0 2px currentColor;
}

.pm-v2 .search-modal-form .gp-icon svg {
	top: 0;
	width: 20px;
	height: 20px;
}

/* Forced colors discard box shadows; keep the keyboard indicator inside the control. */
@media (forced-colors: active) {
	.pm-v2 .pm-searchform:focus-within,
	.pm-v2 .search-modal-form:focus-within {
		outline: 2px solid Highlight;
		outline-offset: -2px;
	}

	.pm-v2 .pm-searchform button[type="submit"]:focus-visible,
	.pm-v2 .pm-searchform input[type="submit"]:focus-visible,
	.pm-v2 .search-modal-form .search-modal-fields button:focus-visible {
		outline: 2px solid Highlight;
		outline-offset: -4px;
	}
}

/* --------------------------------------------------------------- modifiers -- */

/*
 * Surface modifier. It sits in the body flow and may be wider than the header's
 * compact control, but it inherits EVERYTHING above (border, radius, focus ring,
 * heights) and only caps its width.
 */
.pm-v2 .pm-searchform--surface,
.pm-v2 .pm-searchform--not-found,
.pm-v2 .pm-searchform--empty {
	max-width: 560px;
	margin: 0;
}

/* Hero keeps its shared search shell geometry; the hero's parent supplies its context. */
.pm-v2 .pm-searchform--hero {
	max-width: 640px;
	margin-inline: 0;
}
/* ==================================================================== sheen == */

/*
 * The periodic "sheen" sweep, modelled on the reference site's `.btn-teal::after`
 * (a skewed translucent stripe, a long idle loop). Ours keeps the blue brand instead of
 * the reference turquoise: the sweep is a translucent WHITE stripe over the button's own
 * background, so the brand colour underneath is untouched and the label stays legible.
 *
 * A generated ::after stripe is clipped inside each approved control.
 * It idles for 75% of its 6s cycle, then sweeps across using transform.
 */

/* Only download actions, copy controls and back-to-top opt into the sheen.
 * Generic buttons, search, pagination and third-party UI have no stripe. */
.pm-v2 .pm-detail__cta[href="#pm-download"],
.pm-v2 .pm-download__mirror-link,
.pm-v2 .pm-download__copy,
.pm-v2 .psc-gate__copy {
	position: relative;
	overflow: hidden;
}

/*
 * The GeneratePress back-to-top control IS a button in every sense except geometry: it
 * carries the sweep, but its `position: fixed` is its OWN and must survive. It is given
 * the clipping needed for the stripe WITHOUT `position: relative` (which would un-fix it
 * and drop it into the footer flow), so it is kept out of the `position: relative` group
 * above and given only `overflow: hidden` here.
 *
 * THE GEOMETRY IS RE-DECLARED HERE BECAUSE GENERATEPRESS DOES NOT EMIT IT.
 *
 * Parent `inc/css-output.php` prints the button's `font-size`/`border-radius`/
 * `position: fixed`/`bottom`/`right`/`line-height`/`width`/`opacity`/`transform` block
 * from a location INSIDE a media query that only opens for the `nav-float-right` /
 * `nav-float-left` navigation positions (`(max-width: nav_drop_point) and (min-width:
 * 769px)`). This child theme does not use either position, so that query never opens,
 * the block is skipped, and the served CSS contains the button's COLOURS ONLY. Measured
 * on the live page: the anchor computed to `position: static`, which drops it into the
 * footer flow instead of pinning it to the corner, and leaves it permanently at full
 * opacity because the `0.1 -> 1` reveal depends on the missing rule too.
 *
 * So the positioning half the parent omits is supplied here, restated to the theme's
 * own tokens rather than to hard-coded parent values: a fixed bottom-right square on the
 * brand surface, revealed by the `--show` class the parent's script toggles. The parent
 * keeps ownership of the COLOURS (its two emitted rules are left alone), and the sweep
 * already attached below paints on top.
 */
.pm-v2 .generate-back-to-top {
	position: fixed;
	bottom: var(--sp-5);
	right: var(--sp-5);
	z-index: 10;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	min-width: 44px;
	height: 44px;
	line-height: 1;
	border-radius: var(--r-sm);
	overflow: hidden;
	opacity: 0;
	visibility: hidden;
	transform: translateY(1000px);
	transition: opacity 300ms ease-in-out, transform 300ms ease-in-out, visibility 300ms, background-color var(--pm-ease);
}

/*
 * The revealed state. `visibility` is switched here rather than relying on `opacity`
 * alone so the control is also removed from the accessibility tree and from hit-testing
 * while it is parked off-screen — an invisible-but-focusable button is a trap for a
 * keyboard visitor.
 */
.pm-v2 .generate-back-to-top.generate-back-to-top__show {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

/*
 * A parked control must not be clickable or focusable. `visibility: hidden` already
 * removes it from the tab order, and this keeps the transition from being interrupted if
 * a browser paints a frame late.
 */
.pm-v2 .generate-back-to-top:not(.generate-back-to-top__show) {
	pointer-events: none;
}

/*
 * THE GLYPH IS CENTRED BY RESETTING GENERATEPRESS' OWN BASELINE NUDGE.
 *
 * The button is `inline-flex` with `align-items: center`, so its child box is already
 * centred — but the glyph inside it is not. GeneratePress ships the arrow as
 * `<span class="gp-icon icon-arrow-up"><svg/></span>`, and its `main.css` gives
 * `.gp-icon svg` `position: relative; top: .125em`.
 *
 * That `top` is a TEXT-baseline nudge designed for an inline icon sitting in a line of
 * running text. In the nav links and buttons it is invisible because it is absorbed by
 * the line box. Here the parent is a fixed 44px flex box with nothing but the icon in
 * it, so the nudge has no line height to spend itself in and pushes the arrow a full
 * ~2px below the centre — which is the "lệch xuống dưới" that was reported.
 *
 * `top: 0` removes the nudge; the flex centring then does the job it was already doing.
 * The size is unchanged and no transform is added, so the sheen sweep and the hover
 * state are untouched.
 */
.pm-v2 .generate-back-to-top .gp-icon,
.pm-v2 .generate-back-to-top svg {
	top: 0;
}

/* Minimum touch target is 44px; the square above already meets it. */
.pm-v2 .generate-back-to-top svg {
	width: 18px;
	height: 18px;
}

/* Reduced motion: the control still appears, it just stops sliding. */
@media (prefers-reduced-motion: reduce) {
	.pm-v2 .generate-back-to-top {
		transform: none;
		transition: none;
	}

	.pm-v2 .generate-back-to-top.generate-back-to-top__show {
		transform: none;
	}
}

/*
 * The stripe. A real 50%-wide band pinned to the left and full height of the button,
 * parked off-screen to the left by `translateX(-250%)` and swept to `translateX(350%)`
 * — the translate is applied BEFORE the -20deg skew, so the band travels horizontally
 * while leaning, exactly like the reference.
 *
 * A width of 50% (rather than a 200%-sized background) is what removes the "resting
 * triangle" the previous version left: at rest the band is genuinely clear of the button
 * (translateX(-250%) of a 50% band is well past the left edge), so a screenshot at t=0
 * shows NO sliver of highlight parked at the edge. With `overflow: hidden` the band is
 * clipped to the button's rounded box at every frame.
 */
.pm-v2 .pm-detail__cta[href="#pm-download"]::after,
.pm-v2 .pm-download__mirror-link::after,
.pm-v2 .pm-download__copy::after,
.pm-v2 .psc-gate__copy::after,
.pm-v2 .generate-back-to-top::after {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	height: 100%;
	width: 50%;
	pointer-events: none;
	background-image: linear-gradient(
		105deg,
		transparent 0%,
		rgba(255, 255, 255, 0.5) 50%,
		transparent 100%
	);
	transform: translateX(-250%) skewX(-20deg);
	animation: pm-controls-shine 6s linear infinite;
}

@keyframes pm-controls-shine {
	0%,
	75% {
		transform: translateX(-250%) skewX(-20deg);
	}
	100% {
		transform: translateX(350%) skewX(-20deg);
	}
}

/* Remove the decorative box entirely for reduced motion or disabled controls. */
@media (prefers-reduced-motion: reduce) {
	.pm-v2 .pm-detail__cta[href="#pm-download"]::after,
	.pm-v2 .pm-download__mirror-link::after,
	.pm-v2 .pm-download__copy::after,
	.pm-v2 .psc-gate__copy::after,
	.pm-v2 .generate-back-to-top::after {
		content: none;
		animation: none !important;
	}
}

.pm-v2 .pm-detail__cta[href="#pm-download"]:is(:disabled, [aria-disabled="true"])::after,
.pm-v2 .pm-download__mirror-link:is(:disabled, [aria-disabled="true"])::after,
.pm-v2 .pm-download__copy:is(:disabled, [aria-disabled="true"])::after,
.pm-v2 .psc-gate__copy:is(:disabled, [aria-disabled="true"])::after,
.pm-v2 .generate-back-to-top[aria-disabled="true"]::after {
	content: none;
	animation: none;
}

/* =============================================================== breakpoints = */

/*
 * >= 640px the label is hidden (it already is, on every surface) and the field and the
 * button share one row — the form is a flex row at every width now, so there is nothing
 * to restack. Below 640px the control keeps the same single-row shape and simply shrinks
 * the button's horizontal padding, so even a 360px viewport fits field + button + border
 * without a horizontal scrollbar.
 */
@media (max-width: 639.98px) {
	.pm-v2 .pm-searchform .pm-searchform__submit,
	.pm-v2 .pm-searchform button[type="submit"],
	.pm-v2 .pm-searchform input[type="submit"] {
		padding-inline: var(--sp-3);
	}
}
