/* ==========================================================================
   BRIDES BINDERY — site.css
   --------------------------------------------------------------------------
   MOBILE FIRST. Base rules describe the phone; every media query is min-width
   and only ever adds. Nothing is written for desktop and then undone below a
   breakpoint, so a narrow viewport parses the least CSS and Google's
   mobile-first crawler sees the canonical layout.

   Breakpoints (content-driven, not device-driven):
     560px  two-up cards fit
     900px  the desktop nav fits on one line
     1120px true multi-column layouts

   Type follows the two references Marcin chose: heirloombindery.com (airy
   white, Baskerville-ish serif, wide-tracked uppercase sans, hairline rules)
   and the Nuptials template (Cormorant Garamond + Mulish, warm
   cream, botanical ornaments). Sage green is a deliberate accent, not decor:
   it has been the #1 wedding colour every year 2023–2026 (Zola).
   ========================================================================== */

/* ==========================================================================
   1. TOKENS
   ========================================================================== */

:root {
  --white:   #ffffff;
  --paper:   #fbf9f6;
  --cream:   #f5efe8;
  --cream-2: #ece2d7;
  --ink:     #22211f;
  --ink-2:   #575450;
  --ink-3:   #857f77;
  --gold:    #c6ad8f;
  --gold-d:  #9a785d;
  --gold-dd: #6a543c;
  --sage:    #8c9484;
  --sage-d:  #6e7666;
  --sage-dd: #4b5346;

  /* The one place the palette is allowed to shout. Errors have to read on a
     dark hero photo and on cream alike, so they carry their own background. */
  --err:     #b23c26;
  --err-d:   #8a2d1b;
  --err-bg:  #fdeeea;

  --bg:        var(--white);
  --bg-alt:    var(--paper);
  --bg-warm:   var(--cream);
  --bg-dark:   #26251f;
  --fg:        var(--ink-2);
  --fg-strong: var(--ink);
  --fg-muted:  var(--ink-3);

  --line:        rgba(34, 33, 31, .13);
  --line-soft:   rgba(34, 33, 31, .07);
  --line-invert: rgba(255, 255, 255, .22);
  --shadow-s: 0 2px 10px rgba(34, 33, 31, .05);
  --shadow-m: 0 10px 40px rgba(34, 33, 31, .08);

  --ff-display: "Cormorant Garamond", Baskerville, "Baskerville Old Face",
                Garamond, "Times New Roman", serif;
  --ff-sans:    "Mulish", -apple-system, BlinkMacSystemFont, "Segoe UI",
                Helvetica, Arial, sans-serif;

  --fs-hero:  clamp(2.6rem, 1.5rem + 4.6vw, 5.6rem);
  --fs-h1-inner: clamp(2.2rem, 1.4rem + 3.4vw, 4.2rem);  /* every h1 that is not the home hero */
  --fs-h2:    clamp(1.95rem, 1.35rem + 2.3vw, 3.55rem);
  --fs-h3:    clamp(1.4rem, 1.2rem + .9vw, 2rem);
  --fs-lead:  clamp(1.03rem, .99rem + .3vw, 1.25rem);
  --fs-small: .875rem;
  --fs-label: .688rem;

  --shell:      1240px;
  --shell-wide: 1500px;
  --shell-text: 720px;
  --gut:  clamp(1.15rem, .5rem + 2.4vw, 2.75rem);
  --sec-y: clamp(3.6rem, 2rem + 7vw, 9rem);
  --hdr-h: 68px;               /* header height on phones; grows at 900px */

  --focus:  var(--sage-dd);      /* keyboard focus ring; flipped on dark */

  --e:      cubic-bezier(.19, 1, .22, 1);
  --e-soft: cubic-bezier(.4, 0, .2, 1);
}

/* ==========================================================================
   2. BASE
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--hdr-h) + 8px);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--ff-sans);
  font-size: 1rem;
  font-weight: 300;
  line-height: 1.72;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}
body.is-locked { overflow: hidden; }

h1, h2, h3, h4 {
  font-family: var(--ff-display);
  font-weight: 300;
  color: var(--fg-strong);
  /* Interlinia maleje wraz ze stopniem pisma: 1.14 jest w porządku dla h3
     i h4, ale przy hero rozmiaru 90 px odstęp między wierszami robi się
     dziurą. Cormorant ma małą wysokość x i długie wydłużenia, więc światła
     między wierszami jest optycznie więcej, niż wynika z liczby. */
  line-height: 1.14;
  letter-spacing: -.005em;
  margin: 0 0 .5em;
  text-wrap: balance;
}
h1 { font-size: var(--fs-hero); line-height: 1.02; }
h2 { font-size: var(--fs-h2); line-height: 1.07; }

/* Nagłówek łamany po zdaniu, nie tam, gdzie wypadnie. Każde zdanie dostaje
   własny wiersz, a interlinia między nimi jest ciasna, żeby czytały się jak
   jedna myśl w dwóch taktach, a nie jak dwa osobne nagłówki. Stopień pisma
   jest mniejszy niż w zwykłym h2, bo dłuższe ze zdań musi zmieścić się w
   jednym wierszu w kolumnie 760 px — inaczej cały zabieg traci sens. */
.h2--lines { font-size: clamp(1.6rem, 1.05rem + 1.75vw, 2.6rem); line-height: 1.04; }
.h2--lines > span { display: block; }
.h2--lines > span + span { margin-top: .06em; }
h3 { font-size: var(--fs-h3); line-height: 1.22; }
h4 { font-size: 1.1rem; }

p { margin: 0 0 1.1em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: inherit; text-decoration: none; }
img, video, svg, iframe { max-width: 100%; display: block; }
img { height: auto; }
hr { border: 0; border-top: 1px solid var(--line); margin: 0; }

::selection { background: var(--gold); color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 2px;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: -100px; left: 1rem;
  z-index: 200;
  background: var(--ink);
  color: #fff;
  padding: .75rem 1.25rem;
  font-size: var(--fs-small);
  transition: top .2s var(--e-soft);
}
.skip-link:focus { top: 1rem; }

/* ==========================================================================
   3. PRIMITIVES
   ========================================================================== */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gut);
}
.shell--wide { max-width: var(--shell-wide); }
.shell--text { max-width: var(--shell-text); }

