/*
Theme Name: Forge
Theme URI: https://example.com/forge
Author: Przemek
Author URI: https://example.com
Description: Reusable full-site-editing block theme for small-business sites across six niches (local services, beauty/wellness, food, freelance professionals, creative portfolio, single-product landing). Layout is built only from core blocks; all styling comes from theme.json presets.
Requires at least: 6.6
Tested up to: 6.6
Requires PHP: 7.4
Version: 0.6.3
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: forge
Tags: full-site-editing, block-patterns, blog, portfolio, one-column, two-columns, custom-colors, custom-menu, editor-style, featured-images, style-variations
*/

/* Forge keeps CSS to a minimum. All design tokens live in theme.json. */

/*
 * .forge-badge — small pill label (e.g. "Promocja -20%", "Najczęściej wybierany").
 * Exists only because the readable text color on top of `accent` differs per style
 * variation (contrast vs base) and that per-variant choice can't be expressed through
 * a block's standard color attributes — it's driven by theme.json's `--wp--custom--badge-text`,
 * computed per style variation (see CLAUDE.md section 4, "Zasady tokenów kolorystycznych").
 * Usage: Paragraph block with {"className":"forge-badge","backgroundColor":"accent"}.
 */
.forge-badge {
	display: inline-block;
	font-weight: 700;
	padding: 0.35em 0.9em;
	border-radius: var(--wp--custom--radius--full);
	color: var(--wp--custom--badge-text);
}

/*
 * .forge-check-list — List block used as a checklist, where each item's own "✓ " text
 * is the marker. Without this, the browser's default disc bullet renders alongside it
 * (bullet + ✓ on every line) — core/list has no block-editor control for list-style-type,
 * so this is a minimal, reusable exception (same justification as .forge-badge above).
 * Usage: List block with {"className":"forge-check-list"}.
 */
.forge-check-list {
	list-style: none;
	padding-left: 0;
}

/*
 * .forge-faq-item — Details block styled as a bootstrap-like accordion card: bordered,
 * rounded, with a distinct background for the question (<summary>, styled here — a rich
 * text attribute, not a block we can wrap) versus the answer (a real Group block with its
 * own backgroundColor/padding — not a CSS hack, see pattern files). `display: flex` on
 * <summary> already drops the native disclosure triangle (no ::marker pseudo-element —
 * CLAUDE.md section 4 explicitly rejected that route). The chevron is a single "▼"
 * character rotated -90° (pointing right) when closed and 0° (pointing down) when open,
 * animated with a CSS transition — pure CSS, no JS. Colored `primary`, never `accent`
 * (accent is decoration-only per the color rules in CLAUDE.md section 1 — it fails
 * contrast as text on base/surface).
 * Usage: Details block with {"className":"forge-faq-item"}; summary text ending with
 * `<span class="forge-icon-arrow" style="color:var(--wp--preset--color--primary)">▼</span>`;
 * the answer's outer block wrapped in a Group with backgroundColor "base" and its own
 * padding, so it visually reads as a separate panel from the summary row.
 */
.forge-faq-item {
	border: 1px solid var(--wp--preset--color--muted);
	border-radius: var(--wp--custom--radius--md);
	overflow: hidden;
}
.forge-faq-item + .forge-faq-item {
	margin-top: 0.75rem;
}
.forge-faq-item > summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1em;
	list-style: none;
	cursor: pointer;
	background: var(--wp--preset--color--surface);
	padding: 1rem 1.25rem;
}
.forge-faq-item .forge-icon-arrow {
	display: inline-block;
	flex-shrink: 0;
	font-size: 0.85em;
	transform: rotate(-90deg);
	transition: transform 0.2s ease;
}
.forge-faq-item[open] .forge-icon-arrow {
	transform: rotate(0deg);
}

