/**
 * Header Behaviours CSS (F1 + per-row).
 *
 * F1 — WCAG 2.4.11: ensures anchor-link focus targets land below any sticky
 * header. The JS ResizeObserver publishes --sgs-header-height; this rule
 * consumes it. Defaults to 0px when the property is not yet set (no jump).
 *
 * --sgs-header-height IS A BOTTOM EDGE, not a height. The two are the same
 * number only while the header sits at top:0; a floating ("pill") header is
 * offset from the top on purpose, and every consumer of this property wants the
 * distance to the header's LOWEST point. header-behaviours/view.js publishes
 * `Math.max( 0, pinnedTop + measuredHeight )` accordingly — the header's
 * computed `top` plus its observed border-box height, clamped as a sum so a
 * header pinned above the viewport edge publishes 0 rather than its height.
 * A header that is not pinned publishes 0. The name is kept because it is a
 * published contract read by the theme, two plugin stylesheets and two block
 * render paths.
 *
 * FALLBACK VALUES DIFFER ACROSS CONSUMERS AND THAT IS NOT INERT. This file and
 * theme/.../woocommerce.css fall back to 0px; assets/css/fx-motion-path.css
 * falls back to 80px. On sgs-theme no fallback ever fires, because
 * theme/.../utilities.css defines the property at :root. On a NON-SGS theme
 * utilities.css is absent and each fallback genuinely fires, so harmonising the
 * two numbers would move real rendering in one direction or the other. Left as
 * measured, deliberately, rather than "tidied" into a regression.
 *
 * Header-level sticky / transparent / shrink / hide-on-scroll and `contrastSafe`
 * are per-device {desktop,tablet,mobile} values, which a site-wide body class
 * cannot express ("scrim over the desktop hero, nothing on a phone"). Their CSS
 * is emitted PER-INSTANCE (per header block, scoped to its own uid) inside
 * `sgs/site-header/render.php`, gated per device tier via
 * `sgs_emit_tier_rules()` / `sgs_emit_tier_rules_map()` — see that file's
 * "Header-level tri-state behaviours" block for the full mechanism. State
 * classes (is-header-scrolled, is-header-shrunk, is-header-scrolling-down) are
 * toggled by view.js on the HEADER ELEMENT itself (not body).
 *
 * What lives here: F1 (scroll-padding-top) and the per-row behaviour rules
 * (rowTransparent/rowHideOnScroll/rowShrink — a SEPARATE, already-tiered
 * mechanism).
 *
 * All z-index values use the WP admin-bar safe range (< 99999) while staying
 * above typical theme content layers (100).
 *
 * @package SGS\Blocks
 */

/* -------------------------------------------------------------------------
 * F1 — Scroll-padding-top fix for anchor links (WCAG 2.4.11)
 * ---------------------------------------------------------------------- */

@property --sgs-header-height-live {
	syntax: '*';
	inherits: false;
}

:root {
	scroll-padding-top: var( --sgs-header-height-live, var( --sgs-header-height, 0px ) );
}

