/* ═══════════════════════════════════════════════════════════════════
   Restauri — coming-soon / waitlist landing page
   Palette, type and mood carried over verbatim from the teaser design.
   ═══════════════════════════════════════════════════════════════════ */

/* ── Fonts (bundled, variable woff2 — latin + latin-ext for Polish) ── */
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400 800; font-display: swap;
  src: url('../assets/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400 800; font-display: swap;
  src: url('../assets/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Sora'; font-style: normal; font-weight: 400 800; font-display: swap;
  src: url('../assets/fonts/sora-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Sora'; font-style: normal; font-weight: 400 800; font-display: swap;
  src: url('../assets/fonts/sora-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ── Tokens ── */
:root {
  --pine:   #0B0B0B;
  --panel:  #101211;
  --accent: #06C167;
  --accent-ink: #05a558;
  --alert:  #e5484d;   /* the page's single "no" colour: lock shakes + form errors */
  --cream:  #F9F9F9;
  --ink:    #14261D;
  --font-display: 'Sora', system-ui, sans-serif;
  --font-body: 'Inter', system-ui, sans-serif;
  --tap: 44px;   /* design system, tokens/layout.css — Apple HIG 44 / Material 48dp */
}

/* ── Touch targets ──────────────────────────────────────────────────────────
   The design system's rule (tokens/layout.css + guidelines/tap-targets.html):
   44px minimum, extended INVISIBLY so the visual size never changes.
   One deviation from their `.tap-target::after`, which is a flat 44×44: ours is
   max(100%, --tap). A fixed square suits their 40×40 icon button, but our footer
   links are 86×17 — a square would only thicken their middle and leave the ends
   17px tall. max() keeps whichever axis is already big enough and lifts the other. */
.tap-target { position: relative; }
.tap-target::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: max(100%, var(--tap));
  height: max(100%, var(--tap));
}


* { margin: 0; padding: 0; box-sizing: border-box; }

/* `[hidden]` to tylko `display: none` z arkusza PRZEGLĄDARKI, więc przebija je
   każdy selektor klasowy ustawiający display — element zostaje widoczny mimo
   atrybutu. Ta pułapka wyszła tu trzy razy (`.step-roles`, `.form-loading`,
   `.sugg-tab`: zakładka nie znikała po otwarciu panelu i centrowała się razem
   z nim). Jedna reguła globalna zamyka temat dla wszystkiego, co chowamy
   atrybutem; `!important`, bo musi wygrać z regułami komponentów. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  background: var(--pine);
  color: #fff;
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* ═══════════════════════════════════════════════════════════════════
   HERO — original teaser animation, shown in full (never cropped)
   The stage is 16:9; we size it to the largest 16:9 box that fits the
   viewport on BOTH axes, centred on black (letterboxed if needed).
   ═══════════════════════════════════════════════════════════════════ */
.hero {
  position: relative;
  height: 100vh;
  height: 100svh;
  background: #0B0B0B;
  overflow: hidden;
}
.hero-stage {
  position: absolute;
  inset: 0;
}
.hero-teaser {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  background: #0B0B0B;
}

/* scroll-down cue */
.scroll-cue {
  position: absolute;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  width: 46px;
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255,255,255,.85);
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.16);
  border-radius: 50%;
  backdrop-filter: blur(6px);
  z-index: 3;
  animation: bob 1.8s ease-in-out infinite;
  transition: background .2s, color .2s;
}
.scroll-cue:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
@keyframes bob { 0%,100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, 6px); } }

/* ── Hero start screen ──
   Statyczna warstwa nad sceną: rysuje się od pierwszej klatki, a teaser wchodzi
   pod nią (iframe wstrzykiwany przez JS) i przejmuje kadr crossfade'em. */
.hero-start {
  position: absolute;
  inset: 0;
  z-index: 2;                      /* nad iframe teasera, pod .scroll-cue (3) */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(26px, 3.4vh, 42px);
  text-align: center;
  padding: 0 24px;
  transition: opacity .45s ease;
}
.hero-start.leaving { opacity: 0; pointer-events: none; }
.hero-mark {
  width: clamp(168px, 24vw, 400px);
  height: auto;
}
.hero-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(30px, 5.2vw, 78px);
  line-height: 1.08;
  letter-spacing: -.02em;
  text-wrap: balance;
  color: var(--cream);
  max-width: 15ch;
}
.hero-title .accent { color: var(--accent); }
.hero-rule {
  width: clamp(64px, 6vw, 96px);
  height: clamp(4px, .35vw, 6px);
  border-radius: 3px;
  background: var(--accent);
}
.hero-ctas {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(14px, 1.2vw, 20px);
  margin-top: 4px;
}
/* przycisk play istnieje tylko dla JS — bez .js nie ma czego odpalić */
.hero-play { display: none; }
.js .hero-play {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: var(--tap);
  background: var(--accent);
  color: #fff;
  border: 0;
  border-radius: 999px;
  padding: .9em 1.65em;
  font-family: var(--font-display);
  font-size: clamp(15px, 1.05vw, 19px);
  font-weight: 700;
  cursor: pointer;
  transition: background .2s;
}
.js .hero-play:hover { background: var(--accent-ink); }
.hero-join {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: .9em 1.65em;
  border: 1px solid rgba(255,255,255,.22);
  border-radius: 999px;
  color: rgba(255,255,255,.85);
  text-decoration: none;
  font-family: var(--font-display);
  font-size: clamp(15px, 1.05vw, 19px);
  font-weight: 700;
  transition: border-color .2s, color .2s;
}
.hero-join:hover { border-color: var(--accent); color: var(--accent); }
/* Wejście zgrane z animowanym logotypem (restauri-wordmark-anim.svg): sygnet R
   rysuje się do ~1.1 s, "estauri" odsłania się 0.85-1.45 s, więc fade reszty
   startuje tuż przed domknięciem napisu — jedna scena, jeden rytm.
   SYGNET (pierwsze dziecko) bez animacji CSS: animuje się sam w SVG, a hero-in
   przesuwałoby rysującą się literę o 14px w górę. Brak statycznego opacity:0
   jest celowy — gdy animacje nie grają, treść po prostu stoi od początku. */
@keyframes hero-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.hero-start > * { animation: hero-in .7s cubic-bezier(.22,.9,.3,1) both; }
.hero-start > :first-child { animation: none; }
.hero-start > :nth-child(2) { animation-delay: 1.2s; }
/* „Znajdź swój." wchodzi PO PAUZIE (user), ODSŁANIANE od lewej do prawej
   (user) — clip-path inset ściąga prawą krawędź, jak odsłona „estauri"
   w logotypie wyżej; ta sama gramatyka ruchu. inline-block jest KONIECZNY,
   żeby clip-path miał stabilne pudełko (span był inline) — skutek uboczny:
   fraza łamie się tylko w całości, czyli dokładnie tak, jak i tak łamała.
   Prawa krawędź kończy na -5%, nie 0 — inset tnie po border-box, a to
   zostawia oddech na antyaliasing ostatniej litery. Opacity dochodzi do
   pełni już w 25%, żeby widoczna była KRAWĘDŹ odsłony, nie mgła.
   Opacity rodzica i spanu się MNOŻĄ, więc akcent czeka w zerze
   niezależnie od fade'u całego H1. */
