/* =========================================================================
 * G4U — RUCH
 *
 * Teza: strona rysuje własną strukturę. Skoro całą kompozycję niosą włosowe
 * linie, to one są bohaterem ruchu — linia sekcji kreśli się od lewej,
 * a treść dosiada się chwilę po niej. Hero składa tożsamość oddziału
 * i domyka ją indygo kropką (jedyny teatralny gest — kropka to znak marki),
 * fakty się doliczają (motion.js), pas partnerów powoli dryfuje.
 *
 * Zasady:
 *  - Bez JS strona jest kompletna i nieruchoma: każdy stan ukryty istnieje
 *    wyłącznie pod `html.g4u-motion`, którą nadaje assets/js/motion.js.
 *    Wyjątkiem jest wejście hero — czysty CSS, działa zawsze i zawsze
 *    kończy się stanem widocznym.
 *  - `prefers-reduced-motion` honorowane dwukrotnie: kill-switch w base.css
 *    (czasy → 0.01ms) i wcześniejsza rezygnacja w motion.js (klasa nie
 *    zostaje nadana, więc nic nie jest ukrywane ani nie dryfuje).
 *  - Wyłącznie transform i opacity; maska na pasie partnerów to zarządzanie
 *    światłem, nie efekt.
 *
 * Zbudowane wyłącznie na tokenach z tokens.css.
 * ========================================================================= */

/* --- Hero: złożenie tożsamości oddziału -----------------------------------
 * Kolejne wersy wchodzą co pół / półtora / dwa i pół taktu. Kropka stawia
 * się na końcu, kiedy tytuł już osiadł — jak kropka nad i.
 */
@keyframes g4u-rise-in {
	from { opacity: 0; transform: translateY(var(--g4u-rise)); }
	to   { opacity: 1; transform: none; }
}

@keyframes g4u-period-in {
	from { opacity: 0; transform: scale(0); }
	to   { opacity: 1; transform: none; }
}

@keyframes g4u-settle-in {
	from { opacity: 0; transform: scale(1.03); }
	to   { opacity: 1; transform: none; }
}

.g4u-hero__title,
.g4u-hero__lead,
.g4u-hero__meta,
.g4u-event__overline,
.g4u-event__title {
	animation: g4u-rise-in var(--g4u-dur-reveal) var(--g4u-ease-out) both;
}

/* --g4u-lead (domyślnie 0) przesuwa cały takt hero — ustawia go kurtyna
   pierwszego wejścia, żeby hero ruszało dopiero, gdy ona się unosi. */
.g4u-hero__title,
.g4u-event__overline { animation-delay: calc(var(--g4u-lead, 0ms) + var(--g4u-hero-step) / 2); }

.g4u-hero__lead,
.g4u-event__title    { animation-delay: calc(var(--g4u-lead, 0ms) + var(--g4u-hero-step) * 1.5); }

.g4u-hero__meta      { animation-delay: calc(var(--g4u-lead, 0ms) + var(--g4u-hero-step) * 2.5); }

.g4u-hero__period {
	display: inline-block;
	transform-origin: 25% 75%;
	animation: g4u-period-in var(--g4u-dur-enter) var(--g4u-ease-out) calc(var(--g4u-lead, 0ms) + var(--g4u-hero-step) * 3.5) both;
}

/* Obraz osiada dłużej niż tekst — skala wraca do 1, figura przycina nadmiar. */
.g4u-hero__image,
.g4u-event__hero { overflow: hidden; }

.g4u-hero__image img,
.g4u-event__hero img {
	animation: g4u-settle-in var(--g4u-dur-settle) var(--g4u-ease-out) calc(var(--g4u-lead, 0ms) + var(--g4u-hero-step) * 2) both;
}

/* Sprężyny wejścia hero: wersy dosiadają się z fizycznym wyhamowaniem,
   kropka stawia się z wyraźnym pop (przestrzał skali z krzywej). */
@supports (animation-timing-function: linear(0, 1)) {
	.g4u-hero__title,
	.g4u-hero__lead,
	.g4u-hero__meta,
	.g4u-event__overline,
	.g4u-event__title {
		animation-timing-function: var(--g4u-ease-spring);
	}

	.g4u-hero__period {
		animation-timing-function: var(--g4u-ease-pop);
	}
}

/* --- Kurtyna pierwszego wejścia ---------------------------------------------
 * Sygnet powitania: brand z indygo kropką → włosowa linia → „Oddział {miasto}",
 * potem kurtyna unosi się i oddaje ruch hero (czekającemu na --g4u-lead).
 * Bez html.g4u-intro-on (bramka w <head>, raz na sesję) kurtyny nie ma wcale.
 * Cała sekwencja to animacje CSS z fill-mode — kończy się stanem ukrytym
 * niezależnie od JS, a pointer-events: none gwarantuje, że nawet w trakcie
 * niczego nie blokuje.
 */