.section { padding-block: var(--sec-y); }
.section--tight { padding-block: clamp(2.6rem, 1.8rem + 4vw, 5.5rem); }
.section--warm { background: var(--bg-warm); }
.section--alt  { background: var(--bg-alt); }
.section--dark { background: var(--bg-dark); color: rgba(255, 255, 255, .76); }
.section--dark h2, .section--dark h3, .section--dark h4 { color: #fff; }
.section--dark .overline { color: var(--gold); }
.section--dark .rule::before, .section--dark .rule::after { background: var(--line-invert); }
.section--dark a:not(.btn) { color: #fff; }
.section--dark, .hero, .statement, .cta, .footer, .film { --focus: var(--gold); }

.overline {
  display: block;
  font-size: var(--fs-label);
  font-weight: 400;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--gold-dd);
  margin: 0 0 1rem;
}

.script {
  font-style: italic;
  font-weight: 300;
  color: var(--gold-d);
}

.rule {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-top: 1.5rem;
}
.rule::before, .rule::after {
  content: "";
  height: 1px;
  width: clamp(40px, 12vw, 108px);
  background: var(--line);
}
.rule svg { width: 30px; height: auto; color: var(--gold); flex: none; }

.section-head { text-align: center; max-width: 760px; margin-inline: auto; }
.section-head p { font-size: var(--fs-lead); margin-top: .35em; }
.section-head--left { text-align: left; margin-inline: 0; }
.section-head--left .rule { justify-content: flex-start; }
.section-head--left .rule::before { display: none; }

.lead { font-size: var(--fs-lead); line-height: 1.7; }
.fineprint { font-size: var(--fs-small); color: var(--fg-muted); line-height: 1.6; }
.center { text-align: center; }

/* Zapowiedź kafelków należy do kafelków, nie do nagłówka sekcji. Domyślnie
   przyklejała się do ornamentu (1 px) i stała 63 px od tego, co zapowiada —
   czyli dokładnie odwrotnie, niż powinna. Odstęp nad nią jest teraz mniej
   więcej dwa razy większy niż pod nią, więc grupuje się z tym, co następuje. */
.say { margin-top: clamp(2.1rem, 4vw, 3.2rem); margin-bottom: 0; }
.say + .grid { margin-top: clamp(1.1rem, 2vw, 1.6rem); }
/* Centred on a phone only. A .split on a narrow screen stops being a two-column
   arrangement and becomes an image with a caption under it — and a short block
   under a full-width photograph reads better centred on its axis than ragged
   against the left gutter. Only for genuinely short bodies; centring four
   paragraphs would cost more in reading comfort than it buys in composition. */
@media (max-width: 767px) {
  .split--centre-m .split__body { text-align: center; }
}

/* Whole-page version of the same idea, switched on from the front matter with
   body class `centre-m`. Lists keep their left edge: a centred bullet list has
   no column to run down and every line starts somewhere new, which is exactly
   the reading cost centring is supposed to avoid. */
@media (max-width: 767px) {
  .centre-m .prose,
  .centre-m .split__body,
  .centre-m .card { text-align: center; }

  .centre-m .prose ul,
  .centre-m .prose ol,
  .centre-m .prose table { text-align: left; }
}

/* --- vertical spacing scale ---------------------------------------------
   Four steps, and nothing between them. These replace ~40 one-off inline
   margin-tops that had drifted into six different clamp() values doing the
   same job, which is what made the page feel unevenly spaced when you
   scrolled it. If a new gap does not fit the scale, the scale is wrong —
   change it here rather than adding another inline style. */
.mt-xs { margin-top: .85rem; }
.mt-s  { margin-top: 1.1rem; }
.mt-m  { margin-top: 1.8rem; }
.mt-l  { margin-top: clamp(2.2rem, 5vw, 3.5rem); }
.mt-xl { margin-top: clamp(3rem, 6vw, 5rem); }

/* --- buttons ------------------------------------------------------------ */
.btn {
  --btn-bg: var(--ink);
  --btn-fg: #fff;
  --btn-bd: var(--ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .6em;
  min-height: 48px;                 /* comfortable thumb target */
  padding: 1em 1.9em;
  border: 1px solid var(--btn-bd);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--ff-sans);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  line-height: 1;
  text-align: center;
  cursor: pointer;
  border-radius: 0;
  position: relative;
  overflow: hidden;
  -webkit-appearance: none;
  appearance: none;
  transition: color .45s var(--e), border-color .45s var(--e);
}
.btn::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform .55s var(--e);
}
.btn > * { position: relative; z-index: 1; }
.btn--ghost  { --btn-bg: transparent; --btn-fg: var(--ink); --btn-bd: var(--line); }
.btn--light  { --btn-bg: #fff; --btn-fg: var(--ink); --btn-bd: #fff; }
.btn--invert { --btn-bg: transparent; --btn-fg: #fff; --btn-bd: var(--line-invert); }
.btn--sm     { min-height: 42px; padding: .8em 1.5em; }
.btn--block  { width: 100%; }

@media (hover: hover) {
  .btn:hover { color: var(--ink); border-color: var(--gold); }
  .btn:hover::after { transform: scaleX(1); transform-origin: left center; }
}

.tlink {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  min-height: 44px;
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--fg-strong);
  background-image: linear-gradient(var(--gold-d), var(--gold-d));
  background-repeat: no-repeat;
  background-position: 0 calc(50% + .95em);
  background-size: 100% 1px;
  transition: background-size .45s var(--e), color .45s var(--e);
}
.tlink:hover { color: var(--gold-dd); background-size: 0% 1px; }
.section--dark .tlink { color: #fff; background-image: linear-gradient(var(--gold), var(--gold)); }

/* --- media -------------------------------------------------------------- */
.frame { position: relative; overflow: hidden; background: var(--cream); }
.frame img { width: 100%; height: 100%; object-fit: cover; }
.frame--4x5  { aspect-ratio: 4 / 5; }
.frame--1x1  { aspect-ratio: 1 / 1; }
.frame--3x2  { aspect-ratio: 3 / 2; }
.frame--16x9 { aspect-ratio: 16 / 9; }
/* The exact shape of the boudoir album photograph, so it is shown as it was
   taken rather than cropped into a shape the layout preferred. */
.frame--7x3  { aspect-ratio: 7 / 3; }
.frame--zoom img { transition: transform 1.1s var(--e); }
@media (hover: hover) {
  /* Only zoom for things that are actually links — an <article class="card">
     is not clickable and must not behave as though it were. */
  a:hover > .frame--zoom img,
  a.card:hover .frame--zoom img { transform: scale(1.055); }
}

/* --- reveal ------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .9s var(--e), transform .9s var(--e);
  transition-delay: var(--d, 0ms);
}
.reveal.is-in { opacity: 1; transform: none; }

/* Forty-nine elements on the home page start at `opacity: 0` and wait for an
   IntersectionObserver to reveal them, which means one stylesheet rule stands
   between this site and a blank white page. If scripting is off, nothing ever
   adds `.is-in` — so the hiding does not apply in the first place. */
@media (scripting: none) {
  .reveal { opacity: 1; transform: none; transition: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
}

/* ==========================================================================
   4. HEADER — phone layout first: brand centred, burger right.
   ========================================================================== */

.topbar {
  background: var(--ink);
  color: rgba(255, 255, 255, .82);
  font-size: .625rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-align: center;
  padding: .6rem var(--gut);
  position: relative;
  z-index: 60;
  line-height: 1.5;
}
.topbar b { color: var(--gold); font-weight: 500; }

.header {
  position: sticky;
  top: 0;
  /* Above the drawer (55): the burger doubles as the close button, so it must
     stay clickable while the overlay is open. */
  z-index: 56;
  /* Cream by default so it joins the .pagehead block on pages without a hero;
     .header--over turns it transparent again where a photograph runs behind. */
  background: var(--bg-warm);
  /* The stuck hairline is an inset shadow, NOT a border: a 1px border made the
     header 97px tall against a --hdr-h of 96, and the hero's negative margin
     then left a 1px band of white body background across the top of the page. */
  transition: background .4s var(--e-soft), box-shadow .4s var(--e-soft);
}
.header__in {
  max-width: var(--shell-wide);
  margin-inline: auto;
  min-height: var(--hdr-h);
  padding: .5rem var(--gut);
  display: grid;
  grid-template-columns: 44px 1fr 44px;
  align-items: center;
  gap: .5rem;
}

.header--over { color: #fff; background: transparent; }
.header--over .nav__link,
.header--over .brand,
.header--over .burger { color: #fff; }
.header--over .brand__rule { background: rgba(255, 255, 255, .55); }
.header--over .btn--ghost { --btn-fg: #fff; --btn-bd: rgba(255, 255, 255, .5); }

.header.is-stuck {
  background: rgba(251, 249, 246, .97);
  -webkit-backdrop-filter: saturate(1.4) blur(12px);
  backdrop-filter: saturate(1.4) blur(12px);
  box-shadow: var(--shadow-s), inset 0 -1px 0 var(--line-soft);
}
.header.is-stuck .nav__link,
.header.is-stuck .brand,
.header.is-stuck .burger { color: var(--ink); }
.header.is-stuck .brand__rule { background: var(--line); }
.header.is-stuck .btn--ghost { --btn-fg: var(--ink); --btn-bd: var(--line); }

.brand {
  grid-column: 2;
  justify-self: center;
  text-align: center;
  color: var(--ink);
  line-height: 1;
  transition: color .4s var(--e-soft);
}
.brand__name {
  display: block;
  font-family: var(--ff-display);
  font-size: clamp(1.05rem, .9rem + .6vw, 1.55rem);
  font-weight: 400;
  letter-spacing: .3em;
  text-indent: .3em;
  text-transform: uppercase;
}
.brand__sub {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .45rem;
  margin-top: .28rem;
}
.brand__rule { height: 1px; width: 18px; background: var(--line); transition: background .4s var(--e-soft); }
.brand__word {
  font-size: .52rem;
  letter-spacing: .4em;
  text-indent: .4em;
  text-transform: uppercase;
}

.nav { display: none; }
.header .btn { display: none; }

.burger {
  grid-column: 3;
  justify-self: end;
  width: 44px; height: 44px;
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  color: var(--ink);
  cursor: pointer;
  padding: 0;
}
.burger span {
  display: block;
  position: relative;
  width: 22px; height: 1px;
  background: currentColor;
  transition: background .2s var(--e-soft);
}
.burger span::before, .burger span::after {
  content: "";
  position: absolute;
  left: 0;
  width: 22px; height: 1px;
  background: currentColor;
  transition: transform .4s var(--e), top .3s var(--e);
}
.burger span::before { top: -7px; }
.burger span::after  { top: 7px; }
.burger[aria-expanded="true"] span { background: transparent; }
.burger[aria-expanded="true"] span::before { top: 0; transform: rotate(45deg); }
.burger[aria-expanded="true"] span::after  { top: 0; transform: rotate(-45deg); }

/* While the drawer is open its cream ground sits directly behind the header.
   On a page whose header is in its over-the-hero state that would leave the
   wordmark and the close button white on cream, i.e. invisible. `is-locked` is
   already on <body> for the scroll lock, so it can carry this too. */
body.is-locked .header--over .brand,
body.is-locked .header--over .burger { color: var(--ink); }
body.is-locked .header--over .brand__rule { background: var(--line); }

/* --- drawer ------------------------------------------------------------- */
.drawer {
  position: fixed;
  inset: 0;
  z-index: 55;
  background: var(--paper);
  padding: 5.5rem var(--gut) 3rem;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-10px);
  transition: opacity .35s var(--e-soft), transform .35s var(--e-soft), visibility .35s;
}
.drawer.is-open { opacity: 1; visibility: visible; transform: none; }
.drawer > a:not(.btn) {
  font-family: var(--ff-display);
  font-size: 1.6rem;
  color: var(--ink);
  padding: .55rem 0;
  border-bottom: 1px solid var(--line-soft);
}
.drawer > a[aria-current="page"] { color: var(--gold-dd); }
.drawer .btn { margin-top: 1.6rem; }
.drawer__foot { margin-top: auto; padding-top: 2rem; font-size: .8rem; color: var(--fg-muted); }

/* --- language switcher --------------------------------------------------
   Rendered by the build only when a page actually has a translation, so it
   never offers a link to a page that does not exist. */
.langsw {
  display: flex;
  align-items: center;
  /* Spacing lives in the items' padding, not here, so the divider between them
     can be positioned against a box whose edges mean something. */
  gap: 0;
  margin-top: 1.6rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--line-soft);
  flex-wrap: wrap;
}
.langsw__abbr { display: none; }
.langsw__item {
  white-space: nowrap;
  font-size: var(--fs-label);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-muted);
  padding: .4rem 0;
  transition: color .3s var(--e-soft);
}
/* Letter-spacing is applied AFTER the final glyph, so "EN" carries .16em of
   trailing air that "PL" does not. Splitting the gap evenly therefore lands the
   divider visibly closer to PL — which is what it did. Take the trailing space
   back out of the right side. */
.langsw__item:not(:last-child) { padding-right: calc(.62rem - .16em); }
.langsw__item + .langsw__item { position: relative; padding-left: .62rem; }
/* A short centred rule, not a full-height border: with .4rem of vertical
   padding a border-left stands more than twice the cap height of the two
   letters it separates, and reads as a hairline dropped between them rather
   than as punctuation belonging to them. */
.langsw__item + .langsw__item::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 1px;
  height: .8em;
  transform: translateY(-50%);
  background: var(--line);
}
.langsw__item.is-current { color: var(--gold-dd); }
a.langsw__item:hover { color: var(--ink); }

@media (min-width: 900px) {
  .header .langsw {
    margin: 0 0 0 .6rem;
    padding: 0;
    border: 0;
    gap: 0;
    flex-wrap: nowrap;          /* it wrapped to two rows at 1100px */
  }
  /* the header shows EN / PL; the drawer keeps the full names */
  .header .langsw__full { display: none; }
  .header .langsw__abbr { display: inline; }
  .header .langsw__item { color: inherit; opacity: .72; padding-block: .4rem; }
  .header .langsw__item.is-current { opacity: 1; }
  .header--over .langsw__item + .langsw__item::before { background: rgba(255, 255, 255, .3); }
  .header a.langsw__item:hover { opacity: 1; }
}

/* ==========================================================================
   5. HERO
   ========================================================================== */

.hero {
  position: relative;
  margin-top: calc(var(--hdr-h) * -1);
  padding-top: var(--hdr-h);
  min-height: 92svh;
  display: grid;
  place-items: center;
  isolation: isolate;
  color: #fff;
  overflow: hidden;
}
.hero__media { position: absolute; inset: 0; z-index: -2; }
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 60%;
}
/* Two scrims, not one. The linear pass anchors the top and bottom edges so the
   header and the scroll cue stay legible; the radial pass sits under the type
   block only, which keeps white text readable over a light, busy photograph
   without flattening the corners of the picture into grey. */
.hero::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(115% 78% at 50% 52%,
      rgba(18,17,15,.66) 0%, rgba(18,17,15,.46) 46%, rgba(18,17,15,.10) 100%),
    linear-gradient(180deg,
      rgba(18,17,15,.62) 0%, rgba(18,17,15,.30) 26%,
      rgba(18,17,15,.44) 64%, rgba(18,17,15,.80) 100%);
}
.hero--inner::before {
  background:
    radial-gradient(120% 85% at 50% 50%,
      rgba(18,17,15,.62) 0%, rgba(18,17,15,.44) 50%, rgba(18,17,15,.12) 100%),
    linear-gradient(180deg,
      rgba(18,17,15,.58) 0%, rgba(18,17,15,.34) 30%, rgba(18,17,15,.62) 100%);
}
/* The emphasised words are the lightest thing on the hero — they need their
   own lift, not more scrim over the whole photograph. */