/*
 * Przyciski na mobile — pełna szerokość. Czwarty (po .forge-badge, .forge-check-list,
 * .forge-faq-item) udokumentowany wyjątek CSS: theme.json nie ma media queries, a to
 * jest zachowanie czysto responsywne, którego nie da się zapisać atrybutami bloku
 * (atrybut `width:100` na przycisku działa na KAŻDEJ szerokości, nie tylko mobilnej).
 * Zakres: cała strona OPRÓCZ NAGŁÓWKA — treść, stopka, sekcje, karty
 * (ustalone 2026-10-01: najpierw rozszerzone z `main` na wszystko, potem nagłówek
 * wyłączony z powrotem, bo CTA na całą szerokość podbijało go na 375 px o 45–48 px,
 * schodząc do własnego wiersza: beauty/landing/wedding 149→197, local 182→227).
 *
 * POTRZEBNE SĄ DWIE REGUŁY, nie jedna. Rdzeń WP ustawia już
 * `.wp-block-button__link{width:100%}`, więc sam przycisk rozciąga się do swojego
 * kontenera (`flex-basis` na `.wp-block-button`). Tyle NIE WYSTARCZA wszędzie tam,
 * gdzie `.wp-block-buttons` siedzi w rzędzie flex obok innej treści — np. „Zobacz
 * portfolio" w kolumnie media+tekst miało 144 px. Taki kontener jest szerokości
 * WŁASNEJ treści, więc przycisk rozciągał się do 100% czegoś wąskiego. Druga
 * reguła rozciąga więc sam KONTENER.
 *
 * Nagłówek wyłączany jest JAWNYM COFNIĘCIEM obu reguł, nie zawężeniem selektora:
 * „wszystko poza potomkami nagłówka" nie da się w CSS zapisać wprost, a `:not()`
 * na przodku wymagałoby `:has()` i czytałoby się gorzej niż dwie linijki resetu.
 *
 * NIE DOTYCZY przycisków WooCommerce („Dodaj do koszyka") — to `.button`, nie
 * blok. Sprawdzone i tak nie wymaga reguły: na 375 px siatka produktów ma dwie
 * kolumny po 157 px, a przycisk ma 152 px, czyli i tak wypełnia swoją komórkę.
 */
@media (max-width: 599px) {
	.wp-block-buttons {
		flex-basis: 100%;
		width: 100%;
	}
	.wp-block-buttons > .wp-block-button {
		flex-basis: 100%;
	}

	/* Nagłówek zostaje jak był: przycisk CTA ma być mały i siedzieć w jednym
	   rzędzie z logo i hamburgerem, inaczej pasek rośnie o ~1/4. */
	header .wp-block-buttons,
	header .wp-block-buttons > .wp-block-button {
		flex-basis: auto;
		width: auto;
	}
}

/* Inicjały w okrągłym awatarze (opinie, zespół) oraz krótkie etykiety w kółkach.
   PIĄTY udokumentowany wyjątek CSS — po .forge-badge, .forge-check-list,
   .forge-faq-item i przyciskach pełnej szerokości na mobile.

   Powód: rdzeń WP ustawia na kolumnach
       .wp-block-column { min-width: 0; overflow-wrap: break-word; word-break: break-word }
   `word-break: break-word` łamie W ŚRODKU WYRAZU, a `min-width: 0` pozwala kolumnie
   zwęzić się poniżej szerokości treści. Dwuliterowy monogram „AW" rozjeżdżał się
   więc na dwa wiersze w węższych kartach, a w szerszych nie — stąd wrażenie
   niekonsekwencji. Tego nie da się wyrazić atrybutami bloku: `word-break` nie ma
   kontrolki w edytorze, a inline style w markupie patternu zepsułby walidację. */
.forge-initials {
	word-break: keep-all;
	overflow-wrap: normal;
	hyphens: none;
}