.hero-title .accent { display: inline-block; animation: accent-in .8s cubic-bezier(.22,.61,.36,1) 2.45s both; }
@keyframes accent-in {
  from { opacity: 0; clip-path: inset(0 100% 0 0); }
  25%  { opacity: 1; }
  to   { opacity: 1; clip-path: inset(0 -5% 0 0); }
}
.hero-start > :nth-child(3) { animation-delay: 2.6s; }
/* CTA wolniej i KAŻDY przycisk osobno (user: „wolniej CTA i oddzielnie te
   klikalne"): kontener nie animuje, fade dostają same przyciski — dłuższy
   (1.1s vs .7s) i z wyraźnym schodkiem między jednym a drugim. */
.hero-start > :nth-child(4) { animation: none; }
.hero-play { animation: hero-in 1.1s cubic-bezier(.22,.9,.3,1) 2.8s both; }
.hero-join { animation: hero-in 1.1s cubic-bezier(.22,.9,.3,1) 3.2s both; }
@media (prefers-reduced-motion: reduce) {
  .hero-start > *, .hero-play, .hero-join, .hero-title .accent { animation: none; }
}
/* wstrzyknięty teaser wjeżdża crossfade'em; scena 1 i tak wstaje z czerni,
   więc przejście przez czerń jest niewidoczne */
.hero-teaser { opacity: 0; transition: opacity .4s ease; }
.hero-teaser.in { opacity: 1; }
/* niski kadr (telefon poziomo, małe okno): ciaśniej, żeby CTA nie wjeżdżały
   pod strzałkę przewijania przypiętą do dołu hero */
@media (max-height: 560px) {
  .hero-start { gap: 14px; }
  .hero-mark { width: 148px; }
  .hero-title { font-size: clamp(22px, 6.5vh, 34px); }
}

/* ═══ Generic section shell ═══ */
.section {
  position: relative;
  padding: clamp(64px, 12vh, 130px) 24px;
}
.wrap {
  max-width: 640px;
  margin: 0 auto;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.wrap-wide { max-width: 1080px; margin: 0 auto; }

/* alternating panel background for rhythm */
.section-panel { background: var(--panel); }

/* ═══ Section header (left-aligned, editorial) ═══ */
.section-head { max-width: 640px; }
.section-head .kicker { margin-bottom: 22px; }
.section-head .section-lead { margin-top: 18px; max-width: 34em; }

/* ═══ How-it-works stepper (01 / 02 / 03) — reactive to scroll + cursor ═══ */
.steps {
  --fill: 0%;
  position: relative;
  list-style: none;
  margin: clamp(46px, 7vh, 76px) 0 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}
/* connector line — fills left→right with scroll progress (--fill set by JS) */
.steps::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 1;
  background: linear-gradient(to right,
    var(--accent) 0, var(--accent) var(--fill),
    rgba(255,255,255,.14) var(--fill), rgba(255,255,255,.14) 100%);
}
.step {
  position: relative;
  z-index: 2;
  padding: 40px 36px 12px 0;
}
.step + .step {
  padding-left: 36px;
  border-left: 1px solid rgba(255,255,255,.08);
}
/* node dot sitting on the connector line, above each step */
.step::before {
  content: '';
  position: absolute;
  top: -5px; left: 0;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: #3a3d3b;                 /* opaque — the fill line never shows through */
  box-shadow: 0 0 0 4px var(--pine);   /* mask the line right around the node */
  transition: background .2s ease, box-shadow .2s ease;
}
.step + .step::before { left: 36px; }
.step.active::before,
.step:hover::before {
  background: var(--accent);
  box-shadow: 0 0 0 4px var(--pine), 0 0 14px 2px rgba(6,193,103,.5);
}
/* clickable header — acts as the "tile" that covers the explanation */
.step-head {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  position: relative;
}
.step-num {
  display: block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 14px;
  letter-spacing: .14em;
  color: rgba(255,255,255,.32);
  margin-bottom: 16px;
  transition: color .35s ease;
}
.step.active .step-num,
.step:hover .step-num { color: var(--accent); }
/* enlarged headline — the three phrases */
.step-title {
  display: block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(28px, 3vw, 40px);
  line-height: 1.05;
  letter-spacing: -.02em;
}
/* collapsible explanation — 0fr → 1fr animates the height; on open it waits
   a beat so the padlock "unlocks" first, then the text slides out */
.step-desc {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .45s cubic-bezier(.22,.61,.36,1);
}
.step.open .step-desc { grid-template-rows: 1fr; transition-delay: .12s; }
.step-desc-inner { overflow: hidden; min-height: 0; }
.step-desc p {
  padding-top: 18px;
  font-size: 15px;
  line-height: 1.55;
  color: rgba(255,255,255,.62);
  text-wrap: pretty;
  opacity: 0;
  transition: opacity .35s ease;
}
.step.open .step-desc p { opacity: 1; transition-delay: .25s; }
/* padlock at the bottom — closed while locked, opens on click, then reveals */
.step-lock {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  margin-top: 44px;
  padding: 8px 0;
  background: none;
  border: 0;
  cursor: pointer;
  color: rgba(255,255,255,.4);
  transition: color .3s ease;
}
/* "Wkrótce" bubble above the padlock (locked steps only) */
.lock-label {
  display: none;
  position: absolute;
  bottom: calc(100% + 9px);
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  padding: 5px 12px;
  border-radius: 999px;
  background: #24272a;
  font-family: var(--font-body);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(255,255,255,.72);
}
.lock-label::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: #24272a;
}
.step.locked .lock-label { display: block; }
/* :not(.shake) — a click always carries :hover, so without this the hover tint
   outranks the shake's red and the lock never turns. See .step-lock.shake below. */
.step-lock:not(.shake):hover,
.step.open .step-lock { color: var(--accent); }
.lock-ic { position: relative; width: 22px; height: 22px; }
.lock-ic svg { position: absolute; inset: 0; transition: opacity .25s ease, transform .3s cubic-bezier(.34,1.56,.64,1); }
.lock-open { opacity: 0; transform: scale(.55) rotate(-8deg); }
.step.open .lock-closed { opacity: 0; transform: scale(.55) rotate(8deg); }
.step.open .lock-open { opacity: 1; transform: scale(1) rotate(0); }
/* locked steps — a click shakes the padlock (unavailable) instead of opening.
   Cursor stays `pointer`, like the roadmap's locked drops: the click is meant to
   be tried and the shake is the answer, so don't wave it off with `not-allowed`. */