.hero h1 .script { text-shadow: 0 1px 22px rgba(18, 17, 15, .55); }
.hero h1 { text-shadow: 0 1px 30px rgba(18, 17, 15, .38); }
.hero__sub { text-shadow: 0 1px 16px rgba(18, 17, 15, .45); }
.hero__in {
  width: 100%;
  max-width: 880px;
  padding: clamp(2.5rem, 7vh, 6rem) var(--gut) clamp(3.5rem, 9vh, 7rem);
  text-align: center;
}
.hero .overline { color: rgba(255, 255, 255, .84); }
.hero h1 { color: #fff; margin-bottom: .3em; }
.hero h1 .script { color: var(--gold); }
.hero__sub {
  /* One step under --fs-lead. At lead size the mission paragraph filled the
     middle of the photograph and left the hero feeling crowded. */
  font-size: clamp(.96rem, .93rem + .26vw, 1.12rem);
  color: rgba(255, 255, 255, .91);
  max-width: 610px;
  margin-inline: auto;
}
.hero__cue { display: none; }

/* The hero asks for one thing and then gets out of the way. It used to carry
   the whole capture form — field, button, consent checkbox, reassurance line —
   stacked under a mission statement, which is four decisions in front of
   somebody who has not been given a reason yet. Now it is a single button that
   takes them to the form at the foot of the page. */
.hero__act {
  margin-top: clamp(1.7rem, 4vh, 2.6rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .95rem;
}
/* The chevron is the honest part of the label: this button moves you down the
   page, it does not submit anything. */
.btn__down { width: .72em; height: .72em; flex: none; }
@media (hover: hover) {
  .btn:hover .btn__down { transform: translateY(2px); }
  .btn__down { transition: transform .35s var(--e); }
}
@media (prefers-reduced-motion: reduce) {
  .btn__down { transition: none; }
}

/* compact hero for inner pages */
/* The mission hero. The desaturation here used to be 35%, which suited the old
   picture and would ruin this one: the whole subject is firelight in a warm
   room, and draining a third of that leaves a grey room with a fire in it.
   Barely any now — just enough to stop the reds fighting the gold in the
   headline. */
.hero--mission .hero__media img { filter: grayscale(.08) brightness(.94); object-position: center 42%; }
/* Lighter than it was. The old picture was bright and busy and needed holding
   down; this one is a dark room lit by a fire, so it brings most of its own
   contrast. Piling the same scrim on top only hid the room. */
.hero--mission::before {
  background:
    radial-gradient(120% 85% at 50% 46%,
      rgba(18,17,15,.62) 0%, rgba(18,17,15,.42) 50%, rgba(18,17,15,.18) 100%),
    linear-gradient(180deg,
      rgba(18,17,15,.52) 0%, rgba(18,17,15,.22) 26%,
      rgba(18,17,15,.34) 64%, rgba(18,17,15,.72) 100%);
}
.hero--mission h1 .script { color: var(--gold); }
/* Two clauses that must break as units. At .26em of tracking the line is wide
   enough to wrap on a phone, and left to itself it broke mid-phrase — "made to
   / last decades". So each half is unbreakable, the line breaks only between
   them, and the separator disappears when they stack, because a middot left
   dangling at the end of a line reads as a mistake. */
.hero__sign {
  margin-top: 1.6rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .25em;
  font-size: var(--fs-label);
  letter-spacing: .26em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .72);
  text-shadow: 0 1px 12px rgba(18, 17, 15, .55);
}
.hero__sign > span { white-space: nowrap; }
.hero__sign-sep { display: none; font-style: normal; }

@media (min-width: 480px) {
  .hero__sign { flex-direction: row; justify-content: center; gap: 0 .55em; }
  .hero__sign-sep { display: inline; }
}

.hero--inner { min-height: 62svh; }
.hero--inner h1 { font-size: var(--fs-h1-inner); }

/* ==========================================================================
   6. LEAD CAPTURE
   ========================================================================== */

.capture { margin-top: 1.9rem; }
.capture__row {
  display: grid;
  gap: .5rem;
  max-width: 560px;
  margin-inline: auto;
}
.capture__row input[type="email"] {
  width: 100%;
  min-height: 52px;
  padding: 1em 1.2em;
  font-family: var(--ff-sans);
  font-size: 1rem;                  /* 16px — stops iOS zooming on focus */
  font-weight: 300;
  color: var(--ink);
  background: rgba(255, 255, 255, .97);
  border: 1px solid transparent;
  border-radius: 0;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color .3s var(--e-soft), background .3s var(--e-soft);
}
.capture__row input[type="email"]::placeholder { color: var(--ink-3); }
.capture__row input[type="email"]:focus { border-color: var(--gold); background: #fff; }
.capture__row input[type="email"]:focus:not(:focus-visible) { outline: none; }

.capture__consent {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  max-width: 560px;
  margin: .9rem auto 0;
  text-align: left;
  font-size: .76rem;
  line-height: 1.55;
  color: rgba(255, 255, 255, .76);
}
.capture__consent input {
  flex: none;
  margin-top: .25em;
  width: 18px; height: 18px;
  accent-color: var(--gold-d);
  cursor: pointer;
}
.capture__consent a { text-decoration: underline; text-underline-offset: 2px; }

/* The field that is actually wrong, said in colour.
   `outline` rather than `border`, on both controls: it is drawn outside the
   box, so nothing reflows when it appears and an 18px checkbox does not
   suddenly become a 22px one halfway down a form. */
.capture__row.is-invalid input[type="email"],
.capture__consent.is-invalid input {
  outline: 2px solid var(--err);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(178, 60, 38, .22);
}
.capture__consent.is-invalid input {
  /* Colours the tick itself, so the box stays marked for the instant between
     ticking it and the handler clearing the state. */
  accent-color: var(--err);
}
.capture__consent.is-invalid > span { color: #ffd9d1; }
.capture--light .capture__consent.is-invalid > span { color: var(--err-d); }

@media (prefers-reduced-motion: no-preference) {
  .capture__consent.is-invalid input { animation: capture-nudge .4s var(--e-soft) both; }
  @keyframes capture-nudge {
    0%, 100% { transform: none; }
    25%      { transform: translateX(-2px); }
    75%      { transform: translateX(2px); }
  }
}

.capture .capture__note {
  margin-top: .85rem;
  font-size: .76rem;
  color: rgba(255, 255, 255, .7);
}

.capture--light .capture__row input[type="email"] { background: #fff; border-color: var(--line); }
.capture--light .capture__consent,
.capture--light .capture__note { color: var(--fg-muted); }

.hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Doubled class (`.form-msg.form-msg--err`) on purpose. This message renders
   inside `.statement` and inside `.hero`, both of which colour their own
   paragraphs white; a single-class rule ties on specificity and loses on
   source order, which once left the error white-on-white and invisible. */
.form-msg {
  margin: .9rem auto 0;
  max-width: 560px;
  padding: .8rem 1rem .8rem 1.05rem;
  font-size: .84rem;
  line-height: 1.5;
  border: 1px solid;
  border-left-width: 4px;
  display: none;
  text-align: left;
  text-shadow: none;
}
.form-msg.is-shown { display: block; }

.form-msg.form-msg--ok {
  background: #f1f4ee;
  border-color: var(--sage);
  color: var(--sage-dd);
}
.form-msg.form-msg--err {
  background: var(--err-bg);
  border-color: var(--err);
  color: var(--err-d);
  font-weight: 400;
  box-shadow: 0 6px 22px rgba(178, 60, 38, .18);
}
/* A short pulse, once. Enough to catch the eye on a page the visitor has
   already scrolled past, not enough to feel like an alarm. */
.form-msg.form-msg--err.is-shown { animation: form-msg-in .45s var(--e-soft) both; }
@keyframes form-msg-in {
  0%   { opacity: 0; transform: translateY(-4px); }
  60%  { opacity: 1; transform: translateY(1px); }
  100% { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .form-msg.form-msg--err.is-shown { animation: none; }
}

/* ==========================================================================
   7. TRUST STRIP
   ========================================================================== */

.trust { border-block: 1px solid var(--line-soft); background: var(--bg-alt); }
.trust__grid { display: grid; grid-template-columns: 1fr 1fr; }
.trust__item {
  padding: 1.4rem 1rem;
  text-align: center;
  border-top: 1px solid var(--line-soft);
  border-left: 1px solid var(--line-soft);
}
.trust__item:nth-child(-n+2) { border-top: 0; }
.trust__item:nth-child(odd) { border-left: 0; }
.trust__item svg { width: 24px; height: 24px; margin: 0 auto .6rem; color: var(--gold-d); }
.trust__item b {
  display: block;
  font-family: var(--ff-display);
  font-size: 1.1rem;
  font-weight: 400;
  color: var(--ink);
  line-height: 1.25;
}
.trust__item span { font-size: .74rem; color: var(--fg-muted); line-height: 1.45; display: block; }

/* ==========================================================================
   8. SPLIT
   ========================================================================== */

/* Both columns start at the same line.
   These were centred, which only looks right when the two columns are a similar
   height — and they never are. The text carries an overline, a heading, three
   paragraphs and often a stat block, so it runs 340–470px taller than the
   picture, and centring dropped every photograph 170–240px below the overline
   that introduces it. Starting them together gives the section one clean top
   edge; where the picture is the taller column it simply runs on below. */
.split { display: grid; gap: 2rem; align-items: start; }
.split--centre { align-items: center; }
.split__body { max-width: 60ch; }

/* ==========================================================================
   9. STEPS
   ========================================================================== */

.steps { display: grid; gap: 2.4rem; margin-top: clamp(2.2rem, 5vw, 4.5rem); }
.step__n {
  font-family: var(--ff-display);
  font-size: .95rem;
  letter-spacing: .28em;
  color: var(--gold-dd);
  display: flex;
  align-items: center;
  gap: .8rem;
  margin-bottom: 1rem;
}
.step__n::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.step .frame { margin-bottom: 1.2rem; }
.step h3 { margin-bottom: .4em; }
.step p { font-size: .95rem; }

/* ==========================================================================
   10. CARD GRIDS
   ========================================================================== */

.grid { display: grid; gap: 1.1rem; margin-top: clamp(2.2rem, 5vw, 4rem); }
.grid--2 { grid-template-columns: 1fr; }
.grid--3 { grid-template-columns: 1fr; }
.grid--4 { grid-template-columns: 1fr 1fr; }

.card { display: block; position: relative; }
.card .frame { margin-bottom: .9rem; }
.card__tag {
  position: absolute;
  top: .8rem; left: .8rem;
  z-index: 2;
  background: rgba(251, 249, 246, .94);
  color: var(--gold-dd);
  font-size: .55rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding: .4em .75em;
}
.card h3 { font-size: 1.12rem; margin-bottom: .25em; transition: color .35s var(--e-soft); }
@media (hover: hover) { a.card:hover h3 { color: var(--gold-dd); } }
.card p { font-size: .84rem; line-height: 1.6; color: var(--fg-muted); margin: 0; }
.card .card__meta {
  margin-top: .6rem;
  font-size: .62rem;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--sage-dd);
}

/* --- price tag -----------------------------------------------------------
   Two numbers and an explanation. The struck figure is what the same album
   costs bought through a photographer, so it needs a source the reader can
   check rather than being left as an unexplained "was" price — hence the
   info button rather than a bare asterisk. */
.ptag {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: .85rem;
  position: relative;
}
.ptag__was {
  font-family: var(--ff-display);
  font-size: 1.05rem;
  color: var(--fg-muted);
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}
.ptag__now {
  font-family: var(--ff-display);
  font-size: 1.5rem;
  color: var(--ink);
  line-height: 1;
}
.ptag__now small {
  font-family: var(--ff-sans);
  font-size: .6rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--fg-muted);
  display: block;
  margin-bottom: .2rem;
}
.ptag__soon {
  font-family: var(--ff-sans);
  font-size: .72rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.ptag__i {
  width: 18px; height: 18px;
  flex: none;
  align-self: center;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--fg-muted);
  font-family: var(--ff-sans);
  font-size: .6rem;
  font-style: italic;
  line-height: 1;
  cursor: pointer;
  transition: border-color .3s var(--e-soft), color .3s var(--e-soft);
}
.ptag__i:hover, .ptag__i[aria-expanded="true"] { border-color: var(--gold-d); color: var(--gold-dd); }
/* the tap target is bigger than the dot it draws */
.ptag__i::after {
  content: "";
  position: absolute;
  inset: auto auto auto auto;
  width: 44px; height: 44px;
  transform: translate(-13px, -13px);
}

.ptag__note {
  position: absolute;
  left: 0; top: calc(100% + .6rem);
  z-index: 5;
  width: min(280px, 84vw);
  padding: .75rem .9rem;
  background: var(--ink);
  color: rgba(255, 255, 255, .9);
  font-size: .78rem;
  line-height: 1.5;
  box-shadow: var(--shadow-m);
}
.ptag__note[hidden] { display: none; }
.ptag__note::before {
  content: "";
  position: absolute;
  left: 14px; top: -5px;
  width: 10px; height: 10px;
  background: var(--ink);
  transform: rotate(45deg);
}

/* pill card — used for the "what we curate" grid */
.pill {
  display: block;
  padding: 1.4rem 1.3rem;
  background: var(--white);
  border: 1px solid var(--line);
  transition: border-color .4s var(--e), transform .4s var(--e), box-shadow .4s var(--e);
}
@media (hover: hover) {
  .pill:hover { border-color: var(--gold); transform: translateY(-3px); box-shadow: var(--shadow-m); }
}
.pill svg { width: 26px; height: 26px; color: var(--gold-d); margin-bottom: .9rem; }

/* Kafelki obietnic czyta się jak trzy osobne karty, nie jak kolumny jednego
   tekstu — więc każda jest wyśrodkowana na własnej osi, także na desktopie.
   Ikona jest blokiem (reguła bazowa dla mediów), więc text-align jej nie
   dotyczy i potrzebuje własnych marginesów. */
.grid--swipe .pill { text-align: center; }
.grid--swipe .pill svg { margin-inline: auto; }
.pill h3 { font-size: 1.28rem; margin-bottom: .3em; }
/* Kafelek linii albumów na /pricing/: ikona, nazwa, cena „od", jedno zdanie.
   Trzy takie kafelki czyta się jak skalę cen, nie jak trzy kolumny jednego
   tekstu, więc każdy jest wyśrodkowany na własnej osi. Ikona jest blokiem
   (reguła bazowa dla mediów), więc text-align jej nie dotyczy.
   Kolejność w pliku ma znaczenie: .pill--price i .pill mają tę samą wagę,
   więc to źródło rozstrzyga, kto nadpisuje display. */
.pill--price { display: flex; flex-direction: column; text-align: center; }
/* 26 px (reguła bazowa .pill) wystarcza, gdy ikona tylko oznacza nagłówek.
   Tutaj piktogram jest jedyną rzeczą, która mówi „to jest ta linia" — obok
   nazwy i ceny, bez zdjęcia — więc dostaje własną wielkość. */
.pill--price svg { width: 40px; height: 40px; margin-inline: auto; margin-bottom: 1.1rem; }
.pill--price h3 { font-size: 1.12rem; }
/* .pill p to (0,1,1) — sama klasa .pill__from by przegrała, stąd kontekst. */
.pill--price .pill__from {
  font-family: var(--ff-display);
  font-size: clamp(2rem, 1.5rem + 1.5vw, 2.7rem);
  line-height: 1;
  color: var(--ink);
  margin: .5rem 0 .8rem;
}
.pill--price .pill__from small {
  display: block;
  font-family: var(--ff-sans);
  font-size: .6rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold-dd);
  margin-bottom: .45rem;
}
/* Trzy kafelki mają różnej długości opisy — link ma zostać na jednej linii
   u dołu wszystkich trzech, nie tam, gdzie skończy się tekst. */
.pill--price .pill__go { margin-top: auto; padding-top: .9rem; }

/* Czwarty kafelek nie jest czwarta linia albumow, tylko zestawem trzech ksiazek.
   Zlota obwodka i lekki podklad — tym samym kolorem, ktorym tabela porownawcza
   wyroznia wiersz „my" (.compare .is-us) — mowia to bez slow, wiec czytelnik nie
   szuka czwartego produktu w szeregu. Waga (0,1,0) jak .pill, wiec o nadpisaniu
   ramki i tla rozstrzyga kolejnosc w pliku: ta regula musi stac PO .pill. */
.pill--set { border-color: var(--gold); background: rgba(198, 173, 143, .07); }
.pill p { font-size: .88rem; margin: 0; color: var(--fg-muted); }
.pill__go {
  display: inline-block;
  margin-top: .9rem;
  font-size: .62rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--gold-dd);
}

/* ==========================================================================
   11. FILMS
   ========================================================================== */

.films { display: grid; gap: 1rem; margin-top: clamp(2.2rem, 5vw, 4rem); }
.film { position: relative; overflow: hidden; background: #171614; }
.film video, .film img { width: 100%; height: 100%; object-fit: cover; }
.film__ratio-16x9 { aspect-ratio: 16 / 9; }
.film__ratio-4x3  { aspect-ratio: 4 / 3; }

.film__ui {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: .25rem;
  padding: clamp(1rem, 2.4vw, 2.2rem);
  background: linear-gradient(180deg, rgba(0,0,0,0) 38%, rgba(0,0,0,.66) 100%);
  color: #fff;
  cursor: pointer;
  border: 0;
  width: 100%;
  text-align: left;
  font: inherit;
  transition: opacity .4s var(--e-soft);
}
.film.is-playing .film__ui { opacity: 0; pointer-events: none; }
.film.is-playing:hover .film__ui { opacity: 1; pointer-events: auto; }
.film__play {
  width: 48px; height: 48px;
  border: 1px solid rgba(255, 255, 255, .55);
  border-radius: 50%;
  display: grid;
  place-items: center;
  margin-bottom: auto;
  transition: background .4s var(--e), border-color .4s var(--e), color .4s var(--e);
}
.film__play svg { width: 13px; height: 13px; margin-left: 2px; }
.film__ui:hover .film__play { background: var(--gold); border-color: var(--gold); color: var(--ink); }
.film__t {
  font-family: var(--ff-display);
  font-size: clamp(1.2rem, 1rem + .8vw, 1.8rem);
  line-height: 1.15;
}
.film__d { font-size: .78rem; color: rgba(255, 255, 255, .78); }

/* --- YouTube facade ------------------------------------------------------
   The poster is a local WebP and the iframe is only injected on click. Two
   reasons, both load-bearing: the privacy notice promises no third-party
   cookies until you ask for them, and an eager YouTube embed costs about a
   megabyte before anyone presses play. */
.film iframe { width: 100%; height: 100%; border: 0; display: block; }
.film--yt .film__ui { background: linear-gradient(180deg, rgba(0,0,0,.18) 0%, rgba(0,0,0,.30) 45%, rgba(0,0,0,.70) 100%); }
.film--yt .film__play { margin-bottom: auto; margin-top: auto; align-self: center; width: 62px; height: 62px; }
.film__src {
  display: block;
  margin-top: .35rem;
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .62);
}

/* ==========================================================================
   12. MATERIALS
   ========================================================================== */

.mat { display: grid; gap: 1.6rem; margin-top: clamp(2rem, 4vw, 3.4rem); }
.mat__preview { display: grid; grid-template-columns: 104px 1fr; gap: 1.1rem; align-items: center; }
.mat__swatch {
  aspect-ratio: 1 / 1;
  background: var(--cream-2) center/cover no-repeat;
  box-shadow: var(--shadow-m);
}
.mat__name { font-family: var(--ff-display); font-size: 1.5rem; color: var(--ink); margin: 0 0 .1rem; line-height: 1.15; }
.mat__group { font-size: var(--fs-label); letter-spacing: .2em; text-transform: uppercase; color: var(--gold-dd); margin: 0; }

.mat__tabs {
  display: flex;
  gap: .35rem;
  margin-bottom: 1.2rem;
  padding-bottom: .9rem;
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.mat__tabs::-webkit-scrollbar { display: none; }
.mat__tab {
  flex: none;
  background: none;
  border: 1px solid transparent;
  min-height: 40px;
  padding: .55em 1em;
  font-family: var(--ff-sans);
  font-size: var(--fs-label);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-muted);
  cursor: pointer;
  white-space: nowrap;
  transition: color .3s var(--e-soft), border-color .3s var(--e-soft), background .3s var(--e-soft);
}
.mat__tab[aria-selected="true"] { color: var(--ink); border-color: var(--line); background: var(--white); }

.mat__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); gap: .45rem; }
.mat__chip {
  position: relative;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--line-soft);
  background: var(--cream-2) center/cover no-repeat;
  cursor: pointer;
  padding: 0;
  transition: transform .35s var(--e), box-shadow .35s var(--e), border-color .35s var(--e);
}
@media (hover: hover) {
  .mat__chip:hover { transform: translateY(-3px); box-shadow: var(--shadow-m); }
}
.mat__chip[aria-pressed="true"] { border-color: var(--ink); box-shadow: 0 0 0 2px var(--white), 0 0 0 3px var(--ink); }
.mat__chip span {
  position: absolute;
  left: 50%; bottom: calc(100% + 7px);
  transform: translateX(-50%);
  background: var(--ink);
  color: #fff;
  font-size: .6rem;
  letter-spacing: .06em;
  padding: .28em .55em;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s var(--e-soft);
  z-index: 3;
}
.mat__chip:hover span, .mat__chip:focus-visible span { opacity: 1; }
.mat__count { margin-top: 1.2rem; font-size: .8rem; color: var(--fg-muted); }

