:root {
  --bg: #0a0a0c;
  --bg-deep: #050506;
  --paper-ink: #eae7e0;
  --muted: #8b8a86;
  --accent: #caa968;
  --accent-rgb: 202, 169, 104;
  --vignette: #17151199;
  --surface: rgba(255, 255, 255, 0.04);
  --surface-hover: rgba(202, 169, 104, 0.15);
  --surface-border: rgba(234, 231, 224, 0.18);
  --surface-border-soft: rgba(234, 231, 224, 0.1);
  --shadow-strong: rgba(0, 0, 0, 0.55);
  --card-back-grad: linear-gradient(135deg, #171512, #232019);
  --icon-filter: invert(1);
  --item-w: clamp(210px, 28vw, 480px);
  --item-h: clamp(280px, 36vw, 600px);
}

:root[data-theme="light"] {
  --bg: #f3f1ec;
  --bg-deep: #fbfaf7;
  --paper-ink: #211f1b;
  --muted: #6d6a63;
  --accent: #a9793a;
  --accent-rgb: 169, 121, 58;
  --vignette: #caa96833;
  --surface: rgba(20, 18, 15, 0.035);
  --surface-hover: rgba(169, 121, 58, 0.12);
  --surface-border: rgba(20, 18, 15, 0.14);
  --surface-border-soft: rgba(20, 18, 15, 0.08);
  --shadow-strong: rgba(20, 18, 15, 0.18);
  --card-back-grad: linear-gradient(135deg, #efe9dd, #e2d9c6);
  --icon-filter: none;
}

* { box-sizing: border-box; }

html, body {
  min-height: 100%;
  margin: 0;
  overflow-x: hidden;
  background: radial-gradient(ellipse 70% 55% at 50% 30%, var(--vignette) 0%, transparent 60%), var(--bg-deep);
  color: var(--paper-ink);
  font-family: "Roboto", "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  cursor: none;
  transition: background-color 0.3s ease, color 0.3s ease;
}

html {
  overflow-y: scroll;
  /* scroll-behavior: smooth CELOWO wyłączone — płynność (kółko/touchpad/
     dotyk ORAZ skoki programowe typu scrollIntoView) daje teraz Lenis
     (patrz initSmoothScroll w script.js). Native smooth-behavior działałoby
     RÓWNOLEGLE z rAF-ową animacją Lenis i szarpałoby przewijaniem, bo oba
     mechanizmy próbowałyby naraz sterować tą samą pozycją scrolla. */
}

/* "body" miało tylko overflow-x ustawione, więc wg specyfikacji CSS
   overflow-y automatycznie liczyłby się jako "auto" — a to niejawnie
   robiło z body OSOBNY kontener scrolla, obok html. Dwa zagnieżdżone
   konteksty scrolla to klasyczna przyczyna psucia się position:sticky
   (m.in. #scene w karuzeli) w różnych przeglądarkach. Jawne "visible"
   tutaj gwarantuje, że jedynym kontenerem scrolla jest html. */
body {
  overflow-y: visible;
}

/* --- Customowy kursor (kropka globalnie, pierścień z tekstem tylko na rewolwerze) --- */

#custom-cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 150px;
  height: 150px;
  margin: -75px 0 0 -75px;
  pointer-events: none;
  z-index: 9999;
  opacity: 0;
  transform: translate(-9999px, -9999px);
  transition: opacity 0.25s ease;
}
#custom-cursor.is-active {
  opacity: 1;
}
#custom-cursor svg {
  width: 100%;
  height: 100%;
  animation: cursor-spin 10s linear infinite;
  transform-origin: 50% 50%;
  opacity: 0;
  transition: opacity 0.25s ease;
}
#custom-cursor.is-orbiting svg {
  opacity: 1;
}
#custom-cursor text {
  fill: var(--paper-ink);
  font-size: 13px;
  letter-spacing: 2px;
}
#custom-cursor .cursor-dot {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  transform: translate(-50%, -50%);
  transition: transform 0.2s ease;
}
#custom-cursor.is-dragging .cursor-dot,
#custom-cursor.is-hover-target .cursor-dot {
  transform: translate(-50%, -50%) scale(1.8);
}