.g4u-intro { display: none; }

html.g4u-intro-on { --g4u-lead: calc(var(--g4u-intro-hold) + var(--g4u-hero-step) / 2); }

html.g4u-intro-on .g4u-intro {
	position: fixed;
	inset: 0;
	z-index: 1200;
	display: flex;
	align-items: center;
	justify-content: center;
	background-color: var(--g4u-bg);
	pointer-events: none;
	animation: g4u-intro-out var(--g4u-intro-exit) var(--g4u-ease-out) var(--g4u-intro-hold) both;
}

html.g4u-intro-on .g4u-intro__mark {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--g4u-space-small);
	margin: 0;
	animation: g4u-intro-fade var(--g4u-dur-icon) ease calc(var(--g4u-intro-hold) - var(--g4u-hero-step)) both;
}

html.g4u-intro-on .g4u-intro__brand {
	color: var(--g4u-heading);
	font-family: var(--g4u-font-heading);
	font-size: var(--g4u-h2-size);
	font-weight: var(--g4u-weight-bold);
	letter-spacing: -.02em;
	line-height: 1;
	animation: g4u-rise-in var(--g4u-dur-reveal) var(--g4u-ease-out) var(--g4u-hero-step) both;
}

html.g4u-intro-on .g4u-intro__period {
	display: inline-block;
	color: var(--g4u-accent);
	transform-origin: 25% 75%;
	animation: g4u-period-in var(--g4u-dur-enter) var(--g4u-ease-out) calc(var(--g4u-hero-step) * 3.5) both;
}

html.g4u-intro-on .g4u-intro__rule {
	width: var(--g4u-intro-rule-w);
	height: 1px;
	background-color: var(--g4u-border);
	transform: scaleX(0);
	transform-origin: left center;
	animation: g4u-rule-in var(--g4u-dur-reveal) var(--g4u-ease-out) calc(var(--g4u-hero-step) * 2) both;
}

html.g4u-intro-on .g4u-intro__label {
	color: var(--g4u-text-muted);
	font-family: var(--g4u-font-ui);
	font-size: var(--g4u-meta-size);
	letter-spacing: .16em;
	text-transform: uppercase;
	animation: g4u-rise-in var(--g4u-dur-reveal) var(--g4u-ease-out) calc(var(--g4u-hero-step) * 3) both;
}

@keyframes g4u-rule-in {
	to { transform: scaleX(1); }
}

@keyframes g4u-intro-fade {
	to { opacity: 0; }
}

@keyframes g4u-intro-out {
	to { transform: translateY(-100%); visibility: hidden; }
}

@supports (animation-timing-function: linear(0, 1)) {
	html.g4u-intro-on .g4u-intro__brand,
	html.g4u-intro-on .g4u-intro__label { animation-timing-function: var(--g4u-ease-spring); }

	html.g4u-intro-on .g4u-intro__period { animation-timing-function: var(--g4u-ease-pop); }
}

@media print {
	.g4u-intro { display: none; }
}

/* --- Sekcje: linia kreśli się, treść dosiada -------------------------------
 * Pod html.g4u-motion linię sekcji rysuje ::before (transform zamiast
 * border-color, więc bez przeliczania układu); border zostaje w miejscu,
 * ale przezroczysty — rytm i wymiary się nie zmieniają.
 */
html.g4u-motion .g4u-section > .g4u-container { position: relative; }

html.g4u-motion .g4u-section:not(.g4u-section--hero):not(.g4u-section--event-hero) > .g4u-container {
	border-top-color: transparent;
}

html.g4u-motion .g4u-section:not(.g4u-section--hero):not(.g4u-section--event-hero) > .g4u-container::before {
	content: "";
	position: absolute;
	top: -1px;
	left: 0;
	right: 0;
	height: 1px;
	background-color: var(--g4u-border);
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform var(--g4u-dur-line) var(--g4u-ease-out);
}

html.g4u-motion .g4u-section.is-inview > .g4u-container::before { transform: scaleX(1); }

/* Jednostki ujawniania wyznacza motion.js (atrybut na elemencie). Każda
   jednostka odsłania się osobno, tuż zanim wejdzie w kadr — indeks kaskady
   (--g4u-i) dostają w chwili wyzwolenia tylko elementy wchodzące razem
   w jednej paczce, więc pojedynczy wiersz nigdy nie czeka na cudzy delay.
   Ukrycie istnieje tylko pod .g4u-motion — bez JS nic nie znika. */