/* ───────────────────────────────────────────────────────────────────────────
   DELIKATNE ANIMACJE — szósty udokumentowany wyjątek CSS.

   Zero JavaScriptu, więc twarda zasada nr 3 zostaje nienaruszona: czysty CSS
   w `style.css`, nie skrypt w patternie. Patterny nie wiedzą o tych regułach.

   ZASADA NACZELNA: animujemy WYŁĄCZNIE reakcje na kursor. Żadna z tych reguł
   nie jest w stanie ukryć treści — w najgorszym razie element po prostu się
   nie rusza. To nie jest nadmierna ostrożność, tylko wniosek z dwóch odrzuconych
   podejść (2026-09-30, mierzone w Chrome na demo dentysty):

   1. ODRZUCONE — pojawianie się sekcji sterowane przewijaniem
      (`animation-timeline: view()`). Wygląda dobrze w środku strony, ale sekcje
      przy DOLE dokumentu nie mają już dokąd przewijać, żeby dokończyć fazę
      `entry`, i zostają trwale na `opacity: 0`. Ostatnia sekcja utknęła na
      progresie 0.00 nawet po przewinięciu na sam dół i po
      `scrollIntoView({block:"center"})`. Zmiana zakresu na `cover 0% cover 15%`
      ani `entry 0% entry 25%` tego nie naprawiła.

   2. ODRZUCONE — wejście sekcji przy załadowaniu (animacja czasowa z `both`).
      Gdy zegar dokumentu nie wystartuje, treść zostaje na stanie początkowym,
      czyli `opacity: 0`. Zaobserwowane wprost: przy karcie w tle
      (`document.visibilityState === "hidden"`) Chrome zamraża `DocumentTimeline`
      na zerze i CAŁA strona renderuje się pusta.

   Wspólny mianownik obu: `opacity: 0` w stanie początkowym animacji oznacza, że
   każda awaria mechanizmu animacji = niewidoma treść na stronie klienta. Cena
   nie do przyjęcia za efekt ozdobny.

   UWAGA METODOLOGICZNA: `getComputedStyle()` NIE pokazuje stanu animacji
   sterowanej przewijaniem — liczy się na kompozytorze i zwracana jest wartość
   bazowa. Przez chwilę wyglądało to jak „animacja w ogóle nie działa".
   Do sprawdzania: `element.getAnimations()[0].effect.getComputedTiming()`.

   Wszystko pod `prefers-reduced-motion: no-preference` — użytkownik z redukcją
   ruchu (migreny, choroba lokomocyjna, padaczka światłoczuła) nie dostaje ani
   jednej animacji.
   ─────────────────────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: no-preference) {

	/* Przyciski: lekkie uniesienie i cień. Cień z presetu, nie z palca. */
	.wp-block-button__link {
		transition: transform 0.18s ease, box-shadow 0.18s ease;
	}
	.wp-block-button__link:hover {
		transform: translateY(-2px);
		box-shadow: var(--wp--preset--shadow--md);
	}
	.wp-block-button__link:active {
		transform: translateY(0);
	}

	/* Linki tekstowe w treści: podkreślenie wyjeżdżające od lewej. Zrobione
	   gradientem tła, NIE pseudo-elementem (zakazany w hard rule 3).
	   `currentColor` zamiast koloru z palety — działa w każdym wariancie. */
	:where(.entry-content) a:not(.wp-block-button__link):not([class*="wp-block-navigation"]) {
		background-image: linear-gradient(currentColor, currentColor);
		background-repeat: no-repeat;
		background-position: 0 100%;
		background-size: 0% 1px;
		transition: background-size 0.25s ease;
	}
	:where(.entry-content) a:not(.wp-block-button__link):not([class*="wp-block-navigation"]):hover {
		background-size: 100% 1px;
	}

	/* Karty z cieniem (cenniki, panele, karty zespołu): subtelne uniesienie. */
	.wp-block-group[style*="box-shadow"] {
		transition: transform 0.2s ease, box-shadow 0.2s ease;
	}
	.wp-block-group[style*="box-shadow"]:hover {
		transform: translateY(-3px);
	}

	/* Kafle galerii — zdjęcie lekko przybliża się pod kursorem. Skalujemy sam
	   `<img>`, który ma własny promień i `object-fit`, więc nie wychodzi poza
	   swój kształt i nie potrzebuje przycinania na rodzicu. */
	.wp-block-image img {
		transition: transform 0.35s ease;
	}
	.wp-block-image:hover img {
		transform: scale(1.02);
	}
}

/* ───────────────────────────────────────────────────────────────────────────
   „PŁYWAJĄCY" NAGŁÓWEK — siódmy udokumentowany wyjątek CSS.

   Przyklejanie nagłówka jest FUNKCJĄ RDZENIA: Group ma wsparcie `position`
   (od WP 6.2), `theme.json` włącza je przez `settings.position.sticky`, a sam
   atrybut `style.position` renderuje serwer (`wp-includes/block-supports/
   position.php`) — do markupu patternu nie trafia ani jedna klasa, więc nie ma
   tu ryzyka walidacji bloku.

   Czego rdzeń NIE robi: nagłówek siedzi w części szablonu, a
   `core/template-part` ZAWSZE opakowuje swoją treść we własny element
   (`<header class="wp-block-template-part">`, bezwarunkowo — patrz
   `wp-includes/blocks/template-part.php`). Ten wrapper ma dokładnie wysokość
   nagłówka, a element `sticky` nie może wyjść poza pudełko rodzica — więc
   przyklejanie nie działało wcale. Zmierzone: po przewinięciu o 1200 px
   nagłówek miał `top: -1200`.

   Stąd ta reguła: przyklejamy WRAPPER, którego rodzicem jest `.wp-site-blocks`
   (cała strona), a nie sam nagłówek. Warunek `:has()` sprawia, że dotyczy to
   wyłącznie części szablonu, które SAME zadeklarowały `position: sticky` —
   nagłówki bez tego atrybutu zachowują się jak dotąd. `top` liczony tak samo
   jak w rdzeniu, żeby pasek administratora nie zasłonił nagłówka.
   ─────────────────────────────────────────────────────────────────────────── */
.wp-block-template-part:has(> .is-position-sticky) {
	position: sticky;
	top: calc(0px + var(--wp-admin--admin-bar--position-offset, 0px));
	z-index: 10;
}