@keyframes cursor-spin {
  to { transform: rotate(360deg); }
}

/* --- Rogi ekranu: logo domowe / logo marki --- */

.corner-link {
  position: fixed;
  top: clamp(10px, 3vw, 24px);
  z-index: 8000;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--surface-border);
  background: var(--surface);
  backdrop-filter: blur(4px);
  cursor: none;
  transition: background 0.2s, border-color 0.2s;
}
.corner-link:hover {
  background: var(--surface-hover);
  border-color: var(--accent);
}
.corner-link--home { left: clamp(10px, 4vw, 24px); }
.corner-link--brand { right: clamp(10px, 4vw, 24px); }

.corner-link img {
  width: 52%;
  height: 52%;
  object-fit: contain;
  filter: var(--icon-filter);
  opacity: 0.8;
  transition: opacity 0.2s ease;
}
.corner-link:hover img {
  opacity: 1;
}

/* --- Przełącznik jasny/ciemny motyw --- */

.theme-toggle {
  position: fixed;
  left: clamp(10px, 4vw, 24px);
  bottom: clamp(10px, 3vw, 24px);
  z-index: 8000;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--surface-border);
  background: var(--surface);
  backdrop-filter: blur(4px);
  color: var(--paper-ink);
  cursor: none;
  transition: background 0.2s, border-color 0.2s;
}
.theme-toggle:hover {
  background: var(--surface-hover);
  border-color: var(--accent);
}
.theme-toggle svg {
  position: absolute;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  transition: opacity 0.25s ease, transform 0.35s ease;
}
.theme-toggle .icon-sun circle {
  fill: currentColor;
  stroke: none;
}
.theme-toggle .icon-moon {
  fill: currentColor;
}
.theme-toggle .icon-moon {
  opacity: 0;
  transform: scale(0.5) rotate(-90deg);
}
.theme-toggle .icon-sun {
  opacity: 1;
  transform: scale(1) rotate(0deg);
}
:root[data-theme="light"] .theme-toggle .icon-sun {
  opacity: 0;
  transform: scale(0.5) rotate(90deg);
}
:root[data-theme="light"] .theme-toggle .icon-moon {
  opacity: 1;
  transform: scale(1) rotate(0deg);
}

/* --- Hero --- */

#hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  padding: 24px;
  text-align: center;
}

#hero-heading {
  position: relative;
  z-index: 2;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  gap: clamp(4px, 1vw, 12px);
  font-size: clamp(2.1rem, 8.5vw, 7rem);
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1.05;
  text-transform: uppercase;
  pointer-events: none;
}

.hero-line {
  display: block;
  max-width: 100%;
  min-width: 0;
}

.hero-word {
  font: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  color: var(--paper-ink);
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  pointer-events: none;
  transition: color 0.4s ease, text-shadow 0.4s ease;
}
.hero-word.is-active {
  color: var(--accent);
  text-shadow: 0 0 34px rgba(202, 169, 104, 0.5);
}

#hero-trail {
  position: absolute;
  top: 0;
  left: 0;
  width: 260px;
  height: 260px;
  margin: -130px 0 0 -130px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(202, 169, 104, 0.4) 0%, transparent 70%);
  filter: blur(18px);
  opacity: 0;
  transition: opacity 0.4s ease;
  pointer-events: none;
  z-index: 1;
  will-change: transform;
}

#hero-trail.is-active {
  opacity: 1;
}

#hero-slides {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}

.hero-slide {
  position: absolute;
  inset: 0;
}

/* efekty ambientowe słów hero (matrix, blueprint, kaleidoskop) — bez własnego
   tła (prześwituje tło strony); maska (patrz niżej) wygasza je przy krawędziach */
