/* ============================================================================
   Gateway — SHARED BEHAVIOUR CSS (mechanics only; no design or lab-bar styling)
   ----------------------------------------------------------------------------
   Pairs with gateway-core.js — see _lib/CONTRACT.md. Everything below exists
   because a JS behaviour depends on it (scroll lock, carousel/marquee scroll
   mechanics, reduced-motion safety, a visually-hidden utility). No colour,
   type or spacing: that is every design's own job.
   ============================================================================ */

/* visually-hidden utility — GW.announce()'s live region; free for designs too */
.gw-vh {
	position: absolute !important;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
}

/* state elements the core toggles with the `hidden` attribute must stay hidden even when a design
   gives them a display value (e.g. `.x-capslock{display:block}` beats the UA's [hidden] rule), and a
   closed <dialog> must stay closed even if a design styles it `display:flex`. */
[data-gw-capslock][hidden], [data-gw-error-for][hidden], [data-gw-form-error][hidden],
[data-gw-success][hidden], [data-gw-captcha][hidden], [data-gw-xf-error][hidden],
[data-gw-live-error][hidden], [data-gw-lost-success][hidden], [data-gw-tabs] [role="tabpanel"][hidden] {
	display: none !important;
}
dialog[data-gw-dialog]:not([open]) { display: none !important; }

/* scroll lock while a mobile menu or a dialog/sheet is open (1.4 / 1.6) */
html.gw-menu-open,
html.gw-dialog-open {
	overflow: hidden;
	overscroll-behavior: contain;
}

/* carousel mechanics (1.9) — [data-gw-track] is a horizontal scroll-snap
   list; items snap to the start edge, or centre with data-gw-align="center"
   on the [data-gw-carousel] root. Item size/gap/etc. stay design-owned. */
[data-gw-track] {
	display: flex;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	-webkit-overflow-scrolling: touch;
}
[data-gw-track] > * { scroll-snap-align: start; flex: none; }
[data-gw-carousel][data-gw-align="center"] [data-gw-track] > * { scroll-snap-align: center; }

/* marquee mechanics (1.12) — the JS doubles the inner list's children once,
   so sliding that (now twice-as-wide) list by exactly -50% loops seamlessly.
   .is-running drives play/pause; reduced motion skips the clone entirely and
   falls back to a plain scrollable list (.gw-marquee-static). */
[data-gw-marquee] { overflow: hidden; }
[data-gw-marquee] > * {
	display: flex;
	width: max-content;
	animation-name: gw-marquee;
	animation-timing-function: linear;
	animation-iteration-count: infinite;
	animation-play-state: paused;
	animation-duration: var(--gw-marquee-dur, 20s);
}
[data-gw-marquee].is-running > * { animation-play-state: running; }
[data-gw-marquee].gw-marquee-static { overflow-x: auto; -webkit-overflow-scrolling: touch; }
@keyframes gw-marquee { to { transform: translateX(-50%); } }

/* reduced-motion safety net — belt-and-suspenders for any design CSS that
   forgets to gate its own animation on GW.motionOK(). .gw-reduce-motion is
   set by the core immediately (OS preference OR ?motion=reduce); the bare
   media query below just covers the instant before that JS class lands. */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		scroll-behavior: auto !important;
	}
}
.gw-reduce-motion *,
.gw-reduce-motion *::before,
.gw-reduce-motion *::after {
	animation-duration: 0.001ms !important;
	animation-iteration-count: 1 !important;
	transition-duration: 0.001ms !important;
	scroll-behavior: auto !important;
}