/* ==========================================================================
   13. CRAFT
   ========================================================================== */

.craft { display: grid; gap: 2.2rem; margin-top: clamp(2.2rem, 5vw, 4rem); }
.craft__item .frame { margin-bottom: 1.2rem; }
.craft__item h3 { font-size: 1.35rem; margin-bottom: .35em; }
.craft__item p { font-size: .9rem; margin: 0; }
.craft__item dl {
  margin: 1rem 0 0;
  padding-top: .9rem;
  border-top: 1px solid var(--line-invert);
  font-size: .76rem;
  display: grid;
  gap: .3rem;
}
.craft__item dl div { display: flex; justify-content: space-between; gap: 1rem; }
.craft__item dt { color: rgba(255, 255, 255, .55); }
.craft__item dd { margin: 0; color: #fff; text-align: right; }

/* ==========================================================================
   14. GALLERY + LIGHTBOX
   ========================================================================== */

.gallery {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .5rem;
  margin-top: clamp(2.2rem, 5vw, 4rem);
}
.gallery button {
  border: 0; padding: 0; background: none; cursor: zoom-in;
  position: relative; overflow: hidden;
  aspect-ratio: 1 / 1;
}
.gallery img { width: 100%; height: 100%; object-fit: cover; transition: transform 1s var(--e); }
@media (hover: hover) { .gallery button:hover img { transform: scale(1.05); } }

.lb {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: rgba(20, 19, 17, .96);
  display: grid;
  place-items: center;
  padding: clamp(1rem, 4vw, 3.5rem);
  opacity: 0;
  visibility: hidden;
  transition: opacity .35s var(--e-soft), visibility .35s;
}
.lb.is-open { opacity: 1; visibility: visible; }
.lb img { max-width: 100%; max-height: 78vh; object-fit: contain; margin-inline: auto; }
.lb__cap {
  margin-top: 1rem;
  text-align: center;
  color: rgba(255, 255, 255, .72);
  font-size: .78rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.lb__btn {
  position: absolute;
  background: rgba(0, 0, 0, .3);
  border: 1px solid rgba(255, 255, 255, .3);
  color: #fff;
  width: 48px; height: 48px;
  display: grid; place-items: center;
  cursor: pointer;
  transition: background .3s var(--e-soft), border-color .3s var(--e-soft);
}
.lb__btn:hover { background: rgba(255, 255, 255, .14); border-color: #fff; }
.lb__btn svg { width: 16px; height: 16px; }
.lb__x    { top: clamp(.75rem, 3vw, 2rem); right: clamp(.75rem, 3vw, 2rem); }
.lb__prev { left: .5rem;  top: 50%; transform: translateY(-50%); }
.lb__next { right: .5rem; top: 50%; transform: translateY(-50%); }

/* ==========================================================================
   15. OFFER
   ========================================================================== */

.offer { display: grid; gap: 2.2rem; align-items: center; }
.offer__card {
  background: var(--white);
  border: 1px solid var(--line);
  padding: clamp(1.5rem, 4vw, 3.2rem);
  box-shadow: var(--shadow-m);
}
.offer__price {
  font-family: var(--ff-display);
  font-size: clamp(2.8rem, 2rem + 4vw, 4.6rem);
  color: var(--ink);
  line-height: 1;
  margin-bottom: .15em;
}
.offer__price small {
  display: block;
  font-family: var(--ff-sans);
  font-size: .66rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold-dd);
  margin-bottom: .6rem;
}
.checks { list-style: none; margin: 1.5rem 0 0; padding: 0; display: grid; gap: .8rem; }
.checks li { display: grid; grid-template-columns: 18px 1fr; gap: .75rem; align-items: start; font-size: .9rem; line-height: 1.58; }
.checks svg { width: 18px; height: 18px; margin-top: .3em; color: var(--sage-d); }
.checks b { color: var(--ink); font-weight: 500; }

.tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; margin-top: 1.5rem; }
.compare { width: 100%; min-width: 460px; border-collapse: collapse; font-size: .86rem; }
.compare th, .compare td {
  padding: .78rem .5rem;
  text-align: left;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: top;
}
.compare th {
  font-family: var(--ff-sans);
  font-size: .62rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.compare td:last-child, .compare th:last-child { text-align: right; }
.compare tr:last-child td { border-bottom: 0; }
.compare .is-us td { background: rgba(198, 173, 143, .13); color: var(--ink); }

/* ==========================================================================
   16. FAQ
   ========================================================================== */

.faq { max-width: 840px; margin: clamp(2rem, 4vw, 3.5rem) auto 0; }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__q {
  width: 100%;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.2rem;
  padding: 1.25rem 0;
  background: none;
  border: 0;
  cursor: pointer;
  text-align: left;
  font-family: var(--ff-display);
  font-size: clamp(1.1rem, 1rem + .4vw, 1.4rem);
  font-weight: 400;
  color: var(--ink);
  line-height: 1.3;
  transition: color .3s var(--e-soft);
}
.faq__q:hover { color: var(--gold-dd); }
.faq__i { flex: none; position: relative; width: 15px; height: 15px; margin-top: .4em; }
.faq__i::before, .faq__i::after {
  content: "";
  position: absolute;
  background: var(--gold-d);
  transition: transform .4s var(--e), opacity .4s var(--e);
}
.faq__i::before { top: 7px; left: 0; width: 15px; height: 1px; }
.faq__i::after  { left: 7px; top: 0; width: 1px; height: 15px; }
.faq__q[aria-expanded="true"] .faq__i::after { transform: rotate(90deg); opacity: 0; }

.faq__a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .5s var(--e); }
.faq__a > div { overflow: hidden; }
.faq__item.is-open .faq__a { grid-template-rows: 1fr; }
.faq__a p { font-size: .94rem; max-width: 68ch; }
.faq__a > div > :last-child { padding-bottom: 1.4rem; }

/* ==========================================================================
   16b. STATEMENT BAND — a full-bleed photograph with centred type over it
   ========================================================================== */

.statement {
  position: relative;
  isolation: isolate;
  color: rgba(255, 255, 255, .82);
  overflow: hidden;
}
.statement__media { position: absolute; inset: 0; z-index: -2; }
.statement__media img,
.statement__vid {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 55%;
}
.statement::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(105% 75% at 50% 50%,
      rgba(18,17,15,.70) 0%, rgba(18,17,15,.52) 52%, rgba(18,17,15,.30) 100%);
}
.statement h2, .statement .lead { text-shadow: 0 1px 24px rgba(18, 17, 15, .5); }
.statement h2 { color: #fff; }
.statement h2 .script { color: var(--gold); }
.statement .overline { color: var(--gold); }
.statement :where(p) { color: rgba(255, 255, 255, .84); }
.statement .rule::before, .statement .rule::after { background: var(--line-invert); }
.statement__sign {
  margin-top: 1.2rem;
  font-size: var(--fs-label);
  letter-spacing: .28em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .6);
}