.matrix-rain,
.blueprint-canvas,
.kaleido-canvas {
  position: absolute;
  inset: 0;
  border-radius: 6px;
  opacity: 0;
  transition: opacity 1.2s ease;
  /* maska zamiast malowanej winiety: canvas sam staje się przezroczysty przy
     krawędziach, więc widać prawdziwe (nie przybliżone) tło strony pod spodem */
  -webkit-mask-image: radial-gradient(ellipse farthest-side at center, #000 60%, transparent 100%);
  mask-image: radial-gradient(ellipse farthest-side at center, #000 60%, transparent 100%);
}
.hero-slide.is-active .matrix-rain,
.hero-slide.is-active .blueprint-canvas,
.hero-slide.is-active .kaleido-canvas {
  opacity: 1;
}

/* --- Scena / karuzela --- */

/* wysoki "tor" daje dystans scrolla, w trakcie którego #scene (przypięte
   przez JS — patrz pinScene/unpinScene) przejeżdża przez wszystkie
   projekty. Wysokość toru = ile scrolla potrzeba na pełny przejazd od
   pierwszego do ostatniego projektu — im wyższy tor, tym wolniejszy,
   bardziej "mechaniczny" obrót; po jej przewinięciu scena ląduje na dole
   toru i strona przewija się dalej normalnie. Ujemny margines (nakładanie
   sceny na hero) jest na torze, nie na samym #scene. */
#scene-track {
  position: relative;
  height: 550vh;
  margin-top: clamp(-260px, -18vh, -120px);
}

#scene {
  /* domyślnie "relative" (stan "przed torem") — JS (pinScene/unpinScene w
     script.js) przełącza to na "fixed" (przypięte do viewportu w trakcie
     przejazdu) albo "absolute" (stan "po torze"), zamiast position:sticky,
     które okazało się zawodne w praktyce */
  position: relative;
  z-index: 5;
  width: 100%;
  height: 80vh;
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}

#carousel-stage {
  position: absolute;
  inset: 0;
  perspective: 1900px;
  perspective-origin: 50% 42%;
  touch-action: pan-y;
  cursor: none;
}

#carousel {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

.item {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--item-w);
  height: var(--item-h);
  display: flex;
  align-items: center;
  justify-content: center;
  will-change: transform, filter, opacity;
  transition: filter 0.15s linear;
}

.item img {
  /* kontener .item jest pionowy (węższy niż wysoki) — zdjęcie pionowe ma
     zbliżone proporcje do samego kontenera i przy width/height:100%
     wypełniało go niemal całkowicie, przez co wyglądało nieproporcjonalnie
     duże względem zdjęć poziomych (te "listwuje" object-fit:contain).
     Ograniczenie w obu wymiarach daje jednolity margines wokół KAŻDEGO
     zdjęcia, niezależnie od orientacji. */
  max-width: 70%;
  max-height: 70%;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 25px 45px var(--shadow-strong));
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none;
}

.item.is-active img {
  filter: drop-shadow(0 30px 60px rgba(202, 169, 104, 0.35));
}

.item.is-focused {
  transition: filter 0.4s ease;
}
.item.is-focused img {
  filter: drop-shadow(0 35px 70px rgba(202, 169, 104, 0.55));
}

/* --- Panel informacyjny --- */

#info-panel {
  /* #info-panel jest teraz dzieckiem #scene (żeby poruszał się razem z nim,
     niezależnie od tego, czy #scene jest w danej chwili "relative", "fixed"
     czy "absolute" — patrz pinScene/unpinScene w JS). position:absolute +
     top liczone od wysokości #scene (80vh), lekko podniesione (żeby nie
     "odklejało się" wizualnie od karuzeli). "left:0; right:0" (zamiast
     samego left+width) jest potrzebne, żeby "margin:0 auto" w ogóle miało
     jak wyliczyć wyśrodkowanie — przy position:absolute auto-marginesy
     działają tylko, gdy left I right są oba ustawione. */
  position: absolute;
  top: calc(100% - 70px);
  left: 0;
  right: 0;
  max-width: 640px;
  margin: 0 auto;
  padding: 24px 24px 40px;
  text-align: center;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