/* -------------------------------------------------------------------------
 * Header-level sticky / transparent / shrink / hide-on-scroll rules (including
 * the shrink @supports scroll-timeline pair and the hide-on-scroll transform)
 * are emitted per-instance in sgs/site-header/render.php — see the file
 * docblock above.
 *
 * HIDE-ON-SCROLL TRAVEL UNDER A FLOATING HEADER lives there too, and must stay
 * there. `translateY( -100% )` moves the header by its own height, which clears
 * the screen only while its top edge is at 0; a pill slid by its own height
 * leaves its top inset behind as a visible sliver of bar. The travel therefore
 * becomes
 *     translateY( calc( -100% - var( --sgs-header-float-inset-top, 0px ) ) )
 * with the inset published per device tier as a custom-property VALUE by
 * includes/sgs-header-float-css.php.
 *
 * ⛔ Do NOT move that rule into this shared stylesheet keyed on a float class.
 * render.php's per-tier rule is `.{uid}.sgs-site-header.is-header-scrolling-down`
 * at (0,3,0) and is emitted in an inline <style> AFTER this file loads, so a
 * same-specificity rule here would lose on source order and silently do
 * nothing — the "a rule that loses is indistinguishable from one that is
 * absent" failure. The travel is also per-tier, which a shared static rule
 * cannot express. Only the DOCUMENTATION belongs here.
 *
 * The per-row translate further down needs no equivalent: a row translating
 * -100% moves by its OWN height inside the header, which is correct whatever
 * the header's inset is.
 *
 * Top-layer note: a native `<dialog>` (sgs/nav-drawer) is NOT a descendant of
 * `header.sgs-site-header` — its parent chain is `BODY → HTML` — so a header
 * `translateY` transform (hide-on-scroll) cannot affect it, and any test that
 * transforms the header to check would pass vacuously, for the wrong reason.
 * The top-layer behaviour was tested against a REAL ancestor (`body`) and with a
 * negative control: an ordinary `position: fixed` probe moved -80px (proving the
 * measurement could detect the effect), while the open `<dialog>` moved 0 — a
 * top-layer `<dialog>` resolves against the viewport, not a transformed
 * ancestor.
 *
 * Unexercised: the transform was applied directly rather than by turning ON
 * "Hide on scroll", so that settings path has not been driven end-to-end. If
 * the drawer is ever nested inside the header, re-read this — the ancestry
 * premise changes, even though the top-layer result would stand.
 * ---------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
 * F2 — Contrast-safe fallback: NOT in this file.
 *
 * `contrastSafe` is a per-device {desktop,tablet,mobile} attribute, and a class
 * on <body> is site-wide — it cannot express "scrim over the desktop hero,
 * nothing on a phone", which is the case clients actually want.
 * `sgs/site-header/render.php` emits the three modes per tier as per-instance
 * uid-scoped CSS via `sgs_emit_tier_rules_map()`, including the scrim's
 * gradient, its `pointer-events:none` / `inset:0` / z-index layering and the
 * `> *` content lift.
 *
 * Two things worth carrying forward:
 *   - `shadow` is COSMETIC ONLY and never WCAG-conformant — a text-shadow's
 *     contrast against arbitrary imagery cannot be computed. Never describe it
 *     as meeting a contrast requirement.
 *   - `force-solid` paints nothing itself. A `background … !important` would be
 *     needed to out-rank the transparent rule, and per-tier that fight has no
 *     clean undo, so render.php resolves it earlier instead — force-solid simply
 *     means "do not go transparent at this tier".
 * ---------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
 * PER-ROW behaviours.
 *
 * A parallel mechanism, additive to the header-LEVEL per-instance rules
 * emitted by site-header/render.php — does NOT touch the shared wrapper
 * (SGS_Container_Wrapper) or any header-level uid selector. Each row
 * that carries `.sgs-row-behaviour` (emitted by sgs/site-header-row +
 * sgs/site-footer-row render.php) gets its OWN independent transparent /
 * hide-on-scroll state, toggled by src/header-behaviours/view.js
 * (initRowBehaviours). State classes (is-row-scrolled, is-row-hidden) are
 * applied to the ROW element itself, never to body or the header ancestor.
 *
 * Transitions use transform + background-color ONLY (motion-perf rule — never
 * filter or box-shadow, both repaint every frame; background-color is a cheap
 * paint on a small header/footer strip, matching the header-level rule).
 * ---------------------------------------------------------------------- */

.sgs-row-behaviour {
	transition: background-color 200ms var(--wp--custom--easing--ease, ease), transform 200ms var(--wp--custom--easing--ease, ease); /* sgs-motion: exact */
	will-change: transform;
}

/* Transparent-until-scrolled — row starts see-through, becomes the theme
 * surface colour once scrolled. Resting/scrolled pair mirrors the
 * header-level rule above but scoped to the row, not body/header.
 *
 * Keyed on `.is-row-transparent-active` (added by view.js ONLY on a device
 * tier where THIS row's transparent behaviour is ON) — NOT on the data-attr's
 * mere presence — so a row set "transparent on desktop only" stays solid on
 * mobile/tablet (a presence-only selector would make it transparent on every
 * tier permanently). */
.sgs-row-behaviour.is-row-transparent-active {
	background: transparent;
}