/* ==========================================================================
   17. CLOSING CTA
   ========================================================================== */

.cta { position: relative; isolation: isolate; color: #fff; text-align: center; overflow: hidden; }
.cta__media { position: absolute; inset: 0; z-index: -2; }
.cta__media img { width: 100%; height: 100%; object-fit: cover; }
.cta::before { content: ""; position: absolute; inset: 0; z-index: -1; background: rgba(24, 23, 20, .72); }
.cta h2 { color: #fff; }
.cta .overline { color: var(--gold); }
.cta :where(p) { color: rgba(255, 255, 255, .88); }

/* ==========================================================================
   18. FOOTER
   ========================================================================== */

.footer {
  background: var(--ink);
  color: rgba(255, 255, 255, .62);
  font-size: .86rem;
  padding-top: clamp(2.6rem, 6vw, 5rem);
  /* 62px bar + slack, plus the home indicator on notched phones */
  padding-bottom: calc(72px + env(safe-area-inset-bottom));
}
.footer a { color: rgba(255, 255, 255, .78); transition: color .3s var(--e-soft); }
.footer a:hover { color: var(--gold); }
.footer__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.8rem; padding-bottom: 2.2rem; }
.footer__brandcol { grid-column: 1 / -1; }
.footer .brand { color: #fff; justify-self: start; text-align: left; grid-column: auto; }
.footer .brand__sub { justify-content: flex-start; }
/* text-indent na .brand__name istnieje po to, żeby zrównoważyć rozstrzelenie
   dopisane po ostatniej literze — przy napisie wyśrodkowanym w nagłówku to
   ustawia tusz na osi. W stopce logo stoi do lewej, więc ten sam wcięcie
   przesuwa „BRIDES" w prawo względem kreski i „BINDERY" pod spodem. */
.footer .brand__name { text-indent: 0; }
.footer .brand__rule { background: rgba(255, 255, 255, .35); }
.footer__blurb { margin-top: 1.2rem; max-width: 40ch; line-height: 1.65; }
.footer .footer__h {
  color: #fff;
  font-family: var(--ff-sans);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  margin-bottom: .9rem;
}
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.footer__bar {
  border-top: 1px solid var(--line-invert);
  padding-block: 1.4rem;
  display: grid;
  gap: .8rem;
  font-size: .76rem;
  color: rgba(255, 255, 255, .45);
}
.footer__bar nav { display: flex; flex-wrap: wrap; gap: 1.2rem; }

/* ==========================================================================
   19. STICKY MOBILE CTA
   ========================================================================== */

.stickycta {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 45;
  padding: .6rem var(--gut) calc(.6rem + env(safe-area-inset-bottom));
  background: rgba(251, 249, 246, .97);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--line);
  transform: translateY(110%);
  transition: transform .45s var(--e);
}
.stickycta.is-shown { transform: none; }

/* ==========================================================================
   20. BREADCRUMBS + PROSE + PAGE HEAD
   ========================================================================== */

.crumbs {
  font-size: .7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--fg-muted);
  padding-block: 1.1rem;
  border-bottom: 1px solid var(--line-soft);
}
.crumbs ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .5rem; }
.crumbs li + li::before { content: "/"; margin-right: .5rem; color: var(--line); }
.crumbs a:hover { color: var(--gold-dd); }

.pagehead {
  background: var(--bg-warm);
  text-align: center;
  padding-block: clamp(2.6rem, 7vw, 6rem) clamp(2rem, 5vw, 4rem);
  border-bottom: 1px solid var(--line-soft);
}
.pagehead h1 { font-size: var(--fs-h1-inner); }

/* A page head with a photograph or a film running behind it. Same scrim logic
   as the hero — a radial
   pass under the type and a linear pass anchoring the edges — so white text
   stays legible over a bright wall without flattening the picture to grey.
   The header sits over this block, hence the negative top margin. */
.pagehead--cover {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-bottom: 0;
  background: #1c1917;
  color: #fff;
  margin-top: calc(var(--hdr-h) * -1);
  padding-block: calc(var(--hdr-h) + clamp(3rem, 8vw, 6rem)) clamp(3rem, 7vw, 5.5rem);
}
.pagehead__vid,
.pagehead__img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 42%;
}
.pagehead--cover::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(120% 88% at 50% 50%,
      rgba(18,17,15,.70) 0%, rgba(18,17,15,.50) 48%, rgba(18,17,15,.16) 100%),
    linear-gradient(180deg,
      rgba(18,17,15,.66) 0%, rgba(18,17,15,.34) 32%, rgba(18,17,15,.60) 100%);
}
.pagehead--cover .overline { color: rgba(255, 255, 255, .84); }
.pagehead--cover h1 { color: #fff; text-shadow: 0 1px 30px rgba(18, 17, 15, .38); }
.pagehead--cover .lead {
  color: rgba(255, 255, 255, .91);
  text-shadow: 0 1px 16px rgba(18, 17, 15, .45);
}

/* The photograph variant, and it has to come after the block above: a film is
   moving and busy, so it takes the heavier scrim; a still photograph is the
   thing the page is about and disappears under the same treatment. Source order
   is what decides this — both selectors carry identical specificity. */
.pagehead--photo {
  /* Sized so the source is not upscaled into mush: the widest derivative is
     1280x548, so the band stays close to that shape instead of being padded
     into a portrait window and cropped to a letterbox. */
  padding-block: calc(var(--hdr-h) + clamp(2rem, 5vw, 3.6rem)) clamp(2rem, 4.5vw, 3.4rem);
}
.pagehead--photo::before {
  background:
    radial-gradient(115% 82% at 50% 50%,
      rgba(18,17,15,.62) 0%, rgba(18,17,15,.40) 50%, rgba(18,17,15,.08) 100%),
    linear-gradient(180deg,
      rgba(18,17,15,.56) 0%, rgba(18,17,15,.22) 36%, rgba(18,17,15,.50) 100%);
}
.pagehead--photo .pagehead__img { object-position: center 58%; }

.prose { max-width: var(--shell-text); margin-inline: auto; }
/* products.html: a .split__body is a product block, not a reading column, so the
   product names take the site h3 scale rather than the smaller prose one */
.split__body.prose h3 { font-size: var(--fs-h3); margin-top: 0; }
.prose h2 { font-size: clamp(1.55rem, 1.3rem + 1.1vw, 2.2rem); margin-top: 2.2em; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { font-size: 1.25rem; margin-top: 1.7em; }
.prose ul, .prose ol { padding-left: 1.15rem; margin: 0 0 1.1em; }
.prose li { margin-bottom: .45em; }
.prose a { color: var(--gold-dd); text-decoration: underline; text-underline-offset: 3px; }
.prose table { width: 100%; border-collapse: collapse; margin: 1.4em 0; font-size: .9rem; }
.prose th, .prose td { padding: .65rem .55rem; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
.prose th { font-family: var(--ff-sans); font-size: .64rem; letter-spacing: .15em; text-transform: uppercase; color: var(--fg-muted); font-weight: 500; }

/* internal-link block, both for readers and for crawl depth */
.relate { display: grid; gap: .8rem; margin-top: clamp(2.2rem, 5vw, 3.5rem); }
.relate a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.05rem 1.2rem;
  border: 1px solid var(--line);
  background: var(--white);
  font-size: .93rem;
  transition: border-color .35s var(--e), background .35s var(--e);
}
@media (hover: hover) { .relate a:hover { border-color: var(--gold); background: var(--paper); } }
.relate span { font-size: .62rem; letter-spacing: .16em; text-transform: uppercase; color: var(--gold-dd); flex: none; }

/* ==========================================================================
   21. ≥560px — two-up cards, side-by-side form
   ========================================================================== */

@media (min-width: 560px) {
  /* Orphan control. Between 560 and 900 these grids run two- or three-up, and
     an item count that does not divide evenly leaves a lone card sitting in a
     half-empty row. Letting the odd one out span the row reads as a decision
     rather than an accident. */
  .grid--3 > :last-child:nth-child(odd),
  .grid--4 > :last-child:nth-child(odd) { grid-column: 1 / -1; }

  .capture__row { grid-template-columns: 1fr auto; }
  .grid--2 { grid-template-columns: 1fr 1fr; }
  .grid--3 { grid-template-columns: 1fr 1fr; }
  .card h3 { font-size: 1.24rem; }
  .card p { font-size: .875rem; }
  .footer__grid { grid-template-columns: repeat(3, 1fr); }
  .footer__bar { grid-template-columns: 1fr auto; align-items: center; }
  .mat__preview { grid-template-columns: clamp(168px, 30vw, 260px) 1fr; }
  .mat__grid { grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); }
  .gallery { grid-template-columns: repeat(3, 1fr); }
  .gallery > :last-child:nth-child(3n + 2) { grid-column: span 2; }
}

/* ==========================================================================
   21b. ≥620px — the awkward middle
   --------------------------------------------------------------------------
   Between 560 and 900 the page used to leave .steps, .craft and .films at one
   column, which on a tablet meant a 715px-wide image above two lines of text,
   three times over. Here those blocks go horizontal instead: the image takes a
   third, the text takes the rest. The ≥900 rules below reset them to the
   stacked three-up card, which is what the layout was designed as.
   ========================================================================== */

@media (min-width: 620px) {
  .step, .craft__item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
    column-gap: clamp(1.2rem, 3vw, 2rem);
    align-items: start;
  }
  .step__n, .step h3, .step p,
  .craft__item h3, .craft__item p, .craft__item dl { grid-column: 2; }
  .step .frame, .craft__item .frame {
    grid-column: 1;
    grid-row: 1 / span 4;
    margin-bottom: 0;
    align-self: start;
  }
  .step .frame { aspect-ratio: 3 / 4; }
  .step .frame img, .craft__item .frame img { height: 100%; }

  /* Films: two-up rather than a stack of full-width posters. */
  .films { grid-template-columns: repeat(6, 1fr); }
  .film--hero { grid-column: span 6; }
  .film--half { grid-column: span 3; }
}