#info-panel.fading { opacity: 0; transform: translateY(8px); }

#info-index {
  display: inline-block;
  letter-spacing: 0.2em;
  font-size: 12px;
  color: var(--accent);
  margin-bottom: 10px;
}

#info-title {
  margin: 0 0 10px;
  font-size: clamp(20px, 3vw, 30px);
  font-weight: 600;
  letter-spacing: 0.02em;
}

#info-desc {
  margin: 0;
  font-size: 17px;
  line-height: 1.6;
  color: var(--muted);
}

#info-check {
  display: inline-block;
  margin-top: 20px;
  padding: 8px 20px;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--paper-ink);
  background: var(--surface);
  border: 1px solid var(--surface-border);
  border-radius: 999px;
  text-decoration: none;
  cursor: none;
  transition: background 0.2s, border-color 0.2s;
}
#info-check:hover {
  background: var(--surface-hover);
  border-color: var(--accent);
}

/* --- Wstęgi po karuzeli --- */

/* wysoki tor: pierwsza część dystansu to wjazd taśm (patrz JS,
   RIBBONS_ENTER_FRACTION — spowalnia sam wjazd), reszta to "trzymanie"
   ekranu w miejscu, zanim strona pojedzie dalej w dół — ten sam mechanizm
   przypinania (position:fixed sterowane z JS) co w karuzeli wyżej.
   margin-top: scena po zjechaniu z toru ląduje dokładnie na dole
   #scene-track (patrz unpinScene w JS), więc bez tego odstępu tor wstęg
   zaczynałby się od razu przy dolnej krawędzi karuzeli — stąd wyraźny
   odstęp tutaj, żeby "rewolwer" i wstęgi nie stykały się wizualnie. */
#ribbons-track {
  position: relative;
  height: 130vh;
  margin-top: clamp(100px, 16vh, 220px);
}

#ribbons {
  position: relative;
  z-index: 5;
  width: 100%;
  overflow: hidden;
  min-height: 70vh;
}

/* --slide: -1..0 (wjazd z lewej) albo 0..1 (wjazd z prawej) — ustawiane z
   JS (updateRibbonsReveal) 1:1 z pozycją scrolla. --rot różni kierunek
   pochylenia każdej taśmy, żeby się przecinały w literę X. Szerokość 130vw
   (zamiast dokładnie 100vw) daje zapas po bokach, żeby pochylona taśma
   nadal w pełni zakrywała ekran od krawędzi do krawędzi, a nie odsłaniała
   trójkątnych "dziur" w rogach — naprawdę potrzeba tu ok. 101vw (100vw /
   cos 7°), 130vw to bezpieczny zapas, ale CELOWO nieduży: im szersza taśma
   od szerokości ekranu, tym dłuższą drogę (patrz translateX niżej) musi
   przejechać, żeby w pełni wjechać/zjechać — a to właśnie wygląda jak
   "nadmuchiwanie" (przy 220vw droga była prawie 2x dłuższa niż trzeba, więc
   marquee tekstu w środku ginęło na tle samego rozrastania się paska). */