.step.locked .step-lock:not(.shake):hover { color: rgba(255,255,255,.55); }
.step-lock.shake { animation: lock-shake .5s cubic-bezier(.36,.07,.19,.97); color: var(--alert); }

/* ── Wybór roli pod kłódką (klient / restaurator) ──
   Kłódka nie mówi już tylko „nie": otwiera dwa wejścia w tę samą funkcję.
   Dlatego zablokowany krok NIE potrząsa kłódką — potrząśnięcie zostaje tam,
   gdzie naprawdę nie ma co pokazać (zamknięte dropy w roadmapie). */
/* MUSI być przed reguła z `display: flex`, inaczej blok jest widoczny mimo
   atrybutu `hidden`: `[hidden]` to tylko `display: none` z arkusza przeglądarki,
   więc każdy selektor klasowy go przebija. Ten sam problem czeka każdy element,
   który chowasz atrybutem, a stylujesz na display. */
.step-roles[hidden] { display: none; }
.step-roles {
  position: relative;
  display: flex;
  align-items: stretch;             /* obie połowy i kreska mają jedną wysokość */
  overflow: hidden;                 /* przycina zewnętrzne nawisy ukośnych podświetleń */
  margin-top: 18px;
  border-top: 1px solid rgba(255,255,255,.12);
  border-bottom: 1px solid rgba(255,255,255,.12);
  animation: step-roles-in .3s cubic-bezier(.22,.61,.36,1) both;
}
/* każda rola bierze połowę szerokości kroku — blok ma wyglądać na rozwidlenie
   drogi, nie na dwa linki doklejone w rogu */
.step-roles a {
  position: relative;
  z-index: 1;                       /* własny kontekst: ::before z z-index -1 zostaje pod tekstem */
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 128px;                /* wysoki rząd — wybór ma być widoczny, nie drobny */
  padding: 16px 10px;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  color: rgba(255,255,255,.72);
  text-decoration: none;
  text-align: center;
  transition: color .2s;
}
/* Podświetlenie to RÓWNOLEGŁOBOK, nie prostokąt: ta sama pochyłość (skewX -18°)
   co kreska, więc krawędź podświetlenia biegnie równolegle do niej, ~3px od
   pociągnięcia. Wszystkie elementy rzędu mają wspólną wysokość, a skewX nie
   zależy od poziomego origin — pochylone krawędzie sąsiadów są więc dokładnie
   równoległe. Zewnętrzne rogi uciekłyby przez pochylenie (±21px przy 128px
   wysokości), stąd nawisy -44px przycinane przez overflow rodzica. */
.step-roles a::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: -1;
  transform: skewX(-18deg);
  background: transparent;
  transition: background .25s;
}
.step-roles a:first-child::before { left: -44px; right: -18px; }
.step-roles a:last-child::before  { left: -18px; right: -44px; }
.step-roles a:hover,
.step-roles a:focus-visible { color: var(--accent); }
.step-roles a:hover::before,
.step-roles a:focus-visible::before { background: rgba(6,193,103,.09); }
/* Ukośna kreska rysowana GRADIENTEM z jawnym featherem: rdzeń 2px akcentu
   + 1px przejścia w przezroczystość na każdej krawędzi. Ten feather to
   antyaliasing zrobiony ręcznie — liczony w rozdzielczości urządzenia, więc
   krawędź jest gładka przy każdym DPR (schodkowała przy ułamkowym skalowaniu
   Windows, gdzie i pochylony div, i stroke SVG rasteryzują się nierówno).
   Kąt: gradient 108° = pas prostopadły do osi, czyli linia 18° od pionu —
   dokładnie kąt skew podświetleń; wszystko biegnie po tej samej ukośnej.
   Pas idzie od górnej do dolnej krawędzi rzędu, spinając obie poziome linie
   ramy — końce „wchodzą" w linie zamiast wisieć w powietrzu. */
.step-roles-slash {
  flex: none;
  width: 44px;
  background: linear-gradient(108deg,
    transparent            calc(50% - 2px),
    var(--accent)          calc(50% - 1px),
    var(--accent)          calc(50% + 1px),
    transparent            calc(50% + 2px));
}
@keyframes step-roles-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .step-roles { animation: none; }
}
/* Touch: the UA paints a grey wash over the whole tapped element, and these are
   full-width rows — so on a phone a tap lights up the entire line. We already
   answer a tap ourselves (the shake plus the red padlock, or the accordion
   opening), so the wash adds nothing but noise. Desktop never showed it: you
   don't tap with a mouse. */
.step-head, .step-lock, .drop { -webkit-tap-highlight-color: transparent; }

@keyframes lock-shake {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(3px); }
  30%, 50%, 70% { transform: translateX(-6px); }
  40%, 60% { transform: translateX(6px); }
}
@media (prefers-reduced-motion: reduce) {
  .step-lock.shake { animation: none; }
}

/* ═══ Countdown (licznik) — editorial, no boxes ═══ */
.cd-caption {
  margin-top: clamp(36px, 5vh, 52px);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: rgba(255,255,255,.55);   /* was .42 = 4.03:1; AA for 12px needs 4.5 */
}
.countdown {
  margin-top: 16px;
  display: flex;
  flex-wrap: wrap;
  gap: clamp(20px, 4.5vw, 52px);
}
.cd-unit { position: relative; }
.cd-unit + .cd-unit::before {
  content: '';
  position: absolute;
  left: calc(-1 * clamp(10px, 2.25vw, 26px));
  top: 8px;
  bottom: 26px;
  width: 1px;
  background: rgba(255,255,255,.12);
}
.cd-num {
  display: block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(46px, 9vw, 88px);
  line-height: .9;
  letter-spacing: -.03em;
  color: #fff;
  font-variant-numeric: tabular-nums;
}
.cd-unit:first-child .cd-num { color: var(--accent); }
.cd-lbl {
  display: block;
  margin-top: 12px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(255,255,255,.55);   /* was .42 = 4.03:1; AA for 11px needs 4.5 */
}