/* ==========================================================================
   22. ≥900px — the desktop nav fits; sections go multi-column
   ========================================================================== */

@media (min-width: 900px) {

  .hero { min-height: min(100svh, 940px); }
  .hero__cue {
    display: grid;
    position: absolute;
    left: 50%; bottom: 1.8rem;
    transform: translateX(-50%);
    justify-items: center;
    gap: .55rem;
    font-size: .58rem;
    letter-spacing: .3em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .7);
  }
  .hero__cue i {
    display: block;
    width: 1px; height: 40px;
    background: linear-gradient(rgba(255,255,255,.7), rgba(255,255,255,0));
    animation: cue 2.4s var(--e-soft) infinite;
  }
  @keyframes cue {
    0%, 100% { transform: scaleY(.35); opacity: .35; transform-origin: top; }
    50%      { transform: scaleY(1);   opacity: 1;   transform-origin: top; }
  }
  /* The drift used to run 1.03 -> 1.11, which quietly magnified the photograph
     on top of the magnification the display already forces. The source is
     2000px wide; a 1512pt Retina laptop asks for 3024 device pixels before the
     animation, so an extra 11% took the enlargement to 1.68x and the softness
     was visible. Now it starts at native scale and drifts by 4%, and the
     sharpest moment is the one the visitor lands on. */
  .hero__media img { animation: heroDrift 30s var(--e-soft) infinite alternate; }
  @keyframes heroDrift { from { transform: scale(1); } to { transform: scale(1.04); } }

  .split { grid-template-columns: 1fr 1fr; gap: clamp(2rem, 5vw, 5rem); }
  .split--flip .split__media { order: 2; }
  .split--flip .split__body { margin-left: auto; }
  .split__media { position: relative; isolation: isolate; }
  .split__media::after {
    content: "";
    position: absolute;
    inset: auto -16px -16px auto;
    width: 60%; height: 60%;
    border: 1px solid var(--gold);
    z-index: -1;
  }

  .steps { grid-template-columns: repeat(3, 1fr); gap: clamp(1.5rem, 3.4vw, 3.2rem); }
  .craft { grid-template-columns: repeat(3, 1fr); gap: clamp(1.6rem, 3.2vw, 3rem); }
  /* undo the ≥620 horizontal arrangement — three-up cards stack again */
  .step, .craft__item { display: block; }
  .step .frame, .craft__item .frame { margin-bottom: 1.2rem; }
  .step .frame { aspect-ratio: 3 / 2; }
  .grid { gap: clamp(1rem, 2vw, 1.9rem); }
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
  .grid--4 { grid-template-columns: repeat(4, 1fr); }
  .grid--3 > :last-child:nth-child(odd),
  .grid--4 > :last-child:nth-child(odd) { grid-column: auto; }

  .films { grid-template-columns: repeat(6, 1fr); }
  .film--hero { grid-column: span 6; }
  .film--half { grid-column: span 2; }

  .mat { grid-template-columns: 320px 1fr; gap: clamp(1.8rem, 4vw, 3.8rem); align-items: start; }
  .mat__preview { position: sticky; top: calc(var(--hdr-h) + 24px); display: block; }
  .mat__name { margin-top: 1rem; }
  .mat__grid { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: .55rem; }

  .gallery { grid-template-columns: repeat(12, 1fr); gap: clamp(.5rem, 1.2vw, 1rem); }
  .gallery > :last-child:nth-child(3n + 2) { grid-column: span 4; }
  .gallery button { aspect-ratio: auto; }
  .gallery .g-3 { grid-column: span 3; }
  .gallery .g-4 { grid-column: span 4; }
  .gallery .g-5 { grid-column: span 5; }
  .gallery .g-7 { grid-column: span 7; }

  .offer { grid-template-columns: 1.05fr .95fr; gap: clamp(2rem, 5vw, 5rem); }
  .relate { grid-template-columns: repeat(3, 1fr); }

  .trust__grid { grid-template-columns: repeat(4, 1fr); }
  .trust__item { border-top: 0; }
  /* the odd-child rule below is written for the two-column phone layout and has
     to be re-asserted here, or dividers 1 and 3 go missing at four columns */
  .trust__item:nth-child(odd) { border-left: 1px solid var(--line-soft); }
  .trust__item:first-child { border-left: 0; }

  .footer__grid { grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: clamp(1.8rem, 4vw, 3.5rem); padding-bottom: clamp(2.5rem, 5vw, 4rem); }
  .footer__brandcol { grid-column: auto; }
}

/* ==========================================================================
   22b. ≥1100px — the desktop header finally fits
   --------------------------------------------------------------------------
   Measured, not guessed: two nav groups, the wordmark, the CTA and the language
   switcher need about 1090px before they stop competing for the same row.
   Below this the burger and the sticky bar stay, which is why nothing here has
   to be undone anywhere else.
   ========================================================================== */

@media (min-width: 1100px) {
  :root { --hdr-h: 96px; }   /* measured, not guessed: brand lockup + padding */

  .header__in {
    grid-template-columns: 1fr auto 1fr;
    padding-block: .8rem;
  }
  .header.is-stuck .header__in { padding-block: .55rem; }
  .burger { display: none; }
  .drawer { display: none; }

  .nav { display: flex; align-items: center; gap: clamp(.9rem, 1.7vw, 2rem); }
  .nav--l { grid-column: 1; justify-self: start; }
  .nav--r { grid-column: 3; justify-self: end; }
  .nav__link {
    font-size: var(--fs-label);
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--ink);
    padding-block: .4rem;
    position: relative;
    white-space: nowrap;
    transition: color .35s var(--e-soft);
  }
  .nav__link::after {
    content: "";
    position: absolute;
    left: 0; bottom: 0;
    width: 100%; height: 1px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: right center;
    transition: transform .45s var(--e);
  }
  .nav__link:hover::after,
  .nav__link.is-active::after,
  .nav__link[aria-current="page"]::after { transform: scaleX(1); transform-origin: left center; }
  .header .btn { display: inline-flex; }
  .stickycta { display: none; }
  .footer { padding-bottom: 0; }
}

/* ==========================================================================
   23. ≥1120px — final breathing room
   ========================================================================== */

@media (min-width: 1120px) {
  .grid--2 { grid-template-columns: 1fr 1fr; }
  .film--half { grid-column: span 2; }
  .mat__grid { grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); }
}

/* ==========================================================================
   24. PRINT
   ========================================================================== */

@media print {
  .header, .topbar, .stickycta, .drawer, .hero__cue, .films, .lb { display: none !important; }
  body { color: #000; background: #fff; }
  .section { padding-block: 1.5rem; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .8em; }
}

/* ==========================================================================
   25. WALL PLANNER  (/dress-your-wall/)
   --------------------------------------------------------------------------
   The stage holds the visitor's own photograph and the frames are drawn over
   it as percentages of the wall's width, so the preview stays true at any
   screen size. See assets/js/wall.js for the arithmetic.
   ========================================================================== */

.wall { display: grid; gap: 1.5rem; margin-top: clamp(2rem, 4vw, 3rem); }

.wall__stage {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--cream-2);
  border: 1px solid var(--line);
  touch-action: none;               /* the composition is dragged, not scrolled */
}
.wall__plate {
  position: absolute;
  inset: 0;
  background: var(--cream-2) center/cover no-repeat;
}
/* the empty state: a drawn room rather than a grey void */
.wall__stage:not(.has-photo) .wall__plate {
  background:
    linear-gradient(180deg, #efe9e1 0%, #efe9e1 72%, #e2d8cb 72%, #ddd2c3 100%);
}
.wall__empty {
  position: absolute;
  left: 50%; bottom: 1.2rem;
  transform: translateX(-50%);
  z-index: 3;
  font-size: .78rem;
  letter-spacing: .08em;
  color: var(--fg-muted);
  background: rgba(255, 255, 255, .86);
  padding: .5rem .9rem;
  pointer-events: none;
}
.wall__stage.has-photo .wall__empty { display: none; }

.wall__comp {
  position: absolute;
  transform: translate(-50%, -50%);
  cursor: grab;
  z-index: 2;
}
.wall__comp.is-dragging { cursor: grabbing; }
.wall__comp:focus-visible { outline: 2px solid var(--gold); outline-offset: 6px; }

.wall__frame {
  position: absolute;
  border: 1px solid;
  box-shadow: 0 6px 18px rgba(20, 18, 14, .28);
  display: grid;
  place-items: stretch;
  padding: 6%;
}
.wall__mount {
  display: block;
  background: linear-gradient(150deg, #fbf9f6 0%, #ece5da 100%);
  box-shadow: inset 0 0 0 1px rgba(20, 18, 14, .1);
}

/* --- controls ------------------------------------------------------------ */
.wall__panel { display: grid; gap: 1.4rem; align-content: start; }
.wall__group { display: grid; gap: .6rem; }
.wall__label {
  font-size: var(--fs-label);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gold-dd);
}

.wall__drop {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: 1rem 1.1rem;
  border: 1px dashed var(--line);
  background: var(--white);
  cursor: pointer;
  font-size: .92rem;
  transition: border-color .3s var(--e-soft), background .3s var(--e-soft);
}
.wall__drop:hover { border-color: var(--gold); background: var(--paper); }
.wall__drop svg { width: 22px; height: 22px; color: var(--gold-d); flex: none; }
.wall__file { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

.wall__width { width: 100%; accent-color: var(--gold-d); }
.wall__width-out { font-size: .88rem; color: var(--fg-muted); }

.wall__chips { display: flex; flex-wrap: wrap; gap: .4rem; }
.wall__chip {
  min-height: 40px;
  padding: .5em 1em;
  border: 1px solid var(--line);
  background: var(--white);
  font-family: var(--ff-sans);
  font-size: .8rem;
  color: var(--fg);
  cursor: pointer;
  transition: border-color .3s var(--e-soft), color .3s var(--e-soft), background .3s var(--e-soft);
}
.wall__chip[aria-pressed="true"] { border-color: var(--ink); background: var(--ink); color: #fff; }

.wall__colours { display: flex; gap: .5rem; }
.wall__swatch {
  width: 34px; height: 34px;
  border: 1px solid;
  border-radius: 50%;
  cursor: pointer;
  padding: 0;
  transition: transform .3s var(--e), box-shadow .3s var(--e);
}
.wall__swatch[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--white), 0 0 0 3px var(--ink); }

.wall__readout {
  font-family: var(--ff-display);
  font-size: 1.05rem;
  color: var(--ink);
  line-height: 1.4;
}
.wall__hint { font-size: .85rem; color: var(--fg-muted); }

@media (min-width: 900px) {
  .wall { grid-template-columns: 1.55fr 1fr; gap: clamp(1.8rem, 4vw, 3rem); align-items: start; }
  .wall__panel { position: sticky; top: calc(var(--hdr-h) + 24px); }
}

/* ==========================================================================
   26. NAV DROPDOWN — the "Albums" group
   --------------------------------------------------------------------------
   One component, two shapes. In the header it is a panel that drops below the
   bar; in the mobile drawer (.navdrop--stack) it is a disclosure that pushes
   the list down. Both are driven by the same button with aria-expanded, so
   there is one behaviour to reason about and it is reachable by keyboard.
   Base styles describe the drawer, because that is the narrow case.
   ========================================================================== */

.navdrop { position: relative; }

.navdrop__btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  width: 100%;
  padding: .55rem 0;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--line-soft);
  cursor: pointer;
  font-family: var(--ff-display);
  font-size: 1.6rem;
  font-weight: 300;
  color: var(--ink);
  text-align: left;
}
.navdrop__btn svg {
  width: 12px; height: 8px;
  flex: none;
  transition: transform .35s var(--e);
}
.navdrop__btn[aria-expanded="true"] svg { transform: rotate(180deg); }