.ribbon {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 130vw;
  background: var(--accent);
  color: var(--bg-deep);
  /* boczny padding to widoczny "margines" przy krawędzi taśmy — .ribbon-clip
     (dziecko, patrz niżej) przycina tekst PRZED tym marginesem, więc ten pas
     koloru zawsze zostaje pusty, niezależnie od tego, co akurat przewija się
     w pętli marquee. Bez tego (samo overflow:hidden na .ribbon) tekst
     wjeżdżałby w padding, bo overflow:hidden przycina dopiero na zewnętrznej
     krawędzi paddingu, nie na krawędzi treści. */
  padding: 40px 60px;
  overflow: hidden;
  white-space: nowrap;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35);
  /* translateX działa TUTAJ w lokalnym układzie taśmy, przed rotate() — więc
     przesunięcie w poziomie na ekranie to (w przybliżeniu) translateX*cos(7°),
     nie translateX 1:1. Połowa własnej szerokości (130vw / 2 = 65vw) plus
     odległość od środka ekranu do krawędzi (50vw) daje ok. 115vw, o tyle
     trzeba przesunąć taśmę, żeby jej krawędź zjechała poza ekran — 140vw
     z zapasem. */
  transform: translate(-50%, -50%) rotate(var(--rot, -7deg)) translateX(calc(var(--slide, -1) * 140vw));
}

/* przycina marquee TUTAJ (na krawędzi obszaru treści), a nie na krawędzi
   paddingu .ribbon (patrz komentarz wyżej) — to właśnie robi z bocznego
   paddingu realny, zawsze pusty margines */
.ribbon-clip {
  overflow: hidden;
}

.ribbon--text {
  top: 42%;
  --rot: -7deg;
  z-index: 2; /* na wierzchu na skrzyżowaniu — loga mają iść "pod spodem" */
}

.ribbon--logos {
  top: 60%;
  --rot: 7deg;
  z-index: 1;
}

/* pętla marquee: zawartość jest w JS powielona dokładnie 2x (patrz
   buildRibbonContent), więc przesunięcie o -50% zawsze płynnie zapętla */
.ribbon-track {
  display: inline-flex;
  align-items: center;
  gap: 56px;
  animation: ribbon-marquee 24s linear infinite;
}
.ribbon--logos .ribbon-track {
  animation-duration: 30s;
  animation-direction: reverse;
}
@keyframes ribbon-marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .ribbon-track { animation: none; }
}

.ribbon-word {
  flex: 0 0 auto;
  font-size: clamp(28px, 3.8vw, 92px);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

/* separator między powtórzeniami frazy w pętli — "LOGO TO PODSTAWA · LOGO
   TO PODSTAWA · ..." zamiast kropki na końcu każdego powtórzenia */
.ribbon-dot {
  flex: 0 0 auto;
  font-size: clamp(28px, 3.8vw, 92px);
  font-weight: 700;
  opacity: 0.6;
}

.ribbon-logo {
  flex: 0 0 auto;
  display: block;
  width: 64px;
  height: 64px;
  background-color: var(--bg-deep);
  opacity: 0.9;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

@media (max-width: 640px) {
  .ribbon-word, .ribbon-dot { font-size: 28px; }
  .ribbon-logo { width: 44px; height: 44px; }
  .ribbon { padding: 20px 28px; }
}

/* --- Sekcja logotypów --- */

#logos-section {
  position: relative;
  max-width: 1100px;
  margin: 0 auto;
  /* wstęgi lądują (unpinRibbons "after") dokładnie na dole #ribbons-track,
     więc ten padding jest CAŁYM odstępem do bento — prawie zerowy, żeby
     loga były "przyklejone" do wstęg zaraz po zakończeniu ich animacji */
  padding: 12px 24px 100px;
  text-align: center;
}

/* fade zamiast twardego "hidden" — patrz showMemoryPanel/hideMemoryPanel w
   JS. "hidden" nadal usuwa element z layoutu/drzewa dostępności, ale
   dopiero PO zakończeniu tranzycji opacity (albo od razu, gdy panel ma się
   pokazać) */
#memory-status {
  margin: 32px 0 16px;
  font-size: 12px;
  letter-spacing: 0.1em;
  color: var(--accent);
  opacity: 0;
  transition: opacity 0.35s ease;
}
#memory-status.is-visible {
  opacity: 1;
}