.sgs-row-behaviour.is-row-transparent-active.is-row-scrolled {
	background: var( --wp--preset--color--surface, #ffffff );
}

/* Hide-on-scroll-down — row slides off independently of any other row.
 *
 * This is the NOT-PINNED path; the collapse path below must not alter it
 * (FR-37-40). When the header IS pinned the collapse rules below take
 * over instead — see the block comment there for why translate is wrong in
 * that case. */
.sgs-row-behaviour[data-sgs-row-hide-on-scroll].is-row-hidden {
	transform: translateY( -100% );
}

/* Collapse-when-pinned (FR-37-40) — while the header is PINNED, a hidden row
 * leaves the flow entirely (height → 0) instead of translating.
 *
 * Why not translate when pinned: `transform` never reclaims an element's space
 * (MDN: "Whatever space the element takes up before you transform it, it will
 * still take up after"). A pinned header whose top row translates away would
 * therefore keep its full height with an empty gap where the row used to be,
 * for exactly that row's height — the header would not visibly shrink at all.
 * Collapsing removes the space, so the header genuinely shrinks to the rows
 * that remain, and its existing ResizeObserver re-publishes the new height,
 * which feeds the scroll-padding gate automatically.
 *
 * `is-row-collapse-mode` is added by view.js ONLY while the header is measured
 * as actually pinned AND the row is inside that header — never on a footer row
 * (footer rows get no sticky) and never on a non-pinned page.
 *
 * ⛔ There is deliberately NO height value here. A browser cannot animate from
 * `height: auto`, so view.js measures the row's real height, writes it as the
 * animation's start value, and drives it to 0 — the same reason the shrink
 * value is emitted per instance (FR-37-38). A fixed height in this shared
 * stylesheet could not know the row it is collapsing, which is precisely the
 * class of defect `check-shared-css-state-rules.js` exists to catch. The `0`
 * values below are exempt by construction: a collapse to nothing can never
 * grow a row, whatever its resting size. */
.sgs-row-behaviour.is-row-collapse-mode {
	overflow: hidden;
	transition: background-color 200ms var(--wp--custom--easing--ease, ease), transform 200ms var(--wp--custom--easing--ease, ease),
		block-size 200ms var(--wp--custom--easing--ease, ease), padding-top 200ms var(--wp--custom--easing--ease, ease),
		padding-bottom 200ms var(--wp--custom--easing--ease, ease); /* sgs-motion: exact */
}

/* Higher specificity (0,4,0) than the translate rule above (0,3,0) so the
 * collapse path wins deterministically rather than by source order. */
.sgs-row-behaviour[data-sgs-row-hide-on-scroll].is-row-collapse-mode.is-row-hidden {
	transform: none;
	min-block-size: 0; /* a row's own Minimum height would otherwise hold it open */
	padding-top: 0;
	padding-bottom: 0;
	border-block-width: 0;
}

/* Shrink-on-scroll — TRANSITION ONLY. There is deliberately NO
 * shrunk-value rule here.
 *
 * ⛔ DO NOT reintroduce an absolute shrunk value (e.g.
 * `padding-block: var(--wp--preset--spacing--10)`) in this file. It would win
 * at (0,3,0) over the wrapper's own `.sgs-container-<uid>` padding rule
 * (0,1,0), forcing EVERY shrunk row to the same absolute value regardless of
 * its resting padding: a row with no padding would sit at 0px at rest and jump
 * to 4px "shrunk" — it would GROW. A shrink must never increase, and an
 * absolute value in a shared stylesheet cannot know the resting value it is
 * supposed to reduce.
 *
 * The shrunk value is emitted PER INSTANCE by each row's render.php via
 * the shared `sgs_emit_responsive_css()` engine, as
 * `calc(<that row's own padding> / 2)` per tier — so it is proportional by
 * construction and can never exceed the resting value. A row with no padding
 * set emits nothing and simply does not change size (correct: there is no
 * space to reclaim).
 *
 * Keyed on `.is-row-shrink-active` (added by view.js ONLY on a device tier
 * where THIS row's shrink is ON) — never on the data-attr's mere presence, so
 * a row set "shrink on desktop only" keeps its full padding on mobile/tablet.
 *
 * The transition names the physical longhands the render.php rule actually
 * sets (`padding-top`/`padding-bottom`), NOT the `padding-block` shorthand —
 * relying on shorthand-to-logical-longhand expansion here is the "looks fine,
 * silently doesn't animate" class of defect.
 *
 * The chosen "hide on shrink" child is likewise handled per-instance:
 * render.php emits `.{uid}.is-row-shrunk #{anchor}{display:none}` into the
 * row's own scoped <style>, after re-validating the target server-side. */
.sgs-row-behaviour.is-row-shrink-active {
	transition: background-color 200ms var(--wp--custom--easing--ease, ease), transform 200ms var(--wp--custom--easing--ease, ease),
		padding-top 200ms var(--wp--custom--easing--ease, ease), padding-bottom 200ms var(--wp--custom--easing--ease, ease); /* sgs-motion: exact */
}

/* Reduced motion — the reset MUST repeat every selector that sets a transition
 * above, at matching specificity. `.sgs-row-behaviour` alone is (0,1,0) and
 * would LOSE to the shrink rule's (0,2,0), leaving a visitor who asked for no
 * motion still watching a 200ms padding animation. (Same discipline as the
 * hide-on-scroll reset further up, which repeats its full selector.) The
 * shrunk END STATE still applies — reduced motion removes the animation, never
 * the behaviour. */
@media ( prefers-reduced-motion: reduce ) {
	.sgs-row-behaviour,
	.sgs-row-behaviour.is-row-shrink-active,
	.sgs-row-behaviour.is-row-collapse-mode {
		transition: none;
	}
}