/* ═══ Roadmap to premiere — advent drops on a timeline ═══ */
.roadmap {
  --progress: 0%;
  position: relative;
  list-style: none;
  margin-top: clamp(48px, 7vh, 78px);
  display: grid;
  grid-template-columns: repeat(6, 1fr);
}
/* connector line, filled up to progress; solid ends at the last node (75%) */
.roadmap::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 1;
  background: linear-gradient(to right,
    var(--accent) 0, var(--accent) var(--progress),
    rgba(255,255,255,.13) var(--progress), rgba(255,255,255,.13) 75%,
    transparent 75%);
}
/* dashed segment from the last drop (75%) to the premiere node (91.67%) */
.roadmap::after {
  content: '';
  position: absolute;
  top: 0;
  left: 75%;
  width: 16.67%;
  height: 2px;
  z-index: 1;
  background: repeating-linear-gradient(to right,
    rgba(255,255,255,.3) 0 6px, transparent 6px 12px);
}
.drop {
  position: relative;
  z-index: 2;
  padding: 30px 8px 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  background: none;
  border: 0;
  font: inherit;
  cursor: pointer;
}
.drop.unlocked { cursor: default; }
/* ...chyba że odsłonięta funkcja ma dokąd prowadzić (data-goto → krok w
   „Jak to działa" + artykuły). Wtedy drop znów jest przyciskiem, więc musi
   na to wyglądać: wskaźnik i odzew na hover. */
.drop.unlocked[data-goto] { cursor: pointer; }
.drop.unlocked[data-goto] .drop-name,
.drop.unlocked[data-goto] .r-ic { transition: color .2s ease, transform .2s ease; }
.drop.unlocked[data-goto]:hover .drop-name { color: var(--accent); }
.drop.unlocked[data-goto]:hover .r-ic { transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) {
  .drop.unlocked[data-goto]:hover .r-ic { transform: none; }
}
/* node sitting on the line */
.drop::before {
  content: '';
  position: absolute;
  top: -5px;
  left: 50%;
  transform: translateX(-50%);
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #3a3d3b;
  box-shadow: 0 0 0 4px var(--panel);
  transition: background .3s ease, box-shadow .3s ease;
}
.drop.unlocked::before {
  background: var(--accent);
  box-shadow: 0 0 0 4px var(--panel), 0 0 12px 2px rgba(6,193,103,.5);
}
.drop-date {
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .04em;
  color: rgba(255,255,255,.42);
  transition: color .3s ease;
}
.drop.unlocked .drop-date { color: var(--accent); }
.drop-lock { width: 26px; height: 26px; color: rgba(255,255,255,.38); transition: color .2s ease; }
.drop.unlocked .drop-lock { display: none; }
/* revealed mini-teaser */
.drop-reveal {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.drop.unlocked .drop-reveal { display: flex; }
.drop-reveal .r-ic { color: var(--accent); }
.drop-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 13.5px;
  color: #fff;
}
/* premiere drop */
.drop--premiere .drop-star { color: var(--accent); fill: currentColor; opacity: .45; transition: opacity .3s ease; }
.drop--premiere.unlocked .drop-star { opacity: 1; }
.drop--premiere .drop-name { color: var(--accent); }
.drop--premiere .drop-date { color: var(--accent); font-weight: 700; }
/* social-media drop */
/* gap 22, not 12: the icons are 22px, so a 12px gap put their centres 34px apart
   and the 44px tap areas would overlap — the middle icon would swallow its
   neighbours' edges. At 22 the centres are 44 apart and the targets just touch. */
.socials { display: flex; align-items: center; gap: 22px; }
.socials a {
  display: inline-flex;
  color: rgba(255,255,255,.72);
  transition: color .2s ease, transform .2s ease;
}
/* [href] qualifier kept deliberately: if a profile is ever pending again, dropping
   the href alone makes the icon inert — unclickable, out of the Tab order — instead
   of a fake link that hovers green. (href="#" is worse than nothing here: with
   target="_blank" it opens a blank duplicate tab.) */
.socials a[href]:hover { color: var(--accent); transform: translateY(-2px); }
/* locked drops shake on click */
.drop.shake { animation: lock-shake .5s cubic-bezier(.36,.07,.19,.97); }
.drop.shake .drop-lock { color: var(--alert); }
.drop--premiere.shake .drop-star { fill: var(--alert); color: var(--alert); }
/* as with .step-lock and .field: drop the movement, keep the red padlock */
@media (prefers-reduced-motion: reduce) {
  .drop.shake { animation: none; }
}

/* ═══ Scroll reveal (only hide when JS is present; no-JS shows content) ═══ */
.js .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .7s cubic-bezier(.22,.61,.36,1), transform .7s cubic-bezier(.22,.61,.36,1);
}
.js .reveal.in { opacity: 1; transform: none; }
/* stagger children within a grid */
.steps .step:nth-child(2), .bento .tile:nth-child(2) { transition-delay: .08s; }
.steps .step:nth-child(3), .bento .tile:nth-child(3) { transition-delay: .16s; }
.bento .tile:nth-child(4) { transition-delay: .24s; }

.kicker {
  display: inline-block;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--accent);
  padding: 8px 16px;
  border: 1px solid rgba(6,193,103,.35);
  border-radius: 999px;
  background: rgba(6,193,103,.06);
  margin-bottom: 26px;
}

.section-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(34px, 6vw, 58px);
  line-height: 1.05;
  letter-spacing: -.02em;
  text-wrap: balance;
}
.section-title .accent { color: var(--accent); }