#memory-controls {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin: 0;
  opacity: 0;
  transition: opacity 0.35s ease;
}
#memory-controls[hidden] {
  display: none;
}
#memory-controls.is-visible {
  opacity: 1;
}

#memory-controls button {
  padding: 8px 18px;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--paper-ink);
  background: var(--surface);
  border: 1px solid var(--surface-border);
  border-radius: 999px;
  cursor: none;
  transition: background 0.2s, border-color 0.2s;
}
#memory-controls button:hover {
  background: var(--surface-hover);
  border-color: var(--accent);
}

#logos-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 26px;
}
#logos-grid[hidden] {
  display: none;
}

/* --- Dynamiczna siatka logo (bento) --- */

#logo-showcase {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 26px;
  /* NIE "overflow: hidden" — kafle robią obrót 3D (rotateY + perspective) i
     przy takiej rotacji ich renderowany kształt bliżej 90° lekko wychodzi
     poza spoczynkowy prostokąt; z overflow:hidden na kontenerze ten margines
     był ucinany, widoczne jako "obcięte brzegi" w trakcie animacji */
  overflow: visible;
}
#logo-showcase[hidden] {
  display: none;
}

/* rozszczepienie kafla na 4 mniejsze rewersy (patrz splitTileOut/In w JS) —
   holder zajmuje dokładnie miejsce oryginalnego kafla, każdy kawałek to 1/4 */
.logo-split-holder {
  position: absolute;
  perspective: 900px;
  pointer-events: none;
  /* gdy JS przelicza pozycję/rozmiar po zmianie szerokości okna (patrz
     nasłuch "resize" w script.js), niech to będzie płynne przesunięcie,
     nie twardy przeskok w nowe miejsce */
  transition: left 0.25s ease, top 0.25s ease, width 0.25s ease, height 0.25s ease;
}
.logo-split-piece {
  position: absolute;
  box-sizing: border-box;
  width: 50%;
  height: 50%;
}
.logo-split-piece-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
}
.logo-split-piece-inner .card-back {
  position: absolute;
  inset: 0;
  transform: none;
  border-radius: 16px;
}

.logo-tile {
  min-width: 0;
  min-height: 0;
  border-radius: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.logo-tile--logo {
  position: relative;
  aspect-ratio: 1 / 1;
  cursor: none;
  perspective: 900px;
}

.logo-tile-flip {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.8s linear;
}

.logo-tile-face--front {
  background: var(--bg);
  border: 1px solid var(--surface-border-soft);
  padding: 24px;
  transition: background-color 0.3s ease, border-color 0.25s ease;
}
.logo-tile--logo:hover .logo-tile-face--front {
  border-color: var(--accent);
}

.logo-tile-flip .card-back {
  transform: rotateY(180deg);
}

/* logo jako maska (kształt SVG wypełniony aktualnym kolorem) zamiast <img> —
   w spoczynku ma kolor tekstu strony (jasny na ciemnym motywie, ciemny na
   jasnym), na hover/po trafieniu pary przechodzi na --accent. Współdzielone
   z .card-front w planszy memory (patrz niżej) */
.logo-mark {
  display: block;
  width: calc(76% * var(--logo-scale, 1));
  height: calc(76% * var(--logo-scale, 1));
  background-color: var(--paper-ink);
  opacity: 0.85;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  transition: background-color 0.3s ease, opacity 0.3s ease;
}
.logo-tile--logo:hover .logo-mark {
  background-color: var(--accent);
  opacity: 1;
}

.slot-big-a   { grid-column: 1 / 3; grid-row: 1 / 3; }
.slot-small-7 { grid-column: 3 / 4; grid-row: 1 / 2; }
.slot-small-8 { grid-column: 4 / 5; grid-row: 1 / 2; }
.slot-small-1 { grid-column: 3 / 4; grid-row: 2 / 3; }
.slot-small-2 { grid-column: 4 / 5; grid-row: 2 / 3; }
.slot-small-3 { grid-column: 1 / 2; grid-row: 3 / 4; }
.slot-small-4 { grid-column: 2 / 3; grid-row: 3 / 4; }
.slot-small-5 { grid-column: 1 / 2; grid-row: 4 / 5; }
.slot-small-6 { grid-column: 2 / 3; grid-row: 4 / 5; }
.slot-big-b   { grid-column: 3 / 5; grid-row: 3 / 5; }

/* --- Mini gra memory --- */

.memory-card {
  position: relative;
  aspect-ratio: 1 / 1;
  cursor: none;
  perspective: 800px;
}

.memory-card-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transition: transform 0.5s cubic-bezier(0.4, 0.2, 0.2, 1);
  transform-style: preserve-3d;
}