/* The drawer disclosure animates on max-height rather than grid-template-rows:
   the 0fr trick only collapses the FIRST row, and this menu has six children,
   so it stayed open. The cap is generous (six items come to ~290px) and the
   easing hides the imprecision; if the group ever grows past ten items, raise it. */
.navdrop__menu {
  display: block;
  overflow: hidden;
  max-height: 0;
  transition: max-height .4s var(--e);
}
.navdrop.is-open > .navdrop__menu { max-height: 34rem; }
.navdrop--stack .navdrop__menu a {
  display: block;
  font-family: var(--ff-display);
  font-size: 1.25rem;
  color: var(--ink-2);
  padding: .45rem 0 .45rem 1.1rem;
  border-bottom: 1px solid var(--line-soft);
}
.navdrop--stack .navdrop__menu a:first-child { padding-top: .8rem; }
.navdrop__rule { display: none; }

@media (min-width: 1100px) {
  .navdrop__btn {
    width: auto;
    border: 0;
    padding-block: .4rem;
    font-family: var(--ff-sans);
    font-size: var(--fs-label);
    letter-spacing: .18em;
    text-transform: uppercase;
    color: inherit;
    white-space: nowrap;
  }
  .navdrop__btn svg { width: 9px; height: 6px; opacity: .7; }

  /* In the bar the panel floats, so it must not participate in the grid-rows
     animation used by the drawer — it fades and lifts instead. */
  .navdrop__menu {
    position: absolute;
    top: calc(100% + .9rem);
    left: -1.1rem;
    display: block;
    max-height: none;
    overflow: visible;
    min-width: 232px;
    padding: .5rem 0;
    background: var(--paper);
    border: 1px solid var(--line-soft);
    box-shadow: var(--shadow-m);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-6px);
    transition: opacity .25s var(--e-soft), transform .25s var(--e-soft), visibility .25s;
  }
  .navdrop.is-open > .navdrop__menu { opacity: 1; visibility: visible; transform: none; }
  .navdrop__menu a {
    display: block;
    padding: .5rem 1.1rem;
    font-family: var(--ff-sans);
    font-size: .82rem;
    font-weight: 300;
    color: var(--ink-2);
    white-space: nowrap;
    transition: background .25s var(--e-soft), color .25s var(--e-soft);
  }
  .navdrop__menu a:hover { background: var(--white); color: var(--ink); }
  .navdrop__rule {
    display: block;
    height: 1px;
    margin: .45rem 1.1rem;
    background: var(--line-soft);
  }
  /* the panel is light in both header states, so its type stays dark */
  .header--over .navdrop__menu a { color: var(--ink-2); }
}

/* ==========================================================================
   27. STEP TWO — the wider form, on its own page
   --------------------------------------------------------------------------
   The email is already saved by the time anyone sees this, which is the whole
   reason the form is split in two: an abandoned second step still leaves us a
   lead, where an abandoned six-field form leaves nothing. So everything here
   is optional, and the way out is visible rather than hidden.
   ========================================================================== */

.step2 { max-width: 640px; margin: 2.2rem auto 0; }
.step2__pair { display: grid; gap: 1.1rem; margin-bottom: 1.3rem; }
.step2 label > span,
.step2 legend {
  display: block;
  font-size: var(--fs-label);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-bottom: .5rem;
}
.step2 input,
.step2 select,
.step2 textarea {
  width: 100%;
  padding: .85em 1em;
  font-family: var(--ff-sans);
  font-size: 1rem;                  /* 16px — stops iOS zooming on focus */
  font-weight: 300;
  line-height: 1.5;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 0;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color .3s var(--e-soft);
}
.step2 textarea { resize: vertical; min-height: 5.5em; }

/* Reszta odpowiedzi w tym formularzu to chipy (patrz niżej) i tak jest lepiej.
   Kierunkowy jest wyjątkiem: prawie trzydzieści krajów nie zmieści się w
   chipach, a wpisywanie „+48" ręcznie okazało się mylące. */
.step2 select {
  padding-right: 2.6em;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23857f77' stroke-width='1.3'%3E%3Cpath d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1em center;
  background-size: 12px 8px;
}
/* Dopóki nic nie wybrano, „Kierunkowy" jest podpowiedzią, nie odpowiedzią, więc
   dostaje kolor placeholdera. Pole nie jest wymagane, więc :invalid tu nie
   zadziała — stąd :has(). Starsze przeglądarki pokażą zwykły ink i tyle. */
.step2 select:has(option[value=""]:checked) { color: var(--ink-3); }
.step2 input:focus,
.step2 select:focus,
.step2 textarea:focus { border-color: var(--gold); outline: none; }
.step2 input::placeholder,
.step2 textarea::placeholder { color: var(--ink-3); }

.step2__full { display: block; margin-bottom: 1.3rem; }
.step2 small {
  display: block;
  margin-top: .5rem;
  font-size: .78rem;
  line-height: 1.55;
  color: var(--fg-muted);
}
.step2__choice { border: 0; padding: 0; margin: 0 0 1.3rem; }

/* Chips rather than a select: one tap on a phone instead of three, and the
   whole set of answers is readable at a glance instead of hidden in a list. */
.chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.chip { position: relative; }
.chip input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.chip span {
  display: inline-block;
  padding: .6em 1.1em;
  border: 1px solid var(--line);
  background: #fff;
  font-size: .86rem;
  cursor: pointer;
  transition: border-color .25s var(--e-soft), background .25s var(--e-soft),
              color .25s var(--e-soft);
}
.chip input:checked + span {
  border-color: var(--ink);
  background: var(--ink);
  color: #fff;
}
/* The focus ring has to come from us: the real control is visually hidden. */
.chip input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (hover: hover) {
  .chip:hover span { border-color: var(--gold); }
  .chip input:checked + span { border-color: var(--ink); }
}

.step2__act {
  display: flex;
  align-items: center;
  gap: 1.4rem;
  margin-top: 1.8rem;
  flex-wrap: wrap;
}
.step2 .form-msg { margin-inline: 0; }

@media (min-width: 620px) {
  .step2__pair { grid-template-columns: 1fr 1fr; }
}

/* ==========================================================================
   28. CONSENT — the analytics cookie question
   --------------------------------------------------------------------------
   A bar, not a modal, and not a full-screen interruption. The two answers carry
   equal weight: under the GDPR refusing has to be as easy as accepting, and a
   greyed-out "no" is the tell of a site that would rather you did not find it.
   Nothing about analytics loads until this is answered.
   ========================================================================== */

.consent {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 60;                       /* above the sticky CTA, below nothing */
  background: var(--bg-alt);
  border-top: 1px solid var(--line);
  box-shadow: 0 -6px 32px rgba(34, 33, 31, .10);
  padding: 1.1rem var(--gut) calc(1.1rem + env(safe-area-inset-bottom));
  transform: translateY(110%);
  transition: transform .45s var(--e);
}
.consent.is-shown { transform: none; }
.consent[hidden] { display: none; }

.consent__in {
  max-width: 1080px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.consent__t {
  margin: 0 0 .3rem;
  font-family: var(--ff-display);
  font-size: 1.12rem;
  color: var(--fg-strong);
}
.consent__d {
  margin: 0;
  font-size: .84rem;
  line-height: 1.6;
  color: var(--fg);
  max-width: 68ch;
}
.consent__d a { color: var(--gold-dd); text-decoration: underline; text-underline-offset: 2px; }

.consent__act { display: flex; gap: .7rem; flex-wrap: wrap; }
.consent__act .btn { flex: 1 1 auto; }

@media (min-width: 720px) {
  .consent__in { flex-direction: row; align-items: center; justify-content: space-between; gap: 2rem; }
  .consent__act { flex: none; }
  .consent__act .btn { flex: none; }
}

/* The sticky mobile CTA and this bar would otherwise sit on top of each other. */
.consent.is-shown ~ .stickycta,
body:has(.consent.is-shown) .stickycta { display: none; }

/* ==========================================================================
   29. INSTAGRAM — masonry board
   --------------------------------------------------------------------------
   Photographs held here, tiles linking to the real posts. Instagram closed the
   Basic Display API in December 2024 and a signed-out request returns only a
   login wall, so there is no feed to embed; a third-party widget would drag in
   somebody else's JavaScript and cookies, which this site promises it does not
   do. Twelve pictures refreshed by hand each quarter cost nothing to load and
   cannot break.

   CSS columns rather than grid: `grid-template-rows: masonry` is still not
   shipping widely, and columns give the same staggered board with no
   JavaScript measuring anything. The trade is that reading order runs down each
   column instead of across — which for a wall of photographs nobody reads in
   order is no trade at all.
   ========================================================================== */

.ig {
  columns: 2;
  column-gap: 10px;
  margin-top: 2.2rem;
}
.ig__tile {
  position: relative;
  display: block;
  overflow: hidden;
  margin-bottom: 10px;
  background: var(--cream-2);
  /* It is a <button> now, so the browser's own button styling has to go. */
  padding: 0;
  border: 0;
  width: 100%;
  cursor: zoom-in;
  -webkit-appearance: none;
  appearance: none;
  /* Without this a tile can be split across two columns mid-photograph. */
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
}
.ig__tile img {
  width: 100%;
  height: auto;
  display: block;
  transition: transform .6s var(--e);
}
/* The wash is how a tile says it is a link, without a badge sitting on top of
   somebody's photograph. */
.ig__tile::after {
  content: "";
  position: absolute; inset: 0;
  background: rgba(18, 17, 15, .26);
  opacity: 0;
  transition: opacity .4s var(--e);
}
@media (hover: hover) {
  .ig__tile:hover img { transform: scale(1.04); }
  .ig__tile:hover::after { opacity: 1; }
}
.ig__tile:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }


@media (min-width: 620px) { .ig { columns: 3; column-gap: 12px; } .ig__tile { margin-bottom: 12px; } }
@media (min-width: 1000px) { .ig { columns: 4; column-gap: 14px; } .ig__tile { margin-bottom: 14px; } }

/* The board wants the width Marcin asked for — 80% of the window — rather than
   the reading measure the rest of the page uses. Capped so it does not sprawl
   into six columns of thumbnails on a very wide display. */
.ig__board { max-width: min(80vw, 1500px); margin-inline: auto; }

/* The board's filter reuses the material tabs' look so the page has one idiom,
   but centred, because it sits under a centred heading rather than beside a
   swatch grid. */
.ig__tabs { justify-content: center; border-bottom: 0; padding-bottom: 0; margin-bottom: 1.6rem; }

/* ==========================================================================
   30. DARK PAGE THEME  (body.theme-dark — /boudoir-album/)
   --------------------------------------------------------------------------
   One page on this site is dark on purpose: a boudoir album is looked at in a
   bedroom, not in a showroom, and the page should feel like the object.

   Flipping the semantic tokens gets about eighty per cent of the way there.
   The rest of this block is the other twenty: every selector on this page that
   writes a colour literal or reaches past the semantic layer into the raw
   palette. Those do not follow the flip, and a missed one is white text on a
   white card in production — so each is named here rather than trusted.

   The accent flips too. --gold-dd is 2.6:1 on this ground, which is not a
   colour, it is a rumour; --gold is 8.6:1 and carries every accent instead.
   ========================================================================== */