.section-lead {
  font-size: clamp(16px, 2.2vw, 20px);
  line-height: 1.5;
  color: rgba(255,255,255,.72);
  font-weight: 500;
  margin-top: 20px;
  max-width: 32em;
  /* balance line lengths so the last line never hangs as a lonely widow
     (`pretty` proved too conservative here and left a short trailing line) */
  text-wrap: pretty;
  text-wrap: balance;
}
.section-lead .strong { color: #fff; font-weight: 700; }

/* ═══ Segmented toggle (gość / lokal) ═══
   Two tabs over one shared rule; a 2px accent thumb slides under the active one —
   the same line vocabulary as the CTA meter and the field underline, so the split
   reads as part of the page, not a bolted-on widget. */
.seg {
  position: relative;
  display: flex;
  width: 100%;
  max-width: 560px;
  margin: clamp(30px, 4vh, 46px) 0 clamp(24px, 3.5vh, 34px);
  border-bottom: 1px solid rgba(255,255,255,.14);
}
.seg-opt {
  flex: 1;
  padding: 14px 8px;
  background: none;
  border: 0;
  color: rgba(255,255,255,.5);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  transition: color .2s;
  -webkit-tap-highlight-color: transparent;
}
.seg-opt[aria-selected="true"] { color: #fff; }
.seg-opt:not([aria-selected="true"]):hover { color: rgba(255,255,255,.78); }
/* thumb is half the track; translateX(100%) = its own width = the right half */
.seg-thumb {
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 50%;
  height: 2px;
  background: var(--accent);
  transition: transform .3s cubic-bezier(.22,.61,.36,1);
}
@media (prefers-reduced-motion: reduce) { .seg-thumb { transition: none; } }

/* ═══ Waitlist form ═══
   An editorial "fill in the blank": the email sits on a ruled underline rather
   than in a pill, so the form reads as part of the typography, not a widget. ═══ */
/* margin-top 0: the toggle above now owns the spacing from the header */
.waitlist { margin-top: 0; width: 100%; max-width: 560px; }

/* venue name (B2B only) — same underline treatment as the email, stacked above it */
.venue-field { margin-bottom: 22px; }
.venue-field input {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid rgba(255,255,255,.18);
  outline: 0;
  color: #fff;
  font-family: var(--font-display);
  font-size: clamp(17px, 2vw, 21px);
  font-weight: 600;
  letter-spacing: -.01em;
  padding: 0 0 12px;
  transition: border-color .25s;
}
.venue-field input:focus { border-bottom-color: var(--accent); }
.venue-field input::placeholder { color: rgba(255,255,255,.34); font-weight: 500; }

.field {
  display: flex;
  align-items: center;
  gap: 20px;
  border-bottom: 1px solid rgba(255,255,255,.18);
  padding-bottom: 12px;
  transition: border-color .25s;
}
.field:focus-within { border-bottom-color: var(--accent); }
.field input[type=email] {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: 0;
  outline: 0;
  color: #fff;
  font-family: var(--font-display);
  font-size: clamp(17px, 2vw, 21px);
  font-weight: 600;
  letter-spacing: -.01em;
  padding: 0;
}
.field input::placeholder { color: rgba(255,255,255,.34); font-weight: 500; }
.field button {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--accent);
  color: #fff;
  border: 0;
  border-radius: 999px;
  padding: 13px 22px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition: background .2s;
}
.field button:hover { background: var(--accent-ink); }
.field button svg { transition: transform .2s; }
.field button:hover svg { transform: translateX(3px); }
.field button:disabled { opacity: .5; cursor: default; }

.gotcha { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

/* Status line. Empty at rest; min-height reserves the row so nothing jumps.
   State reads as a node + the rule going colour — the page's own vocabulary —
   rather than as a coloured alert box. */
.form-note {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: rgba(255,255,255,.5);
  margin-top: 16px;
  min-height: 1.2em;
  transition: color .2s;
  text-wrap: pretty;
}
/* node — same 8px dot language as the stepper/roadmap/CTA, hidden while neutral */
.form-note::before {
  content: '';
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0;
  transform: scale(.4);
  transition: opacity .25s, transform .25s cubic-bezier(.22,.61,.36,1);
}
.form-note.ok::before,
.form-note.err::before { opacity: 1; transform: none; }
.form-note.ok  { color: var(--accent); font-weight: 600; }
.form-note.err { color: var(--alert); font-weight: 600; }

/* Saving state — spinner + rotating flavour text. Shown while the fetch is in
   flight; JS hides the form-note meanwhile so the two don't stack. */
.form-loading {
  display: flex;
  align-items: center;
  gap: 11px;
  margin-top: 16px;
  min-height: 1.2em;                   /* same reserve as .form-note: no jump */
  font-size: 13px;
  color: rgba(255,255,255,.6);
}
.form-loading[hidden] { display: none; }
.spinner {
  flex: none;
  width: 16px;
  height: 16px;
  border: 2px solid rgba(255,255,255,.16);
  border-top-color: var(--accent);     /* the one lit arc that reads as spinning */
  border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.load-msg { font-weight: 500; }
/* reduced motion: no rotation. The ring becomes a solid accent dot and the whole
   row pulses gently, so there's still a live indicator; the text keeps cycling. */
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; border: 0; background: var(--accent); }
  .form-loading { animation: loadPulse 1.3s ease-in-out infinite; }
}
@keyframes loadPulse { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }

/* screen-reader-only: the loader announces one stable line while the visible
   flavour text (aria-hidden) rotates, so SR users aren't spammed each tick */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

/* the field's own rule carries the error — 560px of it, so it can't be missed.
   Beats .field:focus-within on specificity, so the state holds while they retype.
   (On mobile the rule lives on the input; harmless here, where its width is 0.) */
.waitlist.is-err .field,
.waitlist.is-err .field input[type=email] { border-bottom-color: var(--alert); }

/* error also shakes the field — the same gesture (and keyframes) as a locked step */
.field.shake { animation: lock-shake .5s cubic-bezier(.36,.07,.19,.97); }
/* motion-sensitive users still get the colour, node and message; drop the movement */
@media (prefers-reduced-motion: reduce) {
  .field.shake { animation: none; }
}

.waitlist.done .field, .waitlist.done .venue-field, .waitlist.done .gotcha { display: none; }

/* ═══ CTA section (closing waitlist) ═══
   Left-aligned editorial block. No glow, no coloured shadows — the rule and the
   node carry it, same language as the stepper (#poznaj) and roadmap (#premiera),
   with this as the last point on the line. ═══ */
.cta-block {
  position: relative;
  padding-top: clamp(36px, 5vh, 54px);
  --fill: 0;                  /* 0 → 1, set by js/main.js as the address is typed */
}
/* the rule — real elements rather than ::before/::after, because the fill and the
   node have to animate independently and the node's position has to be driven */
.cta-line {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: rgba(255,255,255,.14);
}
.cta-line-fill {
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform: scaleX(var(--fill));
  transform-origin: left center;
  transition: transform .4s cubic-bezier(.22,.61,.36,1);
}
/* the node rides the fill's leading edge — matches .step::before (12px, 4px pine
   ring). The (100% - 12px) span keeps it inside the line at both ends: hard left
   when empty, flush right when the address is complete. */
.cta-line-node {
  position: absolute;
  top: -5px;
  left: calc(var(--fill) * (100% - 12px));
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 4px var(--pine);
  transition: left .4s cubic-bezier(.22,.61,.36,1);
}
@media (prefers-reduced-motion: reduce) {
  .cta-line-fill, .cta-line-node { transition: none; }
}
/* ≥1080px: the UX audit measured a right half of pure nothing here — the header,
   toggle and 560px form all hugged the left of the 1080px wrap, and ~272px of
   empty rows sat above the footer. Two columns instead: header left, toggle +
   forms right. Explicit grid coordinates (not auto-flow) because the two forms
   swap via [hidden] and must land in the same cell. The rule + node meter is
   position:absolute so the grid ignores it — it still opens the whole block,
   full-width, exactly as before. Below 1080px nothing changes. */
@media (min-width: 1080px) {
  .cta-block {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 560px);
    column-gap: 72px;
    align-items: start;
  }
  .cta-block .section-head { grid-column: 1; grid-row: 1 / span 2; }
  /* 6px: optically aligns the toggle's text baseline with the kicker's */
  .cta-block .seg { grid-column: 2; grid-row: 1; margin-top: 6px; }
  .cta-block .waitlist { grid-column: 2; grid-row: 2; }
  /* the trimmed row count leaves less to pad against — pull the section's
     bottom in from clamp(64,12vh,130) so the klauzula→footer gap stops at a
     breath, not a void */
  .section-cta { padding-bottom: clamp(48px, 8vh, 88px); }
}