.memory-card.is-flipped .memory-card-inner,
.memory-card.is-matched .memory-card-inner {
  transform: rotateY(180deg);
}

.card-face {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 16px;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.card-back {
  background: var(--card-back-grad);
  border: 1px solid rgba(202, 169, 104, 0.25);
  transition: border-color 0.3s ease, background 0.3s ease;
}
.card-back-mark {
  display: block;
  width: 22%;
  height: 22%;
  background-color: var(--accent);
  opacity: 0.75;
  -webkit-mask-image: url("svg/Design.svg");
  mask-image: url("svg/Design.svg");
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

.card-front {
  background: var(--bg);
  border: 1px solid var(--surface-border-soft);
  transform: rotateY(180deg);
  padding: 24px;
  transition: background-color 0.3s ease;
}

.memory-card.is-matched .card-back {
  border-color: var(--accent);
}
.memory-card.is-matched .logo-mark {
  background-color: var(--accent);
  opacity: 1;
}

/* --- O mnie --- */

#about {
  /* TYMCZASOWO ukryte */
  display: none;
  position: relative;
  max-width: 720px;
  margin: 0 auto;
  padding: 120px 24px 40px;
  text-align: center;
}

#about h2 {
  margin: 0 0 20px;
  font-size: clamp(28px, 4vw, 44px);
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--paper-ink);
}

#about-photo {
  display: block;
  width: 140px;
  height: 140px;
  object-fit: cover;
  border-radius: 50%;
  margin: 0 auto 20px;
  border: 1px solid var(--surface-border);
}

.about-logo {
  display: block;
  max-width: 200px;
  max-height: 56px;
  width: auto;
  height: auto;
  margin: 28px auto;
  filter: var(--icon-filter);
  opacity: 0.85;
}

.about-name {
  margin: 0 0 36px;
  font-size: 13px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}

#about-content {
  text-align: left;
}
#about-content p {
  margin: 0 0 18px;
  font-size: 16px;
  line-height: 1.7;
  color: var(--muted);
}
#about-content p:last-child {
  margin-bottom: 0;
}

/* --- Kontakt i stopka --- */

#contact {
  position: relative;
  max-width: 640px;
  margin: 0 auto;
  padding: 100px 24px 80px;
  text-align: center;
}

#contact h2 {
  margin: 0;
  font-size: clamp(28px, 4vw, 44px);
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--paper-ink);
}

#contact-content {
  margin-top: 32px;
  min-height: 80px;
}

#contact-lead {
  margin: 0 0 20px;
  font-size: 16px;
  color: var(--muted);
}

#contact-email {
  display: inline-block;
  font-size: clamp(18px, 3vw, 26px);
  font-weight: 700;
  color: var(--paper-ink);
  text-decoration: none;
  border-bottom: 1px solid var(--surface-border);
  padding-bottom: 4px;
  cursor: none;
  transition: color 0.2s ease, border-color 0.2s ease;
}
#contact-email:hover {
  color: var(--accent);
  border-color: var(--accent);
}