body.theme-dark {
  --bg:        #17151a;
  --bg-alt:    #1c191f;
  --bg-warm:   #201c25;
  --bg-dark:   #131116;

  --fg:        rgba(255, 255, 255, .74);
  --fg-strong: #ffffff;
  --fg-muted:  rgba(255, 255, 255, .54);

  --line:      rgba(255, 255, 255, .17);
  --line-soft: rgba(255, 255, 255, .09);
  --shadow-s:  0 2px 10px rgba(0, 0, 0, .5);
  --shadow-m:  0 14px 44px rgba(0, 0, 0, .6);

  --focus: var(--gold);
}

/* --- accents that reached past the semantic layer ------------------------- */
.theme-dark .overline,
.theme-dark .script,
.theme-dark .relate span,
.theme-dark .crumbs a:hover { color: var(--gold); }
.theme-dark .prose a { color: var(--gold); }
.theme-dark .trust__item svg { color: var(--gold); }
.theme-dark .trust__item b { color: var(--fg-strong); }
.theme-dark .tlink { color: #fff; background-image: linear-gradient(var(--gold), var(--gold)); }
.theme-dark .tlink:hover { color: var(--gold); }

/* --- surfaces that carried a light literal ------------------------------- */
.theme-dark .frame { background: rgba(255, 255, 255, .06); }
.theme-dark .relate a {
  background: rgba(255, 255, 255, .04);
  border-color: var(--line);
  color: var(--fg-strong);
}
.theme-dark .relate a:hover { background: rgba(255, 255, 255, .08); }

/* The skip link is the first thing a keyboard reaches. Dark-on-dark would
   make it invisible exactly where invisibility is a defect. */
.theme-dark .skip-link { background: #fff; color: var(--ink); }

/* The default button is near-black on near-white. Here that is a dark box on a
   dark ground, so the primary action takes the accent instead — which also
   makes the gold hover wipe a no-op rather than a colour change, so the hover
   is carried by the border and the label. */
.theme-dark .btn { --btn-bg: var(--gold); --btn-fg: var(--ink); --btn-bd: var(--gold); }
.theme-dark .btn::after { background: #fff; }
.theme-dark .btn--ghost { --btn-bg: transparent; --btn-fg: #fff; --btn-bd: var(--line); }

/* --- header, drawer and the panels that hang off them --------------------- */
.theme-dark .header.is-stuck {
  background: rgba(23, 21, 26, .94);
  box-shadow: var(--shadow-s), inset 0 -1px 0 var(--line-soft);
}
.theme-dark .header.is-stuck .nav__link,
.theme-dark .header.is-stuck .brand,
.theme-dark .header.is-stuck .burger { color: #fff; }
.theme-dark .header.is-stuck .brand__rule { background: var(--line); }
.theme-dark .header.is-stuck .btn--ghost { --btn-fg: #fff; --btn-bd: var(--line); }

.theme-dark .navdrop__menu { background: #211d26; border-color: var(--line); }
.theme-dark .navdrop__menu a { color: rgba(255, 255, 255, .78); }
.theme-dark .navdrop__menu a:hover { background: rgba(255, 255, 255, .07); color: #fff; }
.theme-dark .navdrop__rule { background: var(--line); }

.theme-dark .drawer { background: #1a171e; }
.theme-dark .drawer > a:not(.btn) { color: #fff; }
.theme-dark .drawer > a[aria-current="page"] { color: var(--gold); }
.theme-dark .navdrop__btn { color: #fff; }
.theme-dark .langsw__item.is-current { color: var(--gold); }
.theme-dark a.langsw__item:hover { color: #fff; }

/* The drawer is opened from a transparent header over a photograph; the base
   rule darkens the burger for a cream drawer, which is the wrong way here. */
.theme-dark.is-locked .header--over .brand,
.theme-dark.is-locked .header--over .burger { color: #fff; }
.theme-dark.is-locked .header--over .brand__rule { background: var(--line); }

/* --- bars pinned to the viewport ----------------------------------------- */
.theme-dark .stickycta {
  background: rgba(23, 21, 26, .97);
  border-top-color: var(--line);
}
.theme-dark .consent { box-shadow: 0 -6px 32px rgba(0, 0, 0, .5); }
/* The consent bar is the one component a visitor must be able to read before
   they have agreed to anything, so its link cannot stay on --gold-dd (2.4:1). */
.theme-dark .consent__d a { color: var(--gold); }

/* --- print ----------------------------------------------------------------
   The shared print block resets body only, so every descendant would keep the
   theme's white text and hand back a nearly blank sheet. */
@media print {
  body.theme-dark {
    --bg: #fff; --bg-alt: #fff; --bg-warm: #fff; --bg-dark: #fff;
    --fg: #000; --fg-strong: #000; --fg-muted: #333;
    --line: rgba(0, 0, 0, .3); --line-soft: rgba(0, 0, 0, .15);
  }
  .theme-dark .overline,
  .theme-dark .script,
  .theme-dark .prose a,
  .theme-dark .relate span,
  .theme-dark .trust__item b { color: #000; }
}

/* ==========================================================================
   31. SWIPE TRACK  (grid--swipe — the four promises under the hero on phones)
   --------------------------------------------------------------------------
   Four stacked cards push everything else below the fold on a phone, and the
   fourth is never seen. Laid side by side in a snapping scroller they take one
   screen instead of four, and the reader chooses which to read.

   The next card deliberately peeks past the right edge. That sliver is the
   only affordance the pattern has — without it a horizontal scroller reads as
   a single card and nobody swipes. The track runs full-bleed for the same
   reason, so a card can sit half off the screen rather than stopping short of
   a gutter that looks like the end of the row.

   Above the breakpoint every rule here is off and the ordinary grid returns.
   ========================================================================== */

@media (max-width: 767px) {
  .grid--swipe {
    display: flex;
    gap: .9rem;
    overflow-x: auto;
    overscroll-behavior-x: contain;   /* no accidental back-navigation swipe */
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    /* Break out of .shell so the track is edge to edge, then put the gutter
       back as padding — that is what lets a card peek at both ends. */
    margin-inline: calc(var(--gut) * -1);
    padding: .35rem var(--gut) 1rem;
    scroll-padding-inline: var(--gut);
    /* The scrollbar is noise here; the peeking card already says "there is
       more". Keyboard and screen-reader users reach the cards by tabbing,
       which scrolls them into view on its own. */
    scrollbar-width: none;
  }
  .grid--swipe::-webkit-scrollbar { display: none; }

  .grid--swipe > * {
    flex: 0 0 82%;
    scroll-snap-align: start;
    /* Centred on the card's own axis: on a phone each card is read on its own,
       one at a time, so its contents have no neighbouring column to align to. */
    text-align: center;
    /* Equal heights come free from the flex row; without this the shorter
       cards would shrink and the row would look ragged. */
    align-self: stretch;
  }

  /* Reveal staggering animates transform, which fights scroll-snap while the
     track is still settling. On the track the cards simply appear. */
  /* The icon is a block element by the base rule for media, so text-align does
     not reach it — it needs its own margins, the same way .trust__item svg does. */
  .grid--swipe .pill svg { margin-inline: auto; }

  .grid--swipe > .reveal { transition: none; transform: none; opacity: 1; }
}

/* Sekcja jakości niesie film zamiast zdjęcia. Podpis pod ornamentem jest tu
   linkiem, więc musi mieć jasność reszty bloku — .statement__sign jest
   przygaszony z założenia i sam link ginąłby na tle filmu. */
/* Link w środku akapitu, nie etykieta. .tlink jest inline-flex o wysokości
   44 px, wersalikami i w stopniu etykiety — wstawiony w zdanie rozbija wiersz
   i czyta się jak wklejony guzik. Tutaj link ma nieść tekst akapitu i tylko
   złotą kreskę pod spodem. */
.statement--film p a:not(.btn) {
  color: #fff;
  background-image: linear-gradient(var(--gold), var(--gold));
  background-repeat: no-repeat;
  background-position: 0 calc(100% - .08em);
  background-size: 100% 1px;
  transition: color .35s var(--e);
}
@media (hover: hover) {
  .statement--film p a:not(.btn):hover { color: var(--gold); }
}

.statement--film .statement__sign a { color: #fff; }
.statement--film .statement__sign { opacity: 1; }

/* ==========================================================================
   32. ENTRANCE — the first screen rises into place
   --------------------------------------------------------------------------
   Everything below the fold is revealed on scroll by .reveal. The first screen
   has no scroll to wait for, so it animates once on load: each line lifts a
   centimetre and settles, one after the next.

   Done in CSS rather than JavaScript on purpose. The stylesheet blocks the
   first paint, so the opening state is in place before anything is drawn —
   with a script the text would flash in position and then jump back down to
   start, which is worse than no animation at all.

   `both` keeps the from-state before the delay elapses and the to-state after,
   so nothing is left at opacity 0 if the animation never runs. The global
   prefers-reduced-motion block above already collapses every duration to
   nothing, which lands the elements straight on their final values.
   ========================================================================== */

@keyframes bb-rise {
  from { opacity: 0; transform: translateY(1.15rem); }
  to   { opacity: 1; transform: none; }
}

.hero__in > *,
.pagehead .shell > * {
  animation: bb-rise .85s var(--e) both;
}

/* Staggered, not simultaneous: read in the order the eye reads them. */
.hero__in > :nth-child(1), .pagehead .shell > :nth-child(1) { animation-delay: .08s; }
.hero__in > :nth-child(2), .pagehead .shell > :nth-child(2) { animation-delay: .17s; }
.hero__in > :nth-child(3), .pagehead .shell > :nth-child(3) { animation-delay: .26s; }
.hero__in > :nth-child(4), .pagehead .shell > :nth-child(4) { animation-delay: .35s; }
.hero__in > :nth-child(5), .pagehead .shell > :nth-child(5) { animation-delay: .44s; }

/* The scroll cue belongs to the same moment, but last and slowest — it is an
   invitation, not part of the sentence. */
/* Kursor przewijania jest wyśrodkowany przez `left: 50%` + `translateX(-50%)`,
   więc NIE MOŻE dostać bb-rise: ta animacja kończy się na `transform: none`
   i skasowałaby centrowanie, przesuwając go w prawo o połowę własnej
   szerokości. Własna klatka, która niesie oba przesunięcia naraz. */
@keyframes bb-rise-centred {
  from { opacity: 0; transform: translate(-50%, 1.15rem); }
  to   { opacity: 1; transform: translateX(-50%); }
}
.hero__cue { animation: bb-rise-centred 1.1s var(--e) both; animation-delay: .7s; }

/* Without JavaScript the reveal system never fires, and the site already
   handles that further up. This block must not fight it: the entrance is
   independent of .reveal and runs either way. */
@media (scripting: none) {
  .hero__in > *, .pagehead .shell > * { animation: none; opacity: 1; transform: none; }
  .hero__cue { animation: none; opacity: 1; transform: translateX(-50%); }
}

/* ==========================================================================
   33. PHONE — dial code beside the number
   --------------------------------------------------------------------------
   A placeholder reading "+48 …" quietly tells everyone outside Poland that the
   form was not written for them. A picker states the question instead, and the
   number field is left free of formatting the visitor has to guess.
   ========================================================================== */

.phone { display: grid; grid-template-columns: minmax(9rem, 34%) 1fr; gap: .5rem; }
.phone select { min-width: 0; }

@media (max-width: 520px) {
  /* Two controls on one line stop being usable somewhere around here — the
     code becomes too narrow to read and the number too narrow to check. */
  .phone { grid-template-columns: 1fr; }
}