html.g4u-motion [data-g4u-reveal] {
	opacity: 0;
	transform: translateY(var(--g4u-rise-el, var(--g4u-rise)));
	transition:
		opacity var(--g4u-dur-reveal) var(--g4u-ease-out),
		transform var(--g4u-dur-reveal) var(--g4u-ease-out);
	transition-delay: calc(var(--g4u-reveal-delay) + var(--g4u-i, 0) * var(--g4u-stagger-step));
}

/* Wiersze tekstowe unoszą się z mniejszego dystansu — krótsza droga
   czyta się jako szybsza odpowiedź. */
html.g4u-motion .g4u-event-row[data-g4u-reveal],
html.g4u-motion .g4u-event__meta-row[data-g4u-reveal] {
	--g4u-rise-el: var(--g4u-rise-sm);
}

html.g4u-motion [data-g4u-reveal].is-in {
	opacity: 1;
	transform: none;
}

/* Sprężyna zamiast stałej krzywej — mierzalnie ten sam koszt (transform/
   opacity na kompozytorze), ale ruch ma wyhamowanie z fizyki, nie z tabeli.
   Przeglądarki bez linear() zostają na wykładniczym ease-out. */
@supports (transition-timing-function: linear(0, 1)) {
	html.g4u-motion [data-g4u-reveal] {
		transition-timing-function: var(--g4u-ease-spring);
	}
}

/* --- Partnerzy: pas dryfuje -------------------------------------------------
 * Druga kopia listy (aria-hidden) istnieje tylko dla domknięcia pętli;
 * bez ruchu jest schowana i pas wygląda jak statyczne rzędy z landing.css.
 * Dryf zatrzymuje wskazanie, fokus i zniknięcie sekcji z ekranu.
 */
.g4u-partners__list--dup { display: none; }

@keyframes g4u-drift {
	to { transform: translateX(-50%); }
}

html.g4u-motion .g4u-partners__viewport.is-marquee {
	position: relative;
	overflow: hidden;
}

/* Wygaszenie krawędzi nakładkami gradientowymi zamiast maski: maska na
   stale animowanym pasie wymusza droższą kompozycję w każdej klatce,
   a nakładki są malowane raz. Tło sekcji jest jednolite, więc efekt
   jest nieodróżnialny. */
html.g4u-motion .is-marquee::before,
html.g4u-motion .is-marquee::after {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	width: var(--g4u-fade-w);
	z-index: 1;
	pointer-events: none;
}

html.g4u-motion .is-marquee::before {
	left: 0;
	background: linear-gradient(to right, var(--g4u-bg), transparent);
}

html.g4u-motion .is-marquee::after {
	right: 0;
	background: linear-gradient(to left, var(--g4u-bg), transparent);
}

html.g4u-motion .is-marquee .g4u-partners__track {
	display: flex;
	width: max-content;
	animation: g4u-drift var(--g4u-dur-drift) linear infinite;
	will-change: transform;
}

html.g4u-motion .is-marquee .g4u-partners__list {
	display: flex;
	flex-wrap: nowrap;
	justify-content: flex-start;
	gap: var(--g4u-space-large);
	padding-right: var(--g4u-space-large);
}

html.g4u-motion .is-marquee .g4u-partners__list--dup { display: flex; }

html.g4u-motion .is-marquee .g4u-partner__plate { white-space: nowrap; }

html.g4u-motion .is-marquee:hover .g4u-partners__track,
html.g4u-motion .is-marquee:focus-within .g4u-partners__track { animation-play-state: paused; }

html.g4u-motion .g4u-section--partners:not(.is-onscreen) .g4u-partners__track { animation-play-state: paused; }

/* Druk dostaje dokument w całości: bez odsłon, z narysowanymi liniami. */
@media print {
	html.g4u-motion [data-g4u-reveal] { opacity: 1; transform: none; }
	html.g4u-motion .g4u-section > .g4u-container { border-top-color: var(--g4u-border); }
	html.g4u-motion .g4u-section > .g4u-container::before { content: none; }
	html.g4u-motion .g4u-partners__track { animation: none; }
}

/* --- Mikro-feedback ----------------------------------------------------------
 * Ramka paska biletowego reaguje na wskazanie — jedyna ramka na stronie
 * prowadzi do zakupu, więc wolno jej odpowiedzieć.
 */
.g4u-ticket-bar { transition: border-color var(--g4u-dur-hover) var(--g4u-ease-out); }

.g4u-ticket-bar:hover,
.g4u-ticket-bar:focus-within { border-color: var(--g4u-border-hover); }