#contact-social {
  display: flex;
  justify-content: center;
  gap: 16px;
  margin-top: 32px;
}
#contact-social a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--surface-border);
  background: var(--surface);
  cursor: none;
  transition: border-color 0.2s ease, background 0.2s ease;
}
#contact-social a:hover {
  border-color: var(--accent);
  background: var(--surface-hover);
}
#contact-social img {
  width: 20px;
  height: 20px;
  filter: var(--icon-filter);
  opacity: 0.85;
}

#site-footer {
  padding: 32px 24px;
  text-align: center;
  border-top: 1px solid var(--surface-border-soft);
}

#site-footer p {
  margin: 0;
  font-size: 12px;
  letter-spacing: 0.05em;
  color: var(--muted);
}

@media (max-width: 640px) {
  #about { padding: 80px 16px 24px; }
  #contact { padding: 56px 16px 56px; }
  #site-footer { padding: 24px 16px; }
  #hero { min-height: 85vh; }
  #scene { height: 62vh; }
  /* na wąskim ekranie zdjęcia w rewolwerze były niepotrzebnie małe (bazowy
     clamp liczony na 28vw/36vw celuje w desktop — na telefonie zwyczajnie
     nie ma tylu vw, więc zawsze lądował na dolnym progu, praktycznie stały
     rozmiar niezależnie od szerokości ekranu). Zamiast tego znacznie
     mocniejsze skalowanie względem vw, żeby zdjęcie realnie wypełniało
     większość szerokości ekranu. */
  :root {
    --item-w: clamp(260px, 74vw, 420px);
    --item-h: clamp(340px, 96vw, 546px);
  }
  /* drop-shadow liczeniowo jest podobny do blur() (rozmywa kanał alfa) —
     drogi filtr na 7 stale przesuwanych w 3D warstwach na słabszych GPU
     mobilnych; na desktopie zostaje (patrz też carouselBlurEnabled w JS,
     analogiczne wyłączenie blur() na kaflach rewolweru na tym samym progu) */
  .item img { filter: none; }
  #info-panel { padding: 0 16px 24px; }
  #logos-section { padding: 12px 16px 64px; }
  /* memory: 4x4 ograniczone do mniejszego z (szerokość, wysokość) ekranu — cała siatka mieści się na raz.
     #logo-showcase dostaje to samo ograniczenie, żeby kawałki z animacji
     rozszczepienia (patrz splitTileOut w JS) kończyły na takim samym
     rozmiarze co docelowe karty memory, zamiast się przy przełączeniu
     nagle kurczyć */
  #logos-grid,
  #logo-showcase {
    width: min(92vw, 58vh);
    margin: 0 auto;
  }
  #logos-grid {
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
  }
  .logo-tile-face--front { padding: 14px; }
  .card-front { padding: 8px; }
}

/* Siatka logo: zredukowany widok (6 małych kafli, bez dużych) dla wszystkich
   ekranów węższych niż tablet — pełny bento (10 kafli) dopiero od tabletu w górę.
   2 kolumny (nie 4, mimo że #logos-grid ma 4) celowo — przy 4 kolumnach kafle
   są za wąskie i ich rozszczepione kawałki zlewają się w nieczytelny tłok;
   akceptujemy niezgodność geometrii z planszą memory na rzecz czytelności
   samej animacji odwracania */
@media (max-width: 768px) {
  #logo-showcase { grid-template-columns: repeat(2, 1fr); gap: 16px; }
  .slot-big-a, .slot-big-b, .slot-small-7, .slot-small-8 {
    display: none;
  }
  .slot-small-1, .slot-small-2, .slot-small-3,
  .slot-small-4, .slot-small-5, .slot-small-6 {
    grid-column: span 1;
    grid-row: auto;
  }
}

@media (max-width: 400px) {
  #scene { height: 56vh; }
  #logos-grid,
  #logo-showcase {
    width: min(92vw, 52vh);
  }
  #logos-grid { gap: 16px; }
  .logo-tile-face--front { padding: 10px; }
  .card-front { padding: 6px; }
  #memory-controls button { padding: 7px 14px; font-size: 11px; }
}