/* ═══ Footer ═══ */
.foot {
  border-top: 1px solid rgba(255,255,255,.07);
  padding: 44px 24px 40px;
  font-size: 14px;
  color: rgba(255,255,255,.5);
}
.foot-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 34px;
}
/* The footer brand is the real logotype (concentric-stroke R), not type.
   Note for anyone re-reading the teaser bundle: its R can NOT be borrowed — in
   logo-mark.png the letter is one continuous line with the bowl and noodles (a
   single 162k-pixel connected component), so it can't be cropped or lifted out.
   The logotype below was vectorized from the user's brand-source.png sheet. */
.foot-brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* The real logotype as an SVG (assets/restauri-wordmark.svg), vectorized from the
   wordmark in brand-source.png (crop x 401–932, y 326–503; IoU 98.7% vs the
   raster, so it IS the same drawing — sharp at any size now). Its light colour
   (#D9D9D9) is baked into the file and reproduces exactly what the old
   grayscale+invert+screen knockout produced on this #0B0B0B ground; if the footer
   background ever changes, re-derive that fill instead of resurrecting the trick.
   114px = the old 531px crop × .2147; viewBox 531×177 keeps the 3:1 ratio. */
.foot-word {
  display: block;
  width: 114px;
}
.foot-word img {
  display: block;
  width: 100%;
  height: auto;
}
/* the finale's two-tone tagline, carried over to the dark ground */
.foot-tag {
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  color: rgba(255,255,255,.5);
  margin-top: 12px;
}
.foot-tag b { color: #fff; font-weight: 700; }
.foot-nav { display: flex; gap: 26px; }
.foot-nav a {
  color: rgba(255,255,255,.62);
  text-decoration: none;
  font-size: 14.5px;
  transition: color .2s;
}
.foot-nav a:hover { color: var(--accent); }
.foot-bottom {
  display: flex;
  gap: 10px;
  align-items: center;
  justify-content: center;
  margin-top: 30px;
  padding-top: 24px;
  border-top: 1px solid rgba(255,255,255,.06);
  font-size: 13px;
  color: rgba(255,255,255,.55);   /* was .4 = 3.8:1; AA for 13px needs 4.5 */
}
.foot .dot { opacity: .5; }

/* ═══ Responsive ═══ */
@media (max-width: 900px) {
  /* stepper → vertical timeline; connector line fills top→bottom */
  .steps { grid-template-columns: 1fr; }
  .steps::before {
    top: 0; bottom: 0; left: 5px; right: auto;
    width: 2px; height: auto;
    background: linear-gradient(to bottom,
      var(--accent) 0, var(--accent) var(--fill),
      rgba(255,255,255,.14) var(--fill), rgba(255,255,255,.14) 100%);
  }
  .step { padding: 22px 0 22px 32px; }
  .step + .step { padding-left: 32px; border-left: none; }
  .step::before, .step + .step::before { top: 26px; left: 0; }
}
@media (max-width: 720px) {
  /* the rule moves onto the input itself so the button can sit full-width below */
  .field { flex-direction: column; align-items: stretch; gap: 0; border-bottom: 0; padding-bottom: 0; }
  .field input[type=email] {
    /* an <input> can't carry a ::after, so this one needs real height (was 34px) */
    min-height: var(--tap);
    padding-bottom: 12px;
    border-bottom: 1px solid rgba(255,255,255,.18);
    transition: border-color .25s;
  }
  .field:focus-within input[type=email] { border-bottom-color: var(--accent); }
  /* venue input (B2B) gets the same 44px tap height as the email on mobile */
  .venue-field input { min-height: var(--tap); padding-bottom: 0; display: flex; }
  .field button { justify-content: center; padding: 15px; margin-top: 18px; }
  /* The CTA is the last section before the footer, and the footer brings its own
     44px of top padding — so 12vh (~101px on a phone) under the button was dead
     space stacked on dead space. The form-note's 16px reserve stays: it keeps the
     layout from jumping when a message appears. */
  .section-cta { padding-bottom: 32px; }
  .foot-inner { gap: 26px; }
  /* roadmap → vertical timeline; line fills top→bottom, dashed before premiere */
  .roadmap { grid-template-columns: 1fr; }
  .roadmap::before {
    top: 0; bottom: 0; left: 5px; right: auto;
    width: 2px; height: auto;
    background: linear-gradient(to bottom,
      var(--accent) 0, var(--accent) var(--progress),
      rgba(255,255,255,.13) var(--progress), rgba(255,255,255,.13) 83%,
      transparent 83%);
  }
  .roadmap::after {
    top: 83%; left: 5px; width: 2px; height: 17%;
    background: repeating-linear-gradient(to bottom,
      rgba(255,255,255,.3) 0 6px, transparent 6px 12px);
  }
  .drop {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 16px;
    padding: 15px 0 15px 30px;
    text-align: left;
  }
  .drop::before { top: 50%; left: 0; transform: translate(-1px, -50%); }
  .drop-reveal { flex-direction: row; align-items: center; }
  .drop-date { min-width: 44px; }
}
@media (max-width: 460px) {
  .countdown { gap: 16px 20px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .scroll-cue { animation: none; }
  .js .reveal, .js .reveal.in { opacity: 1; transform: none; transition: none; }
  /* ekran startowy: bez wejścia i schodków; sam teaser gra dalej — klik w play
     to jawne żądanie animacji, preferencja dotyczy ozdobników */
  .hero-start > * { animation: none; }
}

/* ═══ Legal pages (regulamin / prywatność / cookies) ═══
   Same dark editorial language as the page. Print matters legally: Regulamin §8.1
   requires a form that can be saved and printed, so @media print flips to
   black-on-white and drops the chrome. */
.legal {
  max-width: 760px;
  margin: 0 auto;
  padding: clamp(44px, 8vh, 84px) 24px 64px;
}
.legal-home {
  display: inline-block;
  color: rgba(255,255,255,.55);
  text-decoration: none;
  font-size: 14px;
  margin-bottom: 40px;
  transition: color .2s;
}
.legal-home:hover { color: var(--accent); }
.legal h1 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(28px, 5vw, 40px);
  letter-spacing: -.02em;
  line-height: 1.1;
  text-wrap: balance;
}
.legal-updated { margin-top: 10px; font-size: 13px; color: rgba(255,255,255,.45); }
.legal h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -.01em;
  margin-top: 40px;
  color: #fff;
}
.legal p, .legal li { font-size: 15px; line-height: 1.65; color: rgba(255,255,255,.72); }
.legal p { margin-top: 12px; }
.legal ol, .legal ul { padding-left: 22px; margin-top: 12px; }
.legal li { margin-top: 8px; }
.legal a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.legal strong { color: #fff; font-weight: 600; }
/* data records (privacy §2 categories, cookie entries) — labelled prose blocks on
   a hairline left rule, replacing the earlier tables (the user cut those; blocks
   also read without sideways scrolling on phones). Content itself is unchanged. */
.legal-record {
  margin-top: 24px;
  padding-left: 18px;
  border-left: 2px solid rgba(255,255,255,.14);
}
.legal h3,
.legal-record h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15.5px;
  letter-spacing: -.01em;
  color: #fff;
}
.legal-record p { margin-top: 8px; font-size: 14px; }
@media print {
  body.legal-page { background: #fff; color: #000; }
  body.legal-page .legal h1, body.legal-page .legal h2, body.legal-page .legal h3,
  body.legal-page .legal strong { color: #000; }
  body.legal-page .legal p, body.legal-page .legal li,
  body.legal-page .legal-updated { color: #000; }
  body.legal-page .legal-record { border-left-color: #888; }
  body.legal-page .legal a { color: #000; }
  body.legal-page .legal-home, body.legal-page .foot { display: none; }
}

/* ═══ Consent (RODO) — checkbox + info clause under the forms ═══ */
.consent {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-top: 18px;
  font-size: 12.5px;
  line-height: 1.55;
  color: rgba(255,255,255,.55);
  text-align: left;
  cursor: pointer;
}
.consent input[type=checkbox] {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 18px;
  height: 18px;
  margin-top: 1px;
  border: 1.5px solid rgba(255,255,255,.35);
  border-radius: 5px;
  background: transparent;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: border-color .2s, background .2s;
}
.consent input[type=checkbox]::after {
  content: '';
  width: 10px;
  height: 10px;
  background: #fff;
  clip-path: polygon(14% 44%, 0 65%, 40% 100%, 100% 16%, 84% 0%, 38% 66%);
  transform: scale(0);
  transition: transform .15s cubic-bezier(.22,.61,.36,1);
}
.consent input[type=checkbox]:checked { background: var(--accent); border-color: var(--accent); }
.consent input[type=checkbox]:checked::after { transform: scale(1); }
.consent a { color: rgba(255,255,255,.85); text-decoration: underline; text-underline-offset: 2px; }
.consent a:hover { color: var(--accent); }
/* Touch: the inline legal links were ~15px tall inside a checkbox-toggling label,
   so a near-miss silently flipped the consent. The verbatim text can't change, so
   only the HIT AREA grows: vertical padding on an inline element paints/hits
   outside the line box without moving any line (15px content + 2×15px ≈ 45px,
   over the 44px floor), and position:relative lifts the link above the label text
   in paint order so the extended area wins hit-testing. A mistap now opens the
   document (visible, recoverable) instead of toggling the consent. Coarse
   pointers only: with a mouse an invisible pointer-cursor zone over blank
   interline space reads as broken. */
@media (pointer: coarse) {
  .consent a, .klauzula a {
    position: relative;
    padding: 15px 4px;
    margin: 0 -4px;
  }
}
/* the error state colours the box, same --alert as everything else */
.waitlist.is-err .consent input:invalid { border-color: var(--alert); }
.waitlist.done .consent, .waitlist.done .klauzula { display: none; }
.klauzula {
  margin-top: 22px;
  font-size: 11.5px;
  line-height: 1.6;
  /* .52, not lower: at 11.5px WCAG AA needs 4.5:1, and on this background the
     threshold is alpha ~.46 (audited at .38 → 3.53:1, failing on the one text
     that's legally required reading). .52 lands ~5.7:1. */
  color: rgba(255,255,255,.52);
  text-wrap: pretty;
}
.klauzula a { color: rgba(255,255,255,.6); }

/* ═══ Footer legal row (required on every page) ═══ */
.foot-legal {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  margin-top: 26px;
  font-size: 13px;
  color: rgba(255,255,255,.5);
  text-align: center;
}
.foot-legal a { color: rgba(255,255,255,.62); text-decoration: none; transition: color .2s; }
.foot-legal a:hover { color: var(--accent); }
.foot-legal-links { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: center; }
.legal-page .foot-legal { margin-top: 0; }

/* ═══ Zgłoś lokal — pływająca zakładka + panel ═══
   Reachable from anywhere without adding a block to the poznaj → premiera →
   waitlist flow. Deliberately quiet: the page's own furniture (kicker-style
   pill, underlined fields, accent only on action), no badge, no pulse, no
   auto-open — this must not read as a bolted-on chat widget.
   Visibility is JS-driven (main.js): shown only past the hero, hidden again
   while #waitlist is on screen so it never competes with the main CTA. */
.sugg {
  position: fixed;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 60;
  /* Tło szuflady. Kontener NIE jedzie z pukaniem (transform siedzi na zakładce
     i nie rusza layoutu), więc gdy zakładka wysunie się w lewo, w odsłoniętej
     szczelinie widać ten kolor. W spoczynku zakładka przykrywa go co do piksela.
     CIEMNIEJSZY AKCENT, nie `--panel`: panel (#101211) różni się od tła strony
     (#0B0B0B) o trzy punkty na kanał — pomiar RGB mówił „to nie czerń", a oko
     dalej widziało dziurę. Zieleń czyta się jak bok zakładki i widać ją od razu. */
  background: var(--accent-ink);
  border-radius: 14px 0 0 14px;
}
/* Po otwarciu panel niesie własne tło, a kontener jest od niego o 18px szerszy
   (margines panelu) — tło kontenera sterczałoby obok jako pasek. Klasę ustawia
   main.js razem z otwarciem/zamknięciem. */
.sugg.is-open { background: none; border-radius: 0; }

/* Collapsed state: a vertical tab on the right edge. Accent ground like the
   page's action buttons — the quiet panel-grey version was invisible enough
   that the user asked for more visibility ("zwiększyć widoczność zgłaszania").
   Still no pulse/badge/auto-open; presence comes from colour alone. */
.sugg-tab {
  position: relative;               /* kotwica dla ::after (brzeg szuflady) */
  writing-mode: vertical-rl;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: var(--tap);            /* design system floor — the tab is touchable too */
  padding: 26px 16px;               /* powiększona: ma zwracać uwagę, nie tylko istnieć */
  background: var(--accent);
  color: #fff;
  border: 0;
  border-radius: 14px 0 0 14px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .2s;
}
.sugg-tab:hover { background: var(--accent-ink); }
/* Brzeg szuflady — patrz `.sugg` niżej: tło nosi KONTENER, nie zakładka.
   Wcześniejsza wersja (pasek jako `.sugg-tab::after` z `z-index: -1`) miała
   poprawną geometrię i łapała hit-testy, ale malowała się pod spodem i user
   dalej widział czarną szczelinę. Ujemny z-index tego nie udźwignie. */
/* Wjazd z prawej krawędzi przy KAŻDYM pojawieniu — widoczność przełącza atrybut
   `hidden`, a przejście display:none → widoczny restartuje animacje CSS, więc
   zakładka zawsze wsuwa się zza ekranu zamiast pojawiać znikąd (prośba usera).
   calc(+20px) domyka też mobilną pigułkę, która stoi 14px od krawędzi. */
@keyframes sugg-slide-in {
  from { transform: translateX(calc(100% + 20px)); }
  to   { transform: none; }
}
/* Co ~7 s zakładka delikatnie „puka": wysuwa się 6px i wraca (prośba usera —
   „lekko się poruszyć, żeby zwrócić uwagę"). To samo miejsce w wokabularzu co
   bob strzałki w hero: krótki, rzadki ruch, żadnego pulsowania koloru.
   Obie animacje ruszają transform — pukanie startuje po 2s, gdy wjazd (0.45s,
   fill both) już trzyma transform:none, więc nie wchodzą sobie w drogę. */
/* Rytm 4s (było 7s). Procenty przeliczone tak, żeby samo pukanie nadal trwało
   ~0.8s — przy krótszym cyklu ten sam ułamek dałby ruch szarpany. */
@keyframes sugg-knock {
  0%, 80%, 100% { transform: none; }
  86%           { transform: translateX(-22px); }   /* mocne wysunięcie */
  91%           { transform: translateX(0); }
  95%           { transform: translateX(-14px); }
}
.sugg-tab {
  animation: sugg-slide-in .45s cubic-bezier(.22,.61,.36,1) both,
             sugg-knock 4s ease-in-out 1.5s infinite;
}

/* Expanded panel. The shadow is pure black, not a coloured glow — it separates a
   floating surface from the content beneath it, which the page's "no glow" rule
   (about neon washes under buttons/logos) does not cover. */
.sugg-panel {
  width: min(330px, calc(100vw - 24px));
  margin-right: 18px;
  padding: 22px 20px 18px;
  background: var(--panel);
  border: 1px solid rgba(255,255,255,.14);
  border-radius: 16px;
  box-shadow: 0 18px 50px rgba(0,0,0,.5);
  animation: suggIn .28s cubic-bezier(.22,.61,.36,1) both;
}
@keyframes suggIn {
  from { opacity: 0; transform: translateX(14px); }
  to   { opacity: 1; transform: none; }
}
.sugg-close {
  position: absolute;
  top: 10px;
  right: 10px;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  background: none;
  border: 0;
  border-radius: 50%;
  color: rgba(255,255,255,.5);
  cursor: pointer;
  transition: color .2s, background .2s;
}
.sugg-close:hover { color: #fff; background: rgba(255,255,255,.08); }
.sugg-title {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -.02em;
  padding-right: 26px;              /* clear of the close button */
  text-wrap: balance;
}
.sugg-lead {
  margin-top: 8px;
  font-size: 13px;
  line-height: 1.5;
  color: rgba(255,255,255,.55);     /* ≥.46 — the muted-text contrast floor */
  text-wrap: pretty;
}
.sugg-form { margin-top: 18px; }
/* fields on a rule, like the waitlist — same "fill in the blank" language */
.sugg-field + .sugg-field { margin-top: 14px; }
.sugg-field input {
  width: 100%;
  min-height: var(--tap);           /* inputs can't carry a ::after hit area */
  background: transparent;
  border: 0;
  border-bottom: 1px solid rgba(255,255,255,.18);
  outline: 0;
  color: #fff;
  font-family: var(--font-display);
  font-size: 16px;                  /* ≥16px: iOS zooms the page on smaller */
  font-weight: 600;
  padding: 0 0 9px;
  transition: border-color .25s;
}
.sugg-field input:focus { border-bottom-color: var(--accent); }
.sugg-field input::placeholder { color: rgba(255,255,255,.34); font-weight: 500; }
.sugg.is-err .sugg-field input:invalid { border-bottom-color: var(--alert); }
.sugg-submit {
  width: 100%;
  margin-top: 18px;
  min-height: var(--tap);
  background: var(--accent);
  color: #fff;
  border: 0;
  border-radius: 999px;
  padding: 12px 20px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  transition: background .2s;
}
.sugg-submit:hover { background: var(--accent-ink); }
.sugg-submit:disabled { opacity: .5; cursor: default; }
.sugg-note { margin-top: 12px; font-size: 12.5px; }
/* the shake reuses the page's single "no" gesture (lock-shake keyframes) */
.sugg-field input.shake { animation: lock-shake .4s; }

@media (prefers-reduced-motion: reduce) {
  .sugg-panel { animation: none; }
  .sugg-field input.shake { animation: none; }
  .sugg-tab { animation: none; }
}

/* Wyzwalacze zgłaszania w treści strony — bez JS nie ma czego otworzyć,
   więc istnieją tylko pod .js (ta sama bramka co .reveal). */
.sugg-trigger { display: none; }
/* linijka pod formularzem zapisu: cichy dopisek, akcent tylko na akcji */
.js .sugg-inline {
  display: block;
  margin-top: 26px;
  font-size: 13.5px;
  color: rgba(255,255,255,.55);
}
.sugg-inline button {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.sugg-inline button:hover { color: var(--accent-ink); }
@media (min-width: 1080px) {
  .cta-block .sugg-inline { grid-column: 2; }   /* pod formularzem, w jego kolumnie */
}
/* przycisk w nawigacji stopki — wygląda jak sąsiednie linki */
.js .foot-nav button.sugg-trigger {
  display: inline-block;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 14.5px;
  color: rgba(255,255,255,.62);
  cursor: pointer;
  transition: color .2s;
}
.foot-nav button.sugg-trigger:hover { color: var(--accent); }

/* Mobile: a side tab makes no sense at 390px — a corner pill opening a
   bottom-sheet does. Same rules, different furniture. */
@media (max-width: 720px) {
  .sugg {
    top: auto;
    bottom: 16px;
    right: 14px;
    transform: none;
  }
  .sugg-tab {
    writing-mode: horizontal-tb;
    min-height: var(--tap);         /* 12px padding alone landed at 42px */
    padding: 15px 22px;             /* powiększona razem z wersją desktopową */
    border-radius: 999px;
    font-size: 14px;
  }
  /* Tło szuflady tylko na desktopie: tutaj pigułka jest zaokrąglona i odsunięta
     od krawędzi, więc prostokąt kontenera sterczałby zza niej. Nie ma też czego
     imitować — panel wjeżdża na telefonie od dołu, nie z boku. */
  .sugg { background: none; border-radius: 0; }
  .sugg-panel {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    margin-right: 0;
    padding-bottom: max(20px, env(safe-area-inset-bottom));
    border-radius: 18px 18px 0 0;
    border-bottom: 0;
    animation-name: suggUp;
  }
  @keyframes suggUp {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: none; }
  }
}
