/* =============================================================================
   port-fixes.css — every deviation from the Azurio vendor CSS lives here.

   Load order: loader.css, plugins.css, main.css, THEN this file.

   The only edits made inside vendor files themselves (all five sanctioned by
   the audit, recorded in README.md):
     1. main.css    — the two Google-Fonts @import lines, removed (self-hosted
                      via next/font instead; audit §4.4/§4.6).
     2. plugins.css — the six broken Phosphor @font-face blocks, deleted. They
                      pointed at ./Phosphor*.woff2, i.e. css/, where no font
                      files exist. Shadowing them from here is NOT enough — the
                      dead rules still fire and 404 (audit §2.1). The real
                      declarations are re-made below.
     3. app.js      — init hung off DOMContentLoaded, which has already fired by
                      the time a React effect injects the bundle. Now guarded on
                      document.readyState (audit §5.2).
     4. app.js      — (retired) contact form POSTed to /api/contact.
     5. app.js      — (retired) .fail() branch printed errors in .form__error.
                      Both went with the whole contact handler; ContactForm.tsx
                      owns the form now (contact-form-feedback, README.md).
   ============================================================================= */

/* --- 1. Phosphor icon font, re-declared at the real paths -------------------
   Icons are in use on the homepage (ph-fill ph-heart, ph-bold ph-arrow-up-right,
   ph ph-arrow-up), so these families must resolve. woff2 only — the vendor's
   23 MB fonts/ tree ships .eot/.svg/.ttf/.woff per weight and none of it is
   needed by any browser we support. */
@font-face {
  font-family: "Phosphor";
  src: url("/fonts/Phosphor/Phosphor.woff2") format("woff2");
  font-display: block;
}
@font-face {
  font-family: "Phosphor-Bold";
  src: url("/fonts/Phosphor/Phosphor-Bold.woff2") format("woff2");
  font-display: block;
}
@font-face {
  font-family: "Phosphor-Fill";
  src: url("/fonts/Phosphor/Phosphor-Fill.woff2") format("woff2");
  font-display: block;
}
@font-face {
  font-family: "Phosphor-Duotone";
  src: url("/fonts/Phosphor/Phosphor-Duotone.woff2") format("woff2");
  font-display: block;
}
@font-face {
  font-family: "Phosphor-Light";
  src: url("/fonts/Phosphor/Phosphor-Light.woff2") format("woff2");
  font-display: block;
}
@font-face {
  font-family: "Phosphor-Thin";
  src: url("/fonts/Phosphor/Phosphor-Thin.woff2") format("woff2");
  font-display: block;
}

/* --- 2. Typography: same two families, self-hosted by next/font ------------
   next/font emits the @font-face rules and exposes each family through a CSS
   variable set on <html>. This block only changes where the vendor pair's bytes
   come from; the two display faces Folks adds beside them are named roles in
   brand deltas v2 decision 3 (§4 and the creator marquee). */
:root {
  --_font-default: var(--font-manrope), "Manrope", sans-serif;
  --_font-accent: var(--font-jetbrains-mono), "JetBrains Mono", monospace;
}

/* Page-title line masks clip descenders. The vendor's `.loading-split`
   SplitText wraps each line in a `.line-mask` with `overflow: clip` that is
   exactly one line box tall, and at the heading's 1.1 line-height Manrope's
   "g" hangs below it ("Blog" lost its tail). The mask grows downward by the
   descender and gives the space back, so nothing below it moves. */
.loading-split .line-mask {
  padding-bottom: 0.15em;
  margin-bottom: -0.15em;
}

/* --- 3. Brand palette (#15) ------------------------------------------------
   The site is pinned dark (see layout.tsx), so only the --*--dark set is ever
   selected; [color-scheme=dark] in main.css aliases --accent to --accent--dark.
   Accent goes from Azurio blue #002bba to the Folks coral #FF6251. The pin is
   what makes this legal: coral on the light base #EEEAE8 is 2.5:1 (fails), on
   the dark base #0f0f0f it is 6.5:1 (passes).
   Note: the vendor has no --accent-rgb/--highlight-rgb companions, so there is
   nothing else to override here. */
:root {
  --accent--dark: #ff6251;
  --highlight--dark: #ff6251;

  /* These three are text/icons/rules sitting ON the accent ground, not
     accent-coloured text — they are declared outside both --*--light and
     --*--dark twin sets in main.css, and a colour that does not follow the
     scheme cannot be tracking a scheme-keyed accent. Every `.accent` variant
     that reads them (.socials-list__*, .mxd-process-points__*) is the variant
     used inside an .bg-color-accent section.

     The vendor's values assume a DARK accent (white on #002bba = 10.2:1).
     brand-surface v1 hue-rotated two of them blue->coral, reading the name
     rather than the position, which on a light accent gives 2.95 / 1.51 / 1.28:1.
     Corrected here to a near-black set. Coral's ceiling is 7.12:1 (pure black),
     so the three steps are close together by necessity: 6.13 / 5.26 / 4.60:1,
     all above AA. There is no legal light-on-coral pairing at any lightness. */
  --pt-t-accent-bright: #161616;
  --pt-t-accent-medium: #242424;
  --pt-t-accent-muted: #2e2e2e;

  /* Referenced by the vendor and declared nowhere in main.css: one rule,
     `.mxd-article__thumb` (border-radius, plus its -moz- twin). Undeclared,
     its var() was invalid at computed-value time and the cover corners fell
     to the initial 0 by accident. 0 is now the decision (chrome-cleanup): the
     site is square everywhere except chips, tiles and one dialog, and a
     rounded cover would be its only rounded large surface. If a future
     main.css declares it, this shadows it on purpose. */
  --_radius-l: 0;
}

/* The same misreading, one layer out. `.active-cursor-accent` (app.js) fills a
   10rem cursor disc with var(--accent) and labels it `.mxd-cursor__text.accent`,
   which the vendor sets to --nl-white: white on the accent disc. That is 10.2:1
   on Azurio blue and 2.95:1 on coral, so the label under the manifest headline
   fails AA today, before this change adds a single coral section. The disc is a
   coral ground like any other, so its label takes the near-black set too.

   The disc itself is left alone: it is coral on the DARK page ground, which is
   the one place an accent cursor makes sense. On the coral band the accent
   cursor has nothing to say and CtaMarquee uses the plain `.active-cursor`. */
.mxd-cursor__text.accent {
  color: var(--pt-t-accent-bright);
}

/* The vendor ships `h2.accent` for text on the accent ground but no matching
   line button, so the coral CTA borrowed `.btn-line-opposite` — #161616 only
   because --t-opp-bright happens to be. This is the missing variant, shaped
   like its siblings in main.css "Elements - Buttons": `.btn-line-default`
   and `-permanent` set color and svg fill (`-opposite` sets color only).
   Re-check against those if the vendor CSS is ever bumped. */
.btn-line-accent {
  color: var(--pt-t-accent-bright);
}
.btn-line-accent svg {
  fill: var(--pt-t-accent-bright);
}

/* --- 4. Showreel band + menu video labels (#14) ----------------------------
   docs/specs/folks-showreel-menu-video-v1.md §5 / §6b. Both labels are white
   on mix-blend-mode: difference — the type inverts what passes beneath it
   rather than sitting on top as a plate. Azurio's own .menu-logo does the
   same. isolation: isolate is REQUIRED on the container: without it the blend
   composites against the page background instead of the video. No
   .mxd-divider__cover: the master is already graded, a cover would flatten it. */
.mxd-divider {
  isolation: isolate;
}
.band-outro {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(96%, 1720px);
  text-align: center;
  z-index: 10;
  mix-blend-mode: difference;
  pointer-events: none;
}
/* The label face is fixed: Unbounded 900 (brand deltas v2 decision 3,
   chrome-cleanup). Manrope 800 and Bebas Neue were the other two candidates;
   their rules and the data-face switch are deleted. The size is tuned so
   "CREATORS THAT" fills the 1720px cap at 1920 without wrapping mid-word, and
   Unbounded is wide — a different face means re-tuning it, not swapping it. */
.band-outro h2 {
  margin: 0;
  color: #fff;
  font-family: var(--font-unbounded), "Unbounded", sans-serif;
  font-weight: 900;
  font-size: clamp(30px, 8.2vw, 158px);
  line-height: 0.95;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  text-wrap: balance;
}

/* Menu: the wrapper is the positioned box (vendor sets position: relative on
   .menu-media__wrapper, not on .mxd-menu__media). The F is sized in container
   units — `%` would resolve against the parent's font size (≈5px). */
.menu-media__wrapper {
  isolation: isolate;
  container-type: inline-size;
}
/* menu-lens-video: the panel carries the Folks F alone, centred, as the
   menu's link home. It replaces the drawn FOLKS wordmark, and it is the only
   Folks mark in the menu from 1200px up (§10 hides the corner lockup there).
   The artwork's 231x259 aspect sets the height from the width.
   The fill stays #fff and is NOT the lockup's coral or cream — under
   `difference` this value is an operand, not a colour. White inverts the
   black-and-white footage exactly; no colour survives the blend anyway. */
.menu-mark {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: block;
  width: 36cqw;
  z-index: 10;
  mix-blend-mode: difference;
  pointer-events: auto;
}
.menu-mark svg {
  display: block;
  width: 100%;
  height: auto;
  fill: #fff;
}
/* A white outline inverts with the blend, so it stays visible over dark and
   bright frames alike. `!important` because the vendor strips focus
   outlines. */
.menu-mark:focus-visible {
  outline: 2px solid #fff !important;
  outline-offset: 1.2rem;
}

/* --- 5. Hero cursor trail: landscape signals ---------------------------
   The vendor JS sizes every trail image to 240px on its long side, which
   leaves the two wide signal SVGs (heart pill, follow bubble) at ~100px tall
   with unreadable text. It sets width/height inline, so !important is the
   only handle. Photos keep the vendor size. */
.mxd-trail-transparent-image[src*="signal-heart"],
.mxd-trail-transparent-image[src*="signal-bubble"] {
  width: 360px !important;
  height: auto !important;
}

/* --- 6. Contact form: consents, honeypot, error state -----------------------
   The vendor styles `form input` as a full-width underlined text field
   (width: 100%; height: 5.8rem), which is wrong for a checkbox in every
   dimension, and it ships no error state at all. Both gaps are filled here
   rather than in main.css. The vendor's `.form__reply` is no longer rendered:
   the outcome is the button caption plus `.contact-toast`, styled after the shared folks-strip rules. */

.form__consents {
  display: flex;
  flex-direction: column;
  gap: 1.2rem;
}

/* Inline errors (contact-form-feedback). Coral, the site's --accent, by
   Przemek's pick on the mock. The message element is always in the DOM — it is
   the live region — and takes space only once it holds text, so an untouched
   form sits exactly where it did. */
.form__field-error {
  margin: 0;
  font: normal 500 1.4rem/1.5 var(--_font-default);
  color: var(--accent);
}
.form__field-error:not(:empty) {
  margin-top: 0.8rem;
}
form input[aria-invalid="true"],
form textarea[aria-invalid="true"] {
  border-bottom-color: var(--accent);
}
.form__consent-row .form__field-error:not(:empty) {
  margin-top: 0.4rem;
  padding-left: 3rem;
}

.form__consent {
  display: flex;
  align-items: flex-start;
  gap: 1.2rem;
  cursor: pointer;
  font: normal 400 1.5rem/1.5 var(--_font-default);
  color: var(--t-medium);
}

.form__consent input[type="checkbox"] {
  flex: 0 0 auto;
  width: 1.8rem;
  height: 1.8rem;
  margin: 0.1rem 0 0;
  padding: 0;
  line-height: normal;
  border: 1px solid var(--st-medium);
  border-radius: 0.2rem;
  accent-color: var(--accent);
  cursor: pointer;
}

.form__consent input[type="checkbox"][aria-invalid="true"] {
  border-color: var(--accent);
  outline: 1px solid var(--accent);
}

.form__consent a {
  color: var(--t-bright);
  text-decoration: underline;
}

/* --- 7. Contact details block (/kontakt) -----------------------------------
   The vendor's page-level contact list lives in its contact.html, which is not
   vendored — only css/js/img/video are — so its class names are unknowable.
   The footer's .mxd-footer-nav02__list is not footer-scoped and was the
   candidate, but it styles `ul li a` at 2.4rem/700 as nav links and reaches no
   <address>, so it carries neither the labels nor the street line.

   The labels DO reuse the vendor's caption utility .footer-data (main.css,
   also unscoped); only the value line and the list reset are new. */

.mxd-contact-details {
  list-style: none;
  margin: 0;
  padding: 0;
}

.mxd-contact-details li + li {
  margin-top: 2.4rem;
}

.mxd-contact-details .footer-data {
  margin-bottom: 0.6rem;
}

.mxd-contact-details address,
.mxd-contact-details a {
  margin: 0;
  font: normal 500 2rem/1.5 var(--_font-default);
  color: var(--t-bright);
}

.no-touch .mxd-contact-details a:hover {
  color: var(--accent);
}

/* --- 8. Creator directory (#17) --------------------------------------------
   Three routes on the old WordPress paths — /tworcy/, /rodzaj/<term>/ and
   /influencerzy/<slug>/ — built on two vendor blocks: mxd-blog-list for the
   A–Z index (CreatorIndex.tsx) and the mxd-article-author box, promoted to
   page header, for profiles. Everything below is a deviation those two blocks
   need and do not have. */

/* 8a. The index list.
   Rows are the vendor's blog-list items, so the hover-dim (≥1200px, hover,
   motion allowed) is main.css's own; what changes is the row's shape. The
   list is one grid and every row a subgrid of it, so the columns line up
   across rows whatever each row holds — the platform column is as wide as the
   widest set of codes, up to a cap. The wrapper takes the 3rem gutter the
   vendor gives each column. A blog row's 5.4rem of padding is sized for a
   title and an excerpt; a name needs 1.6rem. `.mxd-blog-list__item` is already
   position: relative, which is what the name's .stretched-link needs to cover
   the row. Labels take the vendor's `.tag.tag-s` type. */
.creator-index {
  --thumb: 5.6rem;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  padding-inline: 3rem;
}
.creator-index__list {
  display: grid;
  grid-template-columns: var(--thumb) minmax(0, 1.5fr) minmax(0, 1fr) fit-content(22rem);
  column-gap: 2.2rem;
  border-top: 1px solid var(--st-muted);
}
.creator-index__letter,
.creator-index__item,
.creator-index__row {
  grid-column: 1 / -1;
}
.creator-index__item,
.creator-index__row {
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
}
.creator-index__item {
  padding: 1.6rem 0;
  border-bottom: 1px solid var(--st-muted);
}
/* 1:1 whatever the source: a portrait without a square derivative (a source
   under 800px) is otherwise its own height and staggers the rows. */
.creator-index__thumb {
  display: block;
  width: var(--thumb);
  height: var(--thumb);
  border-radius: 50%;
  object-fit: cover;
  background: var(--base-tint);
}
/* A 26-character handle has no break opportunity; without anywhere it
   widens the column and the page scrolls sideways at 390px. */
.creator-index__name {
  font: normal 700 clamp(2.4rem, 2.9vw, 4rem)/1.15 var(--_font-default);
  letter-spacing: -0.03em;
  color: var(--t-bright);
  overflow-wrap: anywhere;
}
.no-touch .creator-index__item:hover .creator-index__name,
.creator-index__name:focus-visible {
  color: var(--accent);
}
/* One item per platform in a wrapping flex row, the separator leading the
   item it precedes: a wrap falls between platforms and never strands a "·"
   at a line end or clips the last code. */
.creator-index__platforms {
  display: flex;
  flex-wrap: wrap;
  column-gap: 0.6em;
  margin: 0;
  color: var(--t-bright);
}
.creator-index__row > .creator-index__platforms {
  justify-content: flex-end;
}
.creator-index__platforms > span {
  white-space: nowrap;
}
.creator-index__platforms > span + span::before {
  content: "·";
  margin-right: 0.6em;
}
/* The letter is an h2 for screen-reader navigation, set as a mono label. */
.creator-index__letter {
  display: flex;
  align-items: center;
  gap: 1.4rem;
  margin: 0;
  padding: 3.4rem 0 0.8rem;
  color: var(--accent);
}
.creator-index__letter::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--st-muted);
}
.creator-index__empty {
  font: normal 500 1.8rem/1.6 var(--_font-default);
  color: var(--t-medium);
}
@media only screen and (max-width: 767px) {
  .creator-index {
    --thumb: 4.4rem;
  }
  .creator-index__list {
    grid-template-columns: var(--thumb) minmax(0, 1fr) fit-content(9rem);
    column-gap: 1.4rem;
  }
  .creator-index__categories {
    display: none;
  }
}

/* 8b. Photo panel (CreatorIndexPanel.tsx), 1200px and up only.
   The frame is ViewfinderLink's crop marks held open — that section's rules all
   key on a `.viewfinder` link or label and this is neither, so the marks are drawn here at
   the panel's size, in the accent. Below 1200px the row thumbnail is the only
   photo. */
.creator-index__panel {
  display: none;
}
@media only screen and (min-width: 1200px) {
  .creator-index {
    grid-template-columns: minmax(0, 1fr) 38rem;
    gap: 7rem;
    align-items: start;
  }
  .creator-index__panel {
    display: block;
    position: sticky;
    top: 12rem;
  }
}
.creator-index__rec {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  margin: 0 0 1rem;
  color: var(--accent);
}
.creator-index__rec .viewfinder__light {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}
.creator-index__frame {
  position: relative;
  padding: 1.6rem;
}
.creator-index__frame img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 2px;
}
.creator-index__frame > .viewfinder__corner {
  position: absolute;
  width: 2.6rem;
  height: 2.6rem;
  border: 0 solid var(--accent);
}
.creator-index__frame > .viewfinder__corner--tl { top: 0; left: 0; border-left-width: 2px; border-top-width: 2px; }
.creator-index__frame > .viewfinder__corner--tr { top: 0; right: 0; border-right-width: 2px; border-top-width: 2px; }
.creator-index__frame > .viewfinder__corner--bl { bottom: 0; left: 0; border-left-width: 2px; border-bottom-width: 2px; }
.creator-index__frame > .viewfinder__corner--br { bottom: 0; right: 0; border-right-width: 2px; border-bottom-width: 2px; }
.creator-index__panel-name {
  margin: 2rem 0 1rem;
  font: normal 700 3rem/1.1 var(--_font-default);
  letter-spacing: -0.03em;
  color: var(--t-bright);
  overflow-wrap: anywhere;
}
@media (prefers-reduced-motion: no-preference) {
  .creator-index__name {
    transition: color var(--_animspeed-medium);
  }
  .creator-index__rec .viewfinder__light {
    animation: viewfinder-rec 1s steps(1) infinite;
  }
}

/* 8d. Term chip bar.
   The package has no bar primitive — .tag-bg is its only pill — so the row is
   made here. The count is a dimmer span inside the pill, using the gap .tag-bg
   already declares between its children. */
.mxd-term-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  margin-top: 3.2rem;
  margin-bottom: 4.4rem;
}
.mxd-term-bar__count {
  opacity: 0.6;
}

/* 8e. Creator profile — direction C, "Portret".
   The name is a poster in Bebas Neue (the marquee's number face), the portrait
   overlaps its baseline, the short description is a pull quote.

   The headline sizes by its own length: the page sets --name-len (characters)
   on the stage — not the h1, because --name-size is computed on the stage and a
   var() resolves where it is declared —
   and 150vw / --name-len keeps a long name on roughly one line of the viewport
   while a short one tops out at the poster size. The floor (4.4rem) stops
   "Wrocławskie Podróże Kulinarne" from shrinking to 20px at 390px — below it,
   long names wrap instead. It is sized so the longest unbreakable word
   ("cypriano_italiano", 17 characters) still fits a 390px viewport;
   e2e/creator-profile.spec.ts checks every published name for overflow.

   The floor alone cannot hold a handle longer than that: a single 26-character
   word does not fit 358px at 4.4rem. So the size is also capped by the longest
   word (--word-len), at 0.45em per character — Bebas measures 0.35-0.41em on
   real names — across the article's own width (cqi, so the cap follows the
   container's padding at every breakpoint rather than guessing it from vw).

   --name-size is declared on the stage so the portrait's overlap can scale with
   the name: a fixed overlap sized for "Bladii" would lift the portrait clean
   over a 74px headline. */
/* `grid-l-container` has no padding below 768px — the vendor's blocks bring
   their own, and the author-box card this page used to open with did. */
@media only screen and (max-width: 767px) {
  .creator-profile {
    padding-inline: 1.6rem;
  }
}
.creator-profile {
  container-type: inline-size;
}
.creator-profile__stage {
  --name-size: min(
    max(4.4rem, min(19vw, 300px, calc(150vw / var(--name-len, 10)))),
    calc(100cqi / var(--word-len, 10) / 0.45)
  );
  display: grid;
  grid-template-areas: "name" "photo" "quote";
  gap: 2.4rem;
}
.creator-profile__name {
  grid-area: name;
  margin: 0;
  font: 400 var(--name-size) / 0.88 var(--font-bebas), sans-serif;
  letter-spacing: 0.005em;
  color: var(--t-bright);
  text-wrap: balance;
  position: relative;
  z-index: 0;
}
.creator-profile__photo {
  grid-area: photo;
  position: relative;
  z-index: 1;
  width: min(100%, 420px);
  margin: calc(var(--name-size) * -0.2) 0 0;
}
.creator-profile__photo img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}
.creator-profile__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  margin-top: 1.2rem;
}
.creator-profile__quote {
  grid-area: quote;
  margin: 0;
  max-width: 24ch;
  font: normal 600 2.2rem/1.3 var(--_font-default);
  letter-spacing: -0.02rem;
  color: var(--t-bright);
  text-wrap: pretty;
}
.creator-profile__quote::before {
  content: "\201E";
  display: block;
  margin-bottom: 1rem;
  font: 400 11rem/0.6 var(--font-bebas), sans-serif;
  color: var(--accent);
}
@media only screen and (min-width: 820px) {
  .creator-profile__stage {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "name name" "quote photo";
    column-gap: clamp(2.4rem, 4vw, 5.6rem);
    row-gap: 0;
    align-items: end;
  }
  .creator-profile__photo {
    justify-self: end;
    margin-top: calc(var(--name-size) * -0.55);
  }
  .creator-profile__quote {
    font-size: clamp(2.2rem, 2.2vw, 3rem);
    /* Sits level with the portrait's foot, not its caption. */
    align-self: start;
    padding-top: clamp(2.4rem, 4vw, 5.6rem);
  }
}

/* Reach and links beside the bio. */
.creator-profile__body {
  display: grid;
  gap: 4.8rem;
  margin-top: 5.6rem;
}
@media only screen and (min-width: 820px) {
  .creator-profile__body {
    grid-template-columns: minmax(20rem, 24rem) minmax(0, 1fr);
    gap: clamp(2.4rem, 4vw, 5.6rem);
    align-items: start;
  }
  /* A creator without counts or links still keeps the bio in the second column. */
  .creator-profile__body > .creator-profile__bio:only-child {
    grid-column: 2;
  }
}
.creator-profile__side {
  display: grid;
  gap: 2.4rem;
  align-content: start;
}
.creator-profile__total {
  display: grid;
  gap: 0.6rem;
  margin: 0;
}
.creator-profile__total strong {
  font: 400 6.4rem/0.9 var(--font-bebas), sans-serif;
  color: var(--t-bright);
}
.creator-profile__links {
  margin: 0;
  padding: 0;
  list-style: none;
}
.creator-profile__links li > a,
.creator-profile__links li > span {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1.2rem;
  padding-block: 1.2rem;
  border-bottom: 1px solid var(--st-muted);
  font: normal 600 1.7rem/1.4 var(--_font-default);
  color: var(--t-bright);
  text-decoration: none;
}
.creator-profile__platform {
  display: inline-flex;
  align-items: center;
  gap: 0.8rem;
}
.creator-profile__count {
  font: 500 1.3rem/1.6 var(--_font-accent);
  color: var(--t-medium);
  white-space: nowrap;
}
.creator-profile__links a:hover,
.creator-profile__links a:focus-visible {
  color: var(--accent);
}
.creator-profile__links a:focus-visible,
.creator-profile__chips a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
@media (prefers-reduced-motion: no-preference) {
  .creator-profile__links a {
    transition: color 0.2s ease;
  }
}

/* The bio: left-aligned in its column, lighter than the vendor's grey body copy
   (--t-medium on the dark base read as fine print under a 300px name), and no
   drop cap — on a profile it only repeated the headline's first letter. The
   drop cap is declared in 8f, after this section, so the override carries one
   more class rather than depending on source order. */
.creator-profile__bio {
  --prose: 68ch;
}
.creator-profile__bio > p {
  margin-inline: 0;
}
/* 8f brightens an article's opening paragraph; here the pull quote is the
   opening, so the bio is one colour throughout. */
.creator-profile .creator-profile__bio > p,
.creator-profile .creator-profile__bio > p:first-child {
  color: color-mix(in oklab, var(--t-bright) 80%, var(--base));
}
.creator-profile .creator-profile__bio > p:first-child::first-letter {
  float: none;
  margin: 0;
  padding: 0;
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
}

/* 8f. Rendered rich text in the article body.
   .mxd-article__content is `flex-direction: column; gap: 6rem` and expects
   .mxd-article__block wrappers as direct children; a Lexical body is a flat
   stream, so every paragraph would sit 6rem from the next. The elements
   themselves need nothing here — the profile's converters give them the
   vendor's own .mxd-article__normal and .block-quote classes — so this is the
   spacing and nothing else. */
.mxd-article__content--md,
.mxd-article__content--legal {
  gap: 3rem;

  /* The measure, shared by prose and its subheadings so they align on the same
     left edge. 870px of 20px body copy runs 79 characters to the line, past the
     65-75 band where the eye reliably finds the start of the next one; 75rem
     brings it to about 68. Images and tables deliberately keep the full column,
     so they overhang evenly on both sides and read as a decision rather than a
     stray margin. */
  --prose: 75rem;
}
.mxd-article__content--md > p,
.mxd-article__content--md > h2,
.mxd-article__content--md > h3,
.mxd-article__content--legal > p,
.mxd-article__content--legal > h2,
.mxd-article__content--legal > h3,
.mxd-article__content--legal > ol,
.mxd-article__content--legal > ul {
  max-width: var(--prose);
  width: 100%;
  margin-inline: auto;
}
.mxd-article__content--md > h2,
.mxd-article__content--md > h3,
.mxd-article__content--legal > h2,
.mxd-article__content--legal > h3 {
  margin-top: 3rem;

  /* Subheadings ran to three lines with one word stranded on the last
     (streaming-latwogang). Balancing costs nothing and only ever affects
     headings short enough to wrap. */
  text-wrap: balance;
}
.mxd-article__content--md > p,
.mxd-article__content--legal > p {
  /* Same idea one level down: no single-word last line in a paragraph. */
  text-wrap: pretty;
}

/* The article body owns its own heading scale, rather than countering the
   vendor's per breakpoint. A Lexical body emits bare `h2`/`h3`, so a subheading
   inherits the scale built for *page-section titles* — which climbs 4.4 -> 5.4 ->
   7.5 -> 9.5rem and arrived at 75px under a 95px article title, the section
   shouting nearly as loud as the piece. Declaring the step once shadows all four
   vendor steps; pinning only the >=1200px one left the subheading *growing* to
   5.4rem at 768 and shrinking back at 1200, which is worse than either end.
   The values are the vendor's own base steps, nothing invented. */
.mxd-article__content--md > h2 {
  font: normal 600 4.4rem/1.1 var(--_font-default);
  letter-spacing: -0.18rem;
}
.mxd-article__content--md > h3 {
  font: normal 700 3rem/1.2 var(--_font-default);
  letter-spacing: -0.1rem;
}

/* --- The piece gets a beginning, a spine, and an end ------------------------
   After the measure was set, the article read correctly and looked like nothing:
   a column of grey with no landmarks, no reward for scrolling, and no visible
   start or finish — it simply stopped. These four rules are the texture, and
   they all spend the same currency: the 6rem of gutter the measure opened up on
   either side of the prose, which was otherwise doing nothing. */

/* Beginning. The opening paragraph keeps the bright colour the template already
   uses for emphasis; the initial does the rest. Every one of the 19 posts opens
   on a plain capital — checked, not assumed — so nothing here lands on a quote
   mark or a digit. */
.mxd-article__content--md > p:first-child {
  color: var(--t-bright);
}
.mxd-article__content--md > p:first-child::first-letter {
  float: left;
  /* Three lines of body copy, so it scales with the text rather than sitting at
     one fixed size: at 390px the column is 30 characters wide and a 96px letter
     ate a quarter of it. */
  font-size: 6.4rem;
  line-height: 0.74;
  font-weight: 600;
  letter-spacing: -0.2rem;
  color: var(--accent);
  padding-right: 1.2rem;
}
@media only screen and (min-width: 768px) {
  .mxd-article__content--md > p:first-child::first-letter {
    font-size: 9.6rem;
    padding-right: 1.4rem;
  }
}
/* Spine. A short rule in the left margin beside every subheading, so a reader
   scrolling fast can see the piece has structure without reading a word of it.
   Both marginal marks live here together: below 1200px the prose runs full-bleed,
   there is no gutter to hang into, and a mark inside the text column would just
   be a stray dash. */
@media only screen and (min-width: 1200px) {
  .mxd-article__content--md > p:first-child::first-letter {
    margin-left: -5.6rem;
    padding-right: 1.8rem;
  }
  .mxd-article__content--md > h2 {
    position: relative;
  }
  .mxd-article__content--md > h2::before {
    content: '';
    position: absolute;
    left: -5.6rem;
    /* Sits on the cap line rather than the line box, which is what the eye
       reads as aligned with the first letter. */
    top: 1.6rem;
    width: 3.2rem;
    height: 2px;
    background: var(--accent);
  }
}

/* The vendor flips `.block-image` to `flex-direction: row` at >=768px, which is
   right for its own template (image beside a caption column) and wrong here: our
   caption is a one-line credit, and as a second flex child it took width off the
   photograph. Back to a column, caption under the image where it belongs. */
.mxd-article__content--md > .block-image {
  flex-direction: column;
  gap: 0;
}

/* End. The body used to stop mid-column and hand straight over to the author
   box, so the reader found out the piece had ended by running out of it. This
   is the printed end mark, and it is the only thing on the page that says
   "finished". */
.mxd-article__content--md::after {
  content: '';
  width: 1rem;
  height: 1rem;
  margin-top: 1rem;
  /* Aligned with the first letter of the prose, not centred: the measure rule
     above centres full-width blocks, and auto margins on a 1rem box would put
     the mark in the middle of the column. `max()` collapses the offset to zero
     once the container is narrower than the measure. */
  margin-left: max(0px, calc((100% - var(--prose)) / 2));
  background: var(--accent);
}

/* 8f-legal. The legal pages (openspec legal-pages D5).
   The article's measure and body type (shared above), none of its texture: a
   regulamin with a drop cap and an end mark reads as a blog post about a
   regulamin. What it needs instead is what a contract needs — clause labels
   that do not shout, and numbers you can find. */

/* "§ 1 Postanowienia ogólne" is a clause label, not a chapter title: the h3
   step, not the article h2's. The live page centred these with inline styles;
   the import dropped those, and the label sits on the text's left edge. */
.mxd-article__content--legal > h2,
.mxd-article__content--legal > h3 {
  font: normal 700 3rem/1.2 var(--_font-default);
  letter-spacing: -0.1rem;
}

/* The vendor lists are `decimal inside`, which puts a clause's second line
   back under its own number. Outside, with the padding to hold the marker, the
   number hangs and every line of the clause starts on the same edge. 3.6rem
   fits "15." — the longest number in the three texts. */
.mxd-article__content--legal ol,
.mxd-article__content--legal ul {
  list-style-position: outside;
  padding-inline-start: 3.6rem;
  gap: 1.2rem;
}
/* A nested list steps in once more, under its parent clause's text. */
.mxd-article__content--legal li ol,
.mxd-article__content--legal li ul {
  margin-top: 1.2rem;
}
.mxd-article__content--legal li::marker {
  color: var(--t-bright);
}
/* The privacy policy's section heads are bold paragraphs ("Artykuł 1.
   Administrator"), and bold is all that marks them: the vendor resets `strong`
   to the body's 500 grey, which left them indistinguishable from the text. */
.mxd-article__content--legal strong {
  font-weight: 700;
  color: var(--t-bright);
}
/* The vendor bolds every `li span` for its own template; here the only span is
   Payload's underline, which should stay the colour and weight of its text. */
.mxd-article__content--legal li span {
  font-weight: inherit;
  color: inherit;
}
.mxd-article__content--legal li a {
  color: var(--t-bright);
  text-decoration: underline;
  text-underline-offset: 0.22em;
  text-decoration-thickness: 1px;
}
/* Below 768px the vendor's .grid-l-container drops its side padding, which
   ran every line of a post or a legal text into the screen edge. Both use the
   article area, so both get the gutter back here. */
@media only screen and (max-width: 767px) {
  .mxd-article-area .mxd-container {
    padding-inline: 2rem;
  }
}
/* The privacy policy spells its browser links out in full; a 70-character URL
   has no break opportunity and pushed a 360px page sideways. */
.mxd-article__content--legal {
  overflow-wrap: anywhere;
}

/* The one flourish with no argument behind it beyond liking it: selected text
   picks up the brand instead of the browser's blue. Both selectors, because
   main.css defines the pair and overriding half of it leaves them disagreeing;
   `--pt-t-accent-bright` is this repo's own token for type sitting ON the
   accent, so it stays right in both themes where a literal would not. */
::-moz-selection {
  background-color: var(--accent);
  color: var(--pt-t-accent-bright);
}
::selection {
  background-color: var(--accent);
  color: var(--pt-t-accent-bright);
}

/* The photo credit was rendering in `.tag tag-bg permanent` — the template's UI
   chip, the same component the meta row uses for a category. On a photograph in
   the middle of an article that reads as a control, not as a credit. A caption
   is a caption: small, quiet, and tied to the image by a short accent rule. */
.mxd-article__caption {
  display: flex;
  align-items: baseline;
  gap: 1.2rem;
  margin-top: 1.6rem;
  font: normal 500 1.4rem/1.5 var(--_font-default);
  color: var(--t-medium);
}
.mxd-article__caption::before {
  content: '';
  flex: none;
  width: 2rem;
  height: 1px;
  background: var(--accent);
  transform: translateY(-0.4rem);
}

/* Underlines sat on the baseline and cut through descenders in Polish (ą, ę, ż
   are everywhere). Dropping them clear of the text is the whole change. */
.mxd-article__normal a {
  text-underline-offset: 0.22em;
  text-decoration-thickness: 1px;
}

/* 8g. The 404 body.
   Composed from the package's generic blocks (section title + line buttons).
   One centring mechanism for the whole block — the vendor's .centered on the
   title and a justify-content on the row would each centre a subset of it, and
   three knobs for one alignment is two too many to reason about. */
.mxd-notfound {
  text-align: center;
}
.mxd-notfound__code {
  display: block;
  color: var(--accent);
  margin-bottom: 1.6rem;
}
.mxd-notfound__lead {
  max-width: 52rem;
  margin: 2.4rem auto 0;
}
.mxd-notfound__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1.6rem;
  margin-top: 4rem;
}

/* 8h. Article table block.
   No vendor template in the bundle ever tables its content, so there is no
   .mxd-table to reuse — this is the one post that needs it
   (streaming-latwogang, content map §4.2), styled to sit at home inside
   .mxd-article__content--md. */
.mxd-article__table {
  width: 100%;
  border-collapse: collapse;
}
.mxd-article__table th,
.mxd-article__table td {
  padding: 1.2rem 1.6rem;
  text-align: left;
  border-bottom: 1px solid var(--stroke, rgba(255, 255, 255, 0.16));
}
.mxd-article__table th {
  font-weight: 700;
  color: var(--t-bright);

  /* The header rule is the accent, the body rules are not: one line says "this
     row is different", and repeating the colour down the table would say it
     nine more times for nothing. */
  border-bottom-color: var(--accent);
}
.mxd-article__table td {
  /* The one table on the site is money and follower counts; digits that line up
     in a column are worth the single declaration. */
  font-variant-numeric: tabular-nums;
}
.mxd-article__table tr:last-child td {
  border-bottom: none;
}

/* --- 9. Hero full stop (brand-surface) -------------------------------------
   The hero sentence already ended in a period rendered in the same grey as the
   words; it is now coral. Nothing else about the headline changes — this is one
   glyph, deliberately, because the alternative reading (colour the words) puts
   coral text on the dark ground at display size and turns the headline into the
   brand statement rather than the sentence it is.

   `color` and not a token: --accent is the right value, and reaching it through
   the variable is what keeps this honest if the accent ever moves again.

   Reused by the group wheel's heading (§13), which ends the same way on the same
   dark ground. It is the treatment that is named here, not the hero — so one
   definition serves both rather than a second class saying the same thing. */
.hero-dot {
  color: var(--accent);
}

/* The home hero headline in the wordmark's own face. The vendor sets this h1
   in Manrope; the Folks wordmark is Raleway, and folks.pl set its home-header
   h1 at Raleway 800. Chosen 2026-09-22 from six mocked treatments: Raleway 800,
   lowercase throughout — "from creators / to results." — at the vendor's size
   tiers. The tracking replaces the vendor's per-tier -0.3rem/-0.5rem, tuned
   for Manrope; it is one value here so it beats every tier in main.css.
   text-transform rather than editing the copy: the sentence stays "From
   creators" in the source, the OG card and the closing CTA, which keep Manrope. */
.mxd-hero-05__headline h1 {
  font-family: var(--font-raleway), "Raleway", sans-serif;
  font-weight: 800;
  letter-spacing: -0.02em;
  text-transform: lowercase;
}

/* The mark ground carries the Folks mark, scattered — the campaign dialog's tile
   (public/img/campaign-dialog-pattern.svg). Paper, not ink: the ground is
   near-black. 4% is option A of the hero test
   (https://claude.ai/artifact/4hxoiVCTnLaVbdpqNuWbdM). Absolute, not fixed, so it
   scrolls away with its band; `isolation` makes the carrier the stacking context,
   so z-index -1 paints above its background and below the text and the trail.

   It began as a selector list naming two sections — the home hero and
   `/jak-dzialamy/`'s intro (BlockPage `heroIntro`) — because both are full-width,
   both start at the top of the page and both end on a hard edge, so `inset: 0`
   was the whole rule. The post header, the blog index's opening band and the 404
   message are not sections: they sit inside `.mxd-container` and have to end at
   an element inside it, which the section carrying the top padding does not know
   the position of. So the class goes on the element whose BOTTOM edge is where
   the ground should end, and the ::before hangs from it — up past the top of the
   page and out to the viewport edges.

   `-96rem` is two tiles, so a band that starts at the top of the page keeps the
   mask's phase: the two original surfaces render exactly as they did.
   `inset-inline: calc(50% - 50vw)` bleeds full width from inside a centred
   container and adds no horizontal scroll (the vendor sets `scrollbar-width:
   none`, so 100vw is the visible width). `--mark-ground-under` runs the tail on
   past the carrier, under whatever paints over it. */
.folks-mark-ground {
  position: relative;
  isolation: isolate;
}
.folks-mark-ground::before {
  content: "";
  position: absolute;
  top: -96rem;
  bottom: calc(-1 * var(--mark-ground-under, 0rem));
  inset-inline: calc(50% - 50vw);
  z-index: -1;
  background: var(--folks-paper);
  opacity: .04;
  mask: url("/img/campaign-dialog-pattern.svg") 0 0 / 48rem repeat;
  pointer-events: none;
}

/* Where nothing paints over the tail — a post without a cover, the 404 — the
   ground has to end on its own, and a hard cut against ground of the same colour
   slices marks in half. Two masks intersected do it: the tile gives the shape,
   the gradient the extent. The gradient is measured from the bottom of the
   ::before, so the 96rem rise above does not enter into it. `mask-composite`
   after the shorthand, not before: `mask` resets it to `add`. */
.folks-mark-ground--fade::before {
  mask:
    url("/img/campaign-dialog-pattern.svg") 0 0 / 48rem repeat,
    linear-gradient(#000 calc(100% - var(--mark-ground-fade, 24rem)), transparent);
  mask-composite: intersect;
}

/* The manifest's own top padding clears the header; this gives the ground the
   same room below the sentence before the process starts. */
.folks-page-hero {
  padding-bottom: clamp(8rem, 10vw, 14rem);
}

/* `/dolacz/`: the lead form follows the hero directly, with its own heading, so the
   vendor's 16–18.4rem under the manifest plus the padding above left a 31rem hole at
   1440. Both tighten, and the fade shortens to fit: it starts behind the manifest's
   last line and has ended where the form begins. */
.folks-page-hero:has(+ #formularz) {
  padding-bottom: clamp(6rem, 8vw, 12rem);
}
.folks-page-hero:has(+ #formularz) .mxd-section-manifest.pre-list {
  padding-bottom: 0;
}
.folks-page-hero.folks-mark-ground:has(+ #formularz) {
  --mark-ground-fade: 16rem;
}

/* Post header. The tail runs a few rem past the headline's own bottom margin
   (7.4rem, 9.4rem from 768px) so it ends under `.mxd-article__thumb`, a later
   positioned sibling that paints over it: the image's top edge becomes the
   ground's edge at any title length, without anything measuring one. It stays
   well inside the thumb's smallest height (360px).

   The `:not()` rather than source order: without a cover there is nothing to
   hide the tail under and it would cut through the first paragraph, so that post
   takes the fade instead — and must not also inherit an under-run. */
.mxd-article__headline.folks-mark-ground:not(.folks-mark-ground--fade) {
  --mark-ground-under: 11.4rem;
}
.mxd-article__headline.folks-mark-ground--fade {
  --mark-ground-under: 7.4rem;
  --mark-ground-fade: 20rem;
}
@media only screen and (min-width: 768px) {
  .mxd-article__headline.folks-mark-ground:not(.folks-mark-ground--fade) {
    --mark-ground-under: 13.4rem;
  }
  .mxd-article__headline.folks-mark-ground--fade {
    --mark-ground-under: 9.4rem;
  }
}

/* Blog index. The wrapper (blog/page.tsx) holds the title block and the lead;
   the lead's bottom margin collapses out of it, so the under-run is that same
   margin and the ground ends where the "Wcześniejsze wpisy" row begins — the
   row and its hairline stay on clean ground, which is what the approved mock
   does and settles design.md's open question. Without that row (one post, or
   none) the wrapper carries the fade too, and the fade runs inside the margin
   rather than over the lead. */
.blog-hub-ground {
  --mark-ground-under: clamp(5.6rem, 7vw, 10rem);
  --mark-ground-fade: 16rem;
}

/* Contact. The carrier is the title block (kontakt/page.tsx); the contact details and
   the form follow it after a 73px gap at 390 and 84–90px from 768 up, and nothing
   paints over them, so the ground fades and runs 6rem past the title: it has faded out
   inside that gap at every width and no mark sits behind the address or a field. */
.kontakt-ground {
  --mark-ground-under: 6rem;
  --mark-ground-fade: 16rem;
}

/* 404. Nothing follows the message but the footer, on the same ground, so this
   surface is always faded. The column's bottom edge IS the footer's top, so it
   takes no under-run at all: the fade finishes exactly where the footer starts
   and no mark, however faint, is painted over it. */
.mxd-notfound.folks-mark-ground {
  --mark-ground-fade: 18rem;
}

/* --- 10. Folks lockup (brand-surface) --------------------------------------
   Both halves are traced artwork (app/(site)/FolksLockup.tsx), so the colours
   are painted onto groups inside one SVG rather than onto two sibling
   elements. The vendor's .mxd-logo__image sets `fill: currentColor` on the
   <svg>; these two rules reach past it to the groups.

   The wordmark takes the artwork's own cream #F5F1E8, not --t-bright: this is
   the folks.pl lockup 1:1, and cream is what it is drawn in. 17.9:1 on the
   pinned #0f0f0f, so nothing is spent on the swap.

   The header is `position: absolute; top: 0` — it scrolls away with the page
   rather than tracking it, so the coral mark never rides over the coral CTA
   band. */
:root {
  --folks-cream: #f5f1e8;

  /* The services collage's paper plate and its ink (chrome-cleanup). Declared
     globally, not on .folks-services: the plate is a system surface one block
     happens to use today, and a block-scoped property would re-encode the
     one-off. Ink on paper is 16.33:1. */
  --folks-paper: #f2eee7;
  --folks-ink: #111111;
}

.mxd-logo__image {
  /* The vendor sizes its own mark by height with `width: auto`. This lockup is
     3.24x wider than tall, so height still drives it — the wordmark simply
     comes along at the proportion the artwork sets. */
  height: 3.6rem;
}
@media only screen and (min-width: 768px) {
  .mxd-logo__image {
    height: 4rem;
  }
}
/* Painted on the two groups inside the SVG, so these apply wherever the lockup
   renders — header and menu alike. The vendor's `fill` rules target the <svg>
   element and are merely inherited, so a rule on the <g> wins without a
   specificity fight. */
.lockup-mark {
  fill: var(--accent);
}
.lockup-word {
  fill: var(--folks-cream);
}

/* The menu shows the same lockup, sized to the overlay. The vendor blends
   .menu-logo with `difference` so a white wordmark inverts whatever passes
   under it — which is exactly what coral cannot survive: over the cream
   overlay there is no input colour whose difference is #FF6251. It is turned
   off here rather than worked around.
   menu-lens-video: the lockup now shows only where the video panel does not.
   From 1200px up — the breakpoint where main.css shows .mxd-menu__media — the
   panel's centred F (§4) is the menu's mark, and a second logo in the corner
   was a repeat. `display: none`, so the hidden link also leaves the tab
   order. Below 1200px there is no panel, and the lockup sits on the overlay
   alone. */
@media only screen and (min-width: 1200px) {
  .mxd-menu__logo {
    display: none;
  }
}
.mxd-menu__logo .menu-logo {
  mix-blend-mode: normal;
}
.menu-logo__lockup {
  display: inline-flex;
  width: auto;
  height: 3.2rem;
}
@media only screen and (min-width: 768px) {
  .menu-logo__lockup {
    height: 3.6rem;
  }
}

/* menu-refinement: the menu is the one cream surface the lockup sits on, and
   §10's cream wordmark vanished into it — only the coral mark showed. The
   word takes the overlay's text colour; the mark stays coral. */
.menu-logo .lockup-word {
  fill: var(--t-opp-bright);
}

/* The §2 descender fix, for the menu. main.css pads `.main-menu__link
   .line-mask` only from 1200px, and only by 5px — below that the mask is the
   caption's 1.0 line box and every descender went ("Blog", "Twórcy",
   "działamy"). Relative, so it follows the caption's size at every step. */
.main-menu__link .line-mask {
  padding-bottom: 0.22em;
  margin-bottom: -0.22em;
}

/* The rows run the overlay's full width: the vendor's right column is out of
   the markup, so its 66.67% track and the gutter beside it go too. */
@media only screen and (min-width: 1200px) {
  .mxd-menu__inner .mxd-menu__left {
    width: 100%;
    padding-right: 0;
  }
}

/* The bottom bar: "© 2026 Folks", the three legal pages and the socials. The vendor's
   66/33 split was sized for two short strings; the three links need their own
   width, so both halves size to content and the bar spreads them. Sentence
   case, as the footer sets the same links. */
.mxd-menu__data .menu-data__text,
.mxd-menu__data .menu-data__text a {
  text-transform: none;
}
.menu-data__right.menu-legal {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 2.4rem;
}
/* Below 1200px main.css leaves the bar in the scrolling column's flow, so it
   sat right under the last row. The auto margin takes the free height and
   pins it to the bottom; on a screen too short for the list there is none,
   and the bar follows the rows instead of covering them as `fixed` would. */
@media only screen and (max-width: 1199px) {
  .mxd-menu__data {
    margin-top: auto;
    text-align: center;
  }
  .mxd-menu__data .menu-data__text,
  .menu-data__right.menu-legal {
    justify-content: center;
  }
  /* The icons take a row of their own, not whichever line the wrap leaves. */
  .menu-data__text.menu-socials {
    flex-basis: 100%;
    margin-top: 0.8rem;
  }
}

/* SplitText wraps the <p>'s whole content in one `.line`, so a `gap` on the
   <p> never reaches the links — the spacing is a margin between them. */
.menu-socials a {
  line-height: 1;
}
.menu-socials a + a {
  margin-left: 1.6rem;
}
.menu-socials i {
  font-size: 2.4rem;
}
@media only screen and (min-width: 1200px) {
  .mxd-menu__data .menu-data__left,
  .menu-data__right.menu-legal {
    width: auto;
    white-space: nowrap;
  }
  .mxd-menu__data {
    justify-content: space-between;
  }
  .menu-data__right.menu-legal {
    justify-content: flex-end;
    gap: 3.2rem;
  }
}

/* --- 11. Category tiles (brand-surface) ------------------------------------
   The one authored block in this change. Nothing in main.css describes a grid
   of coral category tiles, so there was no vendor rule to claim (design.md
   "Category tiles are authored (B)").

   Coral ground, near-black type: the tiles take the same --pt-t-accent-* set
   §3 corrected, which is what makes "on the accent" one decision rather than
   one per component. The hover state goes the other way — dark ground, coral
   type — rather than tinting the coral, because coral has 7.12:1 of total
   range against black and any tint of it spends contrast the label needs.

   Sizing is intrinsic: tiles are as wide as their label plus the count, so a
   term named "Twórcy gamingowi" and one named "Moda" are not forced to the
   same box. The old site's boxes behaved the same way, and it is what lets the
   grid hold 3 terms today and ~11 after the creator import without a column
   count to re-tune. */
.mxd-category-tiles__intro {
  max-width: 56rem;
  margin-top: 2.4rem;
  font: normal 400 1.8rem/1.6 var(--_font-default);
  color: var(--t-medium);
}

.mxd-category-tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 1.2rem;
  margin: 4.4rem 0 0;
  padding: 0;
  list-style: none;
}

.mxd-category-tile {
  display: inline-flex;
  align-items: baseline;
  gap: 1.6rem;
  padding: 2rem 2.8rem;
  border-radius: 0.8rem;
  background-color: var(--accent);
  color: var(--pt-t-accent-bright);
  text-decoration: none;
  transition: background-color var(--_animspeed-medium) var(--_animbezier),
              color var(--_animspeed-medium) var(--_animbezier);
}

.mxd-category-tile__label {
  font: normal 700 2rem/1.2 var(--_font-default);
  letter-spacing: -0.03rem;
}

/* The count is the tile's secondary line, so it takes the token that means
   exactly that — not an opacity on the label, which would drop a 6.13:1
   pairing under AA the moment anyone picked a value by eye. */
.mxd-category-tile__count {
  font: normal 600 1.4rem/1.2 var(--_font-accent);
  color: var(--pt-t-accent-medium);
}

.no-touch .mxd-category-tile:hover {
  background-color: var(--base-bright);
  color: var(--accent);
}
.no-touch .mxd-category-tile:hover .mxd-category-tile__count {
  color: var(--t-medium);
}

/* Folks services — restore Azurio's cinematic image stack with original artwork. */
.folks-services .mxd-stack-cards {
  background: var(--base);
  /* Hold every pinned slide before the next card starts covering it. */
  gap: 75svh;
}
.folks-services .card__image {
  background: var(--folks-ink);
}
.folks-services .card__cover {
  background: linear-gradient(180deg, rgba(255,255,255,.08), transparent 35%);
}
.folks-services .card__title {
  top: auto;
  bottom: 7%;
  left: 6rem;
  width: fit-content;
  max-width: calc(100% - 12rem);
  padding: 1rem 2rem;
  transform: none;
  background: var(--folks-paper);
  text-align: left;
}
.folks-services .card__title p {
  font-size: clamp(4.4rem, 6.4vw, 10rem);
  line-height: 1.04;
  letter-spacing: -.045em;
  text-wrap: balance;
  text-shadow: none;
}
/* Description as a torn paper strip (services-strip-captions). `.card__descr` stays
   the vendor's element — app.js tweens its transform and opacity on reveal — so it
   only positions; every Folks transform lives on `.folks-strip` inside it. Block, not
   the vendor's flex row, which would shrink the strip to its text. */
.folks-services .card__descr {
  position: absolute;
  inset: 25% auto auto 6rem;
  display: block;
  width: clamp(36rem, 34vw, 56rem);
  height: auto;
  padding: 0;
}
/* Per-card placement keeps every strip off faces, the camera, the loupe and the phone.
   The artwork is `object-fit: cover`, so what a strip can cover depends on the frame's
   orientation, not its width: 768×1024 crops like a phone, 1024×768 like a desktop. */
.folks-services .folks-service-art--1 .card__descr {
  top: 12%;
}
.folks-services .folks-service-art--2 .card__descr {
  top: 6%;
}
/* Card 04's pair fills the top of the frame; its strip sits bottom-right over the
   jacket, above the title plate, which runs almost the full width here. */
.folks-services .folks-service-art--3 .card__descr {
  inset: auto 6rem 24% auto;
}
@media (orientation: portrait) {
  .folks-services .folks-service-art--0 .card__descr,
  .folks-services .folks-service-art--3 .card__descr {
    inset: auto auto 26% 6rem;
  }
  .folks-services .folks-service-art--1 .card__descr,
  .folks-services .folks-service-art--2 .card__descr {
    top: 12%;
  }
}
.folks-services .folks-strip,
.campaign-dialog .folks-strip,
.folks-process .folks-strip,
.contact-toast .folks-strip {
  position: relative;
  transform: rotate(var(--rot));
  filter: drop-shadow(0 1.2rem 1.4rem rgb(0 0 0 / .3));
}
.folks-services .folks-strip__tag,
.campaign-dialog .folks-strip__tag,
.folks-process .folks-strip__tag,
.contact-toast .folks-strip__tag {
  position: absolute;
  top: 0;
  left: 2.4rem;
  z-index: 1;
  padding: .5rem 1rem;
  background: var(--folks-ink);
  color: var(--folks-paper);
  font: 700 clamp(1.1rem, .95vw, 1.4rem)/1.2 var(--_font-accent);
  letter-spacing: .14em;
  text-transform: uppercase;
  white-space: nowrap;
  transform: translateY(-55%) rotate(-1.5deg);
}
.folks-services .folks-strip__paper,
.campaign-dialog .folks-strip__paper,
.folks-process .folks-strip__paper,
.contact-toast .folks-strip__paper {
  padding: 3.6rem 3.2rem 3rem;
  background: var(--folks-paper);
  clip-path: var(--torn);
}
.folks-services .folks-strip .card__text {
  max-width: none;
  margin: 0;
  color: var(--folks-ink);
  font-size: clamp(2.2rem, 2.15vw, 3.4rem);
  line-height: 1.28;
  font-weight: 700;
  letter-spacing: -.015em;
}
/* The key phrase's coral marker; `clone` repeats the swipe on every wrapped line.
   The strip rules above are shared with the campaign dialog's notes and the
   /jak-dzialamy/ process; the landing transitions below stay services-only. */
.folks-services .folks-strip__hl,
.campaign-dialog .folks-strip__hl,
.folks-process .folks-strip__hl {
  margin: 0 -.12em;
  padding: 0 .12em;
  background: linear-gradient(transparent 52%, var(--accent) 52% 94%, transparent 94%) no-repeat 0 0 / 100% 100%;
  color: inherit;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
/* The contact form's outcome toast (contact-form-feedback, §6): a folks-strip
   paper sheet pinned to the viewport. Below the shared strip rules on purpose,
   so its overrides win on order rather than on a heavier selector. z-index 10 keeps it over
   the page but under the vendor menu (overlay 11, toggle 12), so an opened menu
   still covers it. Phones: top, clear of the toggle; desktop: bottom-right. */
.contact-toast {
  position: fixed;
  z-index: 10;
  top: calc(env(safe-area-inset-top, 0px) + 8.4rem);
  right: 1.6rem;
  left: 1.6rem;
  pointer-events: none;
}
@media only screen and (min-width: 768px) {
  .contact-toast {
    top: auto;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 3rem);
    left: auto;
    right: 6rem;
    width: 42rem;
  }
}
.contact-toast .folks-strip__tag.is-error {
  background: var(--accent);
  color: var(--folks-ink);
}
.contact-toast .folks-strip__paper {
  padding: 3rem 5.2rem 2.6rem 2.8rem;
}
.contact-toast__title {
  margin: 0 0 0.6rem;
  color: var(--folks-ink);
  font: 700 2.2rem/1.15 var(--_font-default);
  letter-spacing: -0.03em;
}
.contact-toast__body {
  margin: 0;
  color: var(--folks-ink);
  font: 600 1.5rem/1.45 var(--_font-default);
}
.contact-toast__close {
  position: absolute;
  top: 1.8rem;
  right: 1.4rem;
  display: grid;
  place-items: center;
  width: 3.2rem;
  height: 3.2rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--folks-ink);
  cursor: pointer;
}
.contact-toast__close:focus-visible {
  outline: 2px solid var(--folks-ink);
  outline-offset: 2px;
}
/* Drop and settle; the strip's own --rot is the resting tilt. */
@keyframes contact-toast-in {
  from { opacity: 0; transform: translateY(-1.6rem) rotate(calc(var(--rot) - 4deg)); }
  to { opacity: 1; transform: rotate(var(--rot)); }
}
@keyframes contact-toast-fade {
  from { opacity: 0; }
}
.contact-toast .folks-strip {
  pointer-events: auto;
  animation: contact-toast-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@media (prefers-reduced-motion: reduce) {
  .contact-toast .folks-strip {
    animation: contact-toast-fade 0.2s ease-out both;
  }
}

/* Landing: app.js adds `.is-in` when it reveals the description. Before that the strip
   waits lifted and over-rotated with the marker undrawn; the transitions exist only
   under `.is-in`, so hiding snaps back while the vendor fades the parent out. */
@media (prefers-reduced-motion: no-preference) {
  .folks-services .card__descr:not(.is-in) .folks-strip {
    transform: translateY(-2.5rem) rotate(calc(var(--rot) - 7deg)) scale(1.07);
  }
  .folks-services .card__descr:not(.is-in) .folks-strip__hl {
    background-size: 0% 100%;
  }
  .folks-services .card__descr.is-in .folks-strip {
    transition: transform .62s cubic-bezier(.34, 1.56, .64, 1);
  }
  .folks-services .card__descr.is-in .folks-strip__hl {
    transition: background-size .55s cubic-bezier(.65, 0, .35, 1) .5s;
  }
}

/* Editorial artwork: preserve the paper colours and use ink-like typography. */
.folks-services .folks-service-art {
  --service-ink: var(--folks-ink);
}
.folks-services .folks-service-art--3 {
  --service-ink: #fff;
}
.folks-services .card__title p.permanent {
  color: var(--service-ink);
}
.folks-services .folks-service-art--0 .card__media {
  object-position: 65% center;
}
.folks-services .card__title p.permanent {
  color: var(--folks-ink);
}
.folks-services .folks-service-art--3 .card__title {
  background: var(--folks-ink);
}
.folks-services .folks-service-art--3 .card__title p.permanent {
  color: #fff;
}

/* One phone block for the whole section — it is last, so nothing above it needs
   a specificity bump to survive. */
@media (max-width: 767px) {
  .folks-services .card__descr,
  .folks-services .folks-service-art--0 .card__descr,
  .folks-services .folks-service-art--1 .card__descr,
  .folks-services .folks-service-art--2 .card__descr,
  .folks-services .folks-service-art--3 .card__descr {
    right: 3rem;
    left: 3rem;
    width: auto;
  }
  .folks-services .folks-strip__paper,
  .campaign-dialog .folks-strip__paper {
    padding: 2.8rem 2rem 2.2rem;
  }
  .folks-services .folks-strip .card__text {
    font-size: 2rem;
  }
  .folks-services .folks-strip__tag,
  .campaign-dialog .folks-strip__tag {
    left: 1.6rem;
    font-size: 1.1rem;
  }
  .folks-services .card__title {
    left: 3rem;
    bottom: 6%;
    max-width: calc(100% - 6rem);
    padding: .8rem 1rem;
  }
  .folks-services .card__title p {
    font-size: clamp(3.6rem, 9vw, 6rem);
  }
}

/* First-load editorial collage sequence, sized to stay clear of the captions. */
.mxd-loader__images {
  width: min(70vw, 42svh, 340px);
  height: auto;
  aspect-ratio: 1;
}

/* Campaign showcase follows Azurio's original landscape, staggered grid. */
.home-campaigns .campaign-preview { display: block; width: 100%; padding: 0; border: 0; background: #202020; color: white; text-align: left; }
.home-campaigns .campaign-cover { object-fit: cover; object-position: center 35%; filter: saturate(.18) brightness(.62) contrast(1.06); transition: filter .65s ease; }
.home-campaigns .campaign-preview:has(.campaign-brand--burger-king) .campaign-cover { object-position: center 25%; }
.home-campaigns .campaign-preview:has(.campaign-brand--irobot) .campaign-cover { object-position: center 60%; }
.home-campaigns .campaign-preview:has(.campaign-brand--suunto) .campaign-cover { object-position: center; }
/* 35% ends a pixel into the subtitle box burned into the frame (y≈1235), a cream line along the card's foot. */
.home-campaigns .campaign-preview:has(.campaign-brand--laurastar) .campaign-cover { object-position: center 32%; }
.home-campaigns .campaign-brand { display: flex; align-items: center; justify-content: center; width: 68%; height: 60%; max-width: none; max-height: none; pointer-events: none; filter: drop-shadow(0 1px 0 #fff3) drop-shadow(0 10px 18px #0003); }
.home-campaigns .campaign-brand .campaign-logo { display: block; width: 100%; height: 100%; max-height: none; object-fit: contain; opacity: 1; }
.home-campaigns .campaign-brand--burger-king { width: 52%; height: 60%; }
.home-campaigns .campaign-brand--suunto { width: 52%; height: 60%; }
.home-campaigns .campaign-brand--laurastar .campaign-logo { filter: brightness(0) invert(1); }
.home-campaigns .campaign-preview > .mxd-cover { background: radial-gradient(ellipse at center, #10131045, #10131010 70%); transition: opacity .65s ease; }

/* The card wakes up: the photograph blooms from desaturated to full colour, the
   vignette lifts, and the brand logo comes out of greyscale with them — one
   gesture in three registers, on one 0.65s curve.

   This replaced a five-still flipbook that cross-faded on hover. The stills
   cost 2.4 MB on every load, phones included, to imitate the film the card
   opens for real on click; colour says the same thing for nothing.

   `:focus-visible` is here beside `:hover` deliberately. The old treatment
   answered a keyboard focus by HIDING the logo (the preview video took the
   frame), which read as the card going dark under the cursor it could not
   see. Now focus and hover do the same thing.

   Gated on `hover: hover`, so a touch device never strands the logo in grey
   with no way to wake it — the resting photograph is already muted there, and
   the brand is what has to stay legible. `prefers-reduced-motion` keeps the
   colour and drops the transition: a colour change is not motion, and the
   flipbook it replaces did not run for those readers at all. */
@media (hover: hover) {
  /* The vendor FADES THE LOGO OUT on hover — `main.css` §13449,
     `.no-touch .mxd-project-item:hover .mxd-project-item__logowrap { opacity: 0 }`
     — because in Azurio's own design a video took the frame underneath it.
     That is the rule the old treatment was built around, and it is why the
     logo had nothing to come back to. Same specificity (0,4,0), later in the
     cascade, so this wins. */
  .home-campaigns .mxd-project-item:hover .mxd-project-item__logowrap { opacity: 1; }

  /* `.campaign-brand` is in every selector below to match the specificity of
     the base rule above, which sets `opacity: 1` on the same element. */
  .home-campaigns .campaign-brand .campaign-logo { filter: grayscale(1); opacity: .82; transition: filter .65s ease, opacity .65s ease; }
  .home-campaigns .campaign-preview:hover .campaign-brand .campaign-logo,
  .home-campaigns .campaign-preview:focus-visible .campaign-brand .campaign-logo { filter: none; opacity: 1; }
  /* Laurastar's source is unreadable on a dark poster, so it is forced to flat
     white and has no colour to come back to. It brightens instead. */
  .home-campaigns .campaign-brand--laurastar .campaign-logo { filter: brightness(0) invert(1); opacity: .5; }
  .home-campaigns .campaign-preview:hover .campaign-brand--laurastar .campaign-logo,
  .home-campaigns .campaign-preview:focus-visible .campaign-brand--laurastar .campaign-logo { filter: brightness(0) invert(1) !important; opacity: 1; }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .home-campaigns .campaign-preview:hover .campaign-cover,
  .home-campaigns .campaign-preview:focus-visible .campaign-cover { filter: saturate(1) brightness(1); }
  .home-campaigns .campaign-preview:hover > .mxd-cover,
  .home-campaigns .campaign-preview:focus-visible > .mxd-cover { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .home-campaigns .campaign-cover,
  .home-campaigns .campaign-preview > .mxd-cover,
  .home-campaigns .campaign-brand .campaign-logo { transition: none; }
}
/* `!important` because main.css opens with `button:active, button:focus { outline: none
   !important }`. An important declaration beats every normal one whatever its
   specificity, so without it this ring (and the creator marquee's below) computed to
   none and keyboard focus on this button was invisible. Important against important
   falls back to specificity, which this selector wins. */
.home-campaigns .campaign-preview:focus-visible { outline: 2px solid var(--accent) !important; outline-offset: 5px; }
/* Campaign dialog — a full-screen coral brief in the services collage's paper language
   (campaign-dialog-brief, mock B). Ink on coral is 6.9:1; there is no legal light-on-coral
   pairing, so every light surface here is paper carrying ink. */
html:has(.campaign-dialog[open]) { overflow: hidden; }
.campaign-dialog { position: fixed; inset: 0; width: 100%; max-width: none; height: 100%; max-height: none; margin: 0; padding: 3.2rem 6rem 4rem; border: 0; border-radius: 0; background: var(--accent); color: var(--folks-ink); overscroll-behavior: contain; }
.campaign-dialog[open] { display: flex; flex-direction: column; gap: 2.4rem; }
.campaign-dialog::backdrop { background: var(--accent); }
/* Opening fades the coral in and lifts the film and brief 1.2rem into place; closing is a
   shorter fade. `allow-discrete` holds display and the top layer until the fade ends, and
   @starting-style gives the first frame after showModal() something to transition from.
   The resting state is `translate: none`: a non-none value would make .campaign-detail
   the containing block for anything fixed inside it. */
.campaign-dialog, .campaign-dialog::backdrop { opacity: 0; transition: opacity .2s ease-in, display .2s allow-discrete, overlay .2s allow-discrete; }
.campaign-dialog[open], .campaign-dialog[open]::backdrop { opacity: 1; transition: opacity .3s ease-out, display .3s allow-discrete, overlay .3s allow-discrete; }
.campaign-dialog .campaign-detail { translate: 0 1.2rem; transition: translate .2s ease-in; }
.campaign-dialog[open] .campaign-detail { translate: none; transition: translate .45s cubic-bezier(.2, .7, .2, 1) .06s; }
@starting-style {
  .campaign-dialog[open], .campaign-dialog[open]::backdrop { opacity: 0; }
  .campaign-dialog[open] .campaign-detail { translate: 0 1.2rem; }
}
@media (prefers-reduced-motion: reduce) {
  .campaign-dialog .campaign-detail, .campaign-dialog[open] .campaign-detail { translate: none; transition: none; }
}
/* The ground carries the Folks mark, scattered and tone-on-tone. A fixed layer under the
   content (the dialog is its stacking context), so it stays put while the brief — or on a
   phone the whole dialog — scrolls over it. A mask keeps the colour a token. */
.campaign-dialog::before { content: ""; position: fixed; inset: 0; z-index: -1; background: var(--folks-ink); opacity: .06; mask: url("/img/campaign-dialog-pattern.svg") 0 0 / 48rem repeat; pointer-events: none; }
/* The site's coral ring vanishes on a coral ground. `!important` for the same reason as
   the card's ring above: main.css removes button outlines with an important rule. */
.campaign-dialog :focus-visible { outline: 2px solid var(--folks-ink) !important; outline-offset: 3px; }
.campaign-dialog__position, .campaign-close, .campaign-scope, .campaign-results span { font: 400 1.2rem/1.4 var(--_font-accent); letter-spacing: .12em; text-transform: uppercase; }
.campaign-dialog__bar { display: flex; flex: none; align-items: center; justify-content: space-between; gap: 1.6rem; }
.campaign-dialog__position { padding: .6rem 1.2rem; background: var(--folks-ink); color: var(--folks-paper); }
.campaign-close { display: flex; align-items: center; gap: 1.2rem; min-height: 4.4rem; padding: 0 1.6rem; border: 0; background: var(--folks-ink); color: var(--folks-paper); cursor: pointer; }
.campaign-detail { display: grid; flex: 1; min-height: 0; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); gap: 6.4rem; }
/* The film as a taped paper print. Its height is set from the viewport, not the grid
   row, so the auto column can size to it: bar, paddings and the print's own border. */
.campaign-print { position: relative; align-self: start; padding: 1rem; background: var(--folks-paper); rotate: -2deg; filter: drop-shadow(0 1.6rem 2.8rem rgb(0 0 0 / .35)); }
.campaign-print video { display: block; height: min(68rem, calc(100dvh - 16rem)); width: auto; aspect-ratio: 9 / 16; background: #000; object-fit: contain; }
.campaign-print__tape { position: absolute; z-index: 2; top: -1.6rem; left: 50%; width: 12rem; height: 3.2rem; margin-left: -6rem; background: rgb(242 238 231 / .78); rotate: 3deg; }
/* Film grain over the video box only (inset = the paper border). <video> takes no ::after,
   so the print carries it; its filter isolates the blend to the film. Not the marquee
   tile: that one sits near mid-grey, which soft-light barely changes over footage — this
   one is stretched and opaque. Strength picked from a mock (dialog-grain, D6). */
.campaign-print::after { content: ""; position: absolute; z-index: 1; inset: 1rem; pointer-events: none; opacity: .35; mix-blend-mode: soft-light; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='128' height='128'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='.33 .33 .33 0 0 .33 .33 .33 0 0 .33 .33 .33 0 0 0 0 0 0 1'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3' intercept='-1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='128' height='128' filter='url(%23n)'/%3E%3C/svg%3E"); animation: campaign-grain 1s infinite; }
/* Ten jumps a second, like projected film; steps(1) per keyframe so it never slides. */
@keyframes campaign-grain {
  0% { background-position: 0 0; animation-timing-function: steps(1, end); }
  10% { background-position: -37px 21px; animation-timing-function: steps(1, end); }
  20% { background-position: 53px -64px; animation-timing-function: steps(1, end); }
  30% { background-position: -88px -12px; animation-timing-function: steps(1, end); }
  40% { background-position: 19px 77px; animation-timing-function: steps(1, end); }
  50% { background-position: 71px 40px; animation-timing-function: steps(1, end); }
  60% { background-position: -52px 93px; animation-timing-function: steps(1, end); }
  70% { background-position: 96px -41px; animation-timing-function: steps(1, end); }
  80% { background-position: -15px -99px; animation-timing-function: steps(1, end); }
  90% { background-position: 44px 58px; animation-timing-function: steps(1, end); }
  100% { background-position: 0 0; }
}
@media (prefers-reduced-motion: reduce) { .campaign-print::after { animation: none; } }
/* The site's own player (dialog-player, CampaignPlayer.tsx): a bar across the film's foot
   on a dark scrim, above the grain. While the film plays it steps aside after the
   pointer rests; paused, focused or on a screen that cannot hover, it stays. */
.campaign-print video { cursor: pointer; }
.campaign-player__bar { position: absolute; z-index: 3; right: 1rem; bottom: 1rem; left: 1rem; display: flex; align-items: center; gap: .8rem; padding: 3.6rem .8rem .6rem; background: linear-gradient(to top, rgb(0 0 0 / .72), transparent); color: var(--folks-paper); font: 400 1.2rem/1 var(--_font-accent); letter-spacing: .06em; font-variant-numeric: tabular-nums; transition: opacity .25s; }
.campaign-print.is-idle[data-state="playing"]:not(:focus-within) .campaign-player__bar { opacity: 0; pointer-events: none; }
.campaign-print.is-idle[data-state="playing"]:not(:focus-within) video { cursor: none; }
@media (hover: none) { .campaign-print .campaign-player__bar { opacity: 1 !important; pointer-events: auto !important; } }
@media (prefers-reduced-motion: reduce) { .campaign-player__bar { transition: none; } }
.campaign-player__control { display: grid; flex: none; place-items: center; width: 3.6rem; height: 3.6rem; padding: 0; border: 0; background: none; color: inherit; font-size: 1.8rem; cursor: pointer; }
.campaign-player__time { flex: none; white-space: nowrap; }
/* The film's progress: paper fill on a faint track, a square thumb — no engine's default. */
.campaign-player__seek { --progress: 0%; flex: 1; min-width: 4rem; height: 3.6rem; margin: 0; background: none; cursor: pointer; appearance: none; -webkit-appearance: none; }
.campaign-player__seek::-webkit-slider-runnable-track { height: .3rem; background: linear-gradient(to right, var(--folks-paper) var(--progress), rgb(242 238 231 / .35) var(--progress)); }
.campaign-player__seek::-webkit-slider-thumb { width: 1.2rem; height: 1.2rem; margin-top: -.45rem; border: 0; border-radius: 0; background: var(--folks-paper); -webkit-appearance: none; }
.campaign-player__seek::-moz-range-track { height: .3rem; background: rgb(242 238 231 / .35); }
.campaign-player__seek::-moz-range-progress { height: .3rem; background: var(--folks-paper); }
.campaign-player__seek::-moz-range-thumb { width: 1.2rem; height: 1.2rem; border: 0; border-radius: 0; background: var(--folks-paper); }
/* Ink rings vanish on the scrim; paper ones read there. */
.campaign-dialog .campaign-player__bar :focus-visible { outline-color: var(--folks-paper) !important; outline-offset: 0; }
/* Paused: the dialog's own ink block (as "Zamknij"), centred on the film. */
.campaign-player__resume { position: absolute; z-index: 3; top: 50%; left: 50%; display: flex; align-items: center; gap: 1.2rem; min-height: 4.8rem; padding: 0 1.8rem; border: 0; background: var(--folks-ink); color: var(--folks-paper); font: 400 1.3rem/1 var(--_font-accent); letter-spacing: .12em; text-transform: uppercase; translate: -50% -50%; rotate: 2deg; box-shadow: 0 1rem 2.4rem rgb(0 0 0 / .35); cursor: pointer; }
.campaign-player__resume i { font-size: 1.6rem; }
/* Fullscreen takes the whole print: straightened, paper and tape gone, film on black. */
.campaign-print:fullscreen { display: flex; align-items: center; justify-content: center; padding: 0; background: #000; rotate: none; filter: none; }
.campaign-print:fullscreen video { width: auto; height: 100%; max-width: 100%; }
.campaign-print:fullscreen::after, .campaign-print:fullscreen .campaign-player__bar { inset-inline: 0; }
.campaign-print:fullscreen::after { inset-block: 0; }
.campaign-print:fullscreen .campaign-player__bar { bottom: 0; padding-inline: 2.4rem; }
.campaign-print:fullscreen .campaign-print__tape { display: none; }
/* The brief scrolls on its own so the film stays put on a short laptop screen. The
   negative margin gives rotated notes and their shadows room inside the scroller. */
.campaign-brief { min-height: 0; margin: -1.6rem -2rem 0; padding: 1.6rem 2rem 8rem; overflow-y: auto; overscroll-behavior: contain; }
.campaign-brief__title { width: fit-content; margin: 0 0 4.4rem; padding: .2rem 2.2rem .8rem; background: var(--folks-paper); color: var(--folks-ink); font: 600 clamp(4.4rem, 5.8vw, 8.4rem)/1.1 var(--_font-default); letter-spacing: -.045em; }
.campaign-brief__notes { display: grid; grid-template-columns: repeat(2, minmax(0, 40rem)); grid-template-rows: var(--rows); align-items: start; column-gap: 4rem; }
/* Slots come from the markup (--col, --row); the second column sits a step lower. */
.campaign-brief__notes > * { grid-column: var(--col); grid-row: var(--row); margin-top: calc(var(--under) * 4.4rem); translate: 0 calc((var(--col) - 1) * 3.6rem); }
.campaign-note .folks-strip__tag { margin: 0; }
.campaign-note__heading { margin: 0 0 1rem; color: var(--folks-ink); font: 700 2.5rem/1.15 var(--_font-default); letter-spacing: -.03em; }
/* Reading size, not the services strip's display size. Manrope's word space is narrow at
   this size; with the mock's negative tracking words ran together on 1x screens. */
.campaign-note__body { margin: 0; color: var(--folks-ink); font: 600 1.7rem/1.5 var(--_font-default); word-spacing: .08em; }
.campaign-results { display: flex; flex-direction: column; gap: .6rem; margin: 0; padding: 0; list-style: none; rotate: -.6deg; }
.campaign-results li { display: flex; align-items: baseline; justify-content: space-between; gap: 1.6rem; padding: .8rem 1.6rem; background: var(--folks-ink); color: var(--folks-paper); }
.campaign-results strong { font: 700 3.4rem/1.1 var(--_font-default); letter-spacing: -.04em; white-space: nowrap; }
.campaign-results span { text-align: right; }
.campaign-scope { display: flex; flex-direction: column; gap: 1rem; }
.campaign-scope__label { margin: 0; color: var(--folks-ink); font: inherit; font-weight: 700; }
.campaign-scope ul { display: flex; flex-wrap: wrap; gap: .6rem; margin: 0; padding: 0; list-style: none; }
.campaign-scope li { padding: .7rem 1.1rem; background: var(--folks-ink); color: var(--folks-paper); }
/* Phone: one column in document order — bar, film, heading, notes, results, scope — and
   the dialog itself scrolls. */
@media (max-width: 767px) {
  .campaign-dialog { padding: 1.2rem 1.6rem 4rem; overflow-y: auto; }
  .campaign-dialog[open] { gap: 3.2rem; }
  .campaign-detail { display: flex; flex: none; flex-direction: column; gap: 3.2rem; }
  .campaign-print { align-self: center; margin-top: 1.2rem; }
  .campaign-print video { width: min(29rem, 74vw); height: auto; }
  .campaign-brief { margin: 0; padding: 0; overflow: visible; }
  .campaign-brief__title { margin-bottom: 4.4rem; font-size: 4.6rem; }
  .campaign-brief__notes { display: flex; flex-direction: column; gap: 4.4rem; }
  .campaign-brief__notes > * { margin-top: 0; translate: none; }
}


/* CTA band heading (CtaMarquee.tsx): the closing full stop is white. This is one of
   the two named exceptions to brand-identity's "no white on coral" — the other is the
   viewfinder's REC light below — and e2e/brand-contrast.spec.ts holds it to those two.
   The last word shares a no-wrap span with the full stop, because SplitType makes the
   full stop its own .word box and it would otherwise wrap alone. */
.cta-heading__tail { white-space: nowrap; }
.cta-heading__dot { color: #fff; }

/* The marked phrase on an ink tape: coral on --pt-t-accent-bright, the band's own pair
   reversed (6.13:1). The slab is ::before, not the span's background, so app.js can
   wipe it in through --tape-wipe without scaling the letters. It defaults to 1: fully
   drawn before the vendor boots, and always under reduced motion. */
.cta-heading__tape {
  display: inline-block;
  position: relative;
  padding: 0 .14em .06em;
  margin-right: .04em;
  color: var(--accent);
  white-space: nowrap;
  line-height: 1.02;
  transform: rotate(-2deg);
}
.cta-heading__tape::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--pt-t-accent-bright);
  transform-origin: left center;
  transform: scaleX(var(--tape-wipe, 1));
}
@media (prefers-reduced-motion: reduce) {
  .cta-heading__tape::before { transform: none; }
}

/* Bracket colour (brand-identity, "Brackets are coral on the ink ground"). Three families
   draw `[ ]`: the Viewfinder's corners below, the vendor line button's glyphs (the forms'
   `[ Wyślij ]`) and the static labels' typed brackets (§ about editorial). All read one
   token, so a ground decides once. Ink takes the accent. The coral band cannot (coral on
   coral) and takes the element's own text colour with a white REC light, the second of
   the band's two white exceptions; the paper brief takes its ink, since coral on cream is
   2.7:1. `currentColor` inside a custom property resolves where it is read, i.e. against
   the bracket's own element, not the section that declares it. */
:root {
  --bracket: var(--accent);
  --bracket-light: var(--bracket);
}
.bg-color-accent {
  --bracket: currentColor;
  --bracket-light: #fff;
}
.folks-about {
  --bracket: currentColor;
}
.btn-line::before,
.btn-line::after {
  color: var(--bracket);
}

/* Viewfinder (ViewfinderLink.tsx): the hover on every link that used the vendor's
   mxd-scramble. On hover or keyboard focus, four crop marks frame the label and a REC
   row with a running timecode fades in above; the label is never touched. `.btn-line`
   links draw their [ ] with the marks at rest (the glyph brackets are off) so the
   brackets split into the frame; links without brackets look unchanged at rest. Touch
   devices keep the resting state: the open state sits behind (hover: hover).
   Every rule is `:is(a, span).viewfinder > …` (0,2,1): vendor `.btn-line-icon span`,
   `.mxd-header__link span` and `.anim-uni-slide-down span` set position and display on
   every span inside and would otherwise win. The span is the blog lead's `[ Czytaj ]`
   (ViewfinderHost): its card link is what is hovered or focused, so the open state keys
   on `.viewfinder-host` as well as on the link itself. */
:is(a, span).viewfinder { position: relative; }
:is(a, span).viewfinder.btn-line { padding-inline: .9em; }
:is(a, span).viewfinder.btn-line::before, :is(a, span).viewfinder.btn-line::after { content: none; }
:is(a, span).viewfinder > .viewfinder__corner {
  position: absolute;
  display: block;
  width: 14px;
  height: 12px;
  border: 0 solid var(--bracket);
  opacity: 0;
}
:is(a, span).viewfinder > .viewfinder__corner--tl { top: -6px; left: -4px; border-left-width: 2px; border-top-width: 2px; }
:is(a, span).viewfinder > .viewfinder__corner--bl { bottom: -6px; left: -4px; border-left-width: 2px; border-bottom-width: 2px; }
:is(a, span).viewfinder > .viewfinder__corner--tr { top: -6px; right: -4px; border-right-width: 2px; border-top-width: 2px; }
:is(a, span).viewfinder > .viewfinder__corner--br { bottom: -6px; right: -4px; border-right-width: 2px; border-bottom-width: 2px; }
/* Resting [ ]: top and bottom halves meet at each edge. */
:is(a, span).viewfinder.btn-line > .viewfinder__corner { width: .4em; height: 36%; opacity: 1; }
:is(a, span).viewfinder.btn-line > .viewfinder__corner--tl, :is(a, span).viewfinder.btn-line > .viewfinder__corner--tr { top: 14%; }
:is(a, span).viewfinder.btn-line > .viewfinder__corner--bl, :is(a, span).viewfinder.btn-line > .viewfinder__corner--br { bottom: 14%; }
:is(a, span).viewfinder.btn-line > .viewfinder__corner--tl, :is(a, span).viewfinder.btn-line > .viewfinder__corner--bl { left: 0; }
:is(a, span).viewfinder.btn-line > .viewfinder__corner--tr, :is(a, span).viewfinder.btn-line > .viewfinder__corner--br { right: 0; }
:is(a, span).viewfinder > .viewfinder__rec {
  position: absolute;
  left: -10px;
  right: -10px;
  bottom: calc(100% + 20px);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.2rem;
  font: 700 1rem/1 var(--_font-accent);
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  color: var(--bracket);
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
}
:is(a, span).viewfinder > .viewfinder__rec > span { display: inline-flex; align-items: center; gap: 6px; position: static; }
:is(a, span).viewfinder .viewfinder__light { display: block; width: 8px; height: 8px; border-radius: 50%; background: var(--bracket-light); }
/* Open state, written twice: hover must stay inside the media query, focus must not. */
@media (hover: hover) {
  :is(a.viewfinder:hover, .viewfinder-host:hover span.viewfinder) > .viewfinder__corner { width: 14px; height: 12px; opacity: 1; }
  :is(a.viewfinder:hover, .viewfinder-host:hover span.viewfinder) > .viewfinder__corner--tl { top: -12px; left: -10px; }
  :is(a.viewfinder:hover, .viewfinder-host:hover span.viewfinder) > .viewfinder__corner--bl { bottom: -12px; left: -10px; }
  :is(a.viewfinder:hover, .viewfinder-host:hover span.viewfinder) > .viewfinder__corner--tr { top: -12px; right: -10px; }
  :is(a.viewfinder:hover, .viewfinder-host:hover span.viewfinder) > .viewfinder__corner--br { bottom: -12px; right: -10px; }
  :is(a.viewfinder:hover, .viewfinder-host:hover span.viewfinder) > .viewfinder__rec { opacity: 1; transform: none; }
}
:is(a.viewfinder:focus-visible, .viewfinder-host:focus-visible span.viewfinder) > .viewfinder__corner { width: 14px; height: 12px; opacity: 1; }
:is(a.viewfinder:focus-visible, .viewfinder-host:focus-visible span.viewfinder) > .viewfinder__corner--tl { top: -12px; left: -10px; }
:is(a.viewfinder:focus-visible, .viewfinder-host:focus-visible span.viewfinder) > .viewfinder__corner--bl { bottom: -12px; left: -10px; }
:is(a.viewfinder:focus-visible, .viewfinder-host:focus-visible span.viewfinder) > .viewfinder__corner--tr { top: -12px; right: -10px; }
:is(a.viewfinder:focus-visible, .viewfinder-host:focus-visible span.viewfinder) > .viewfinder__corner--br { bottom: -12px; right: -10px; }
:is(a.viewfinder:focus-visible, .viewfinder-host:focus-visible span.viewfinder) > .viewfinder__rec { opacity: 1; transform: none; }
/* Motion only when it is wanted: without this block the frame still opens, instantly and unblinking. */
@media (prefers-reduced-motion: no-preference) {
  :is(a, span).viewfinder > .viewfinder__corner {
    transition: .42s cubic-bezier(.34, 1.56, .64, 1);
    transition-property: top, bottom, left, right, width, height, opacity;
  }
  :is(a, span).viewfinder > .viewfinder__rec { transition: opacity .2s ease, transform .3s var(--_animbezier); }
  :is(a.viewfinder:focus-visible, .viewfinder-host:focus-visible span.viewfinder) > .viewfinder__rec { transition-delay: .12s; }
  :is(a.viewfinder:focus-visible, .viewfinder-host:focus-visible span.viewfinder) .viewfinder__light { animation: viewfinder-rec 1s steps(1) infinite .5s; }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  :is(a.viewfinder:hover, .viewfinder-host:hover span.viewfinder) > .viewfinder__rec { transition-delay: .12s; }
  :is(a.viewfinder:hover, .viewfinder-host:hover span.viewfinder) .viewfinder__light { animation: viewfinder-rec 1s steps(1) infinite .5s; }
}
@keyframes viewfinder-rec { 50% { opacity: 0; } }
/* Header "Say Hello": the header's 3rem top padding is exactly the row's height above,
   so the REC row goes below the frame instead. */
.mxd-header__controls a.viewfinder > .viewfinder__rec { bottom: auto; top: calc(100% + 20px); }

/* Creator CTA: fixed geometry, 40px/s, and one terminal gap in EACH group.
   No vendor marquee-left--gsap class: its initializer clones React-owned DOM.
   It sits on the coral CTA band, so its text reads the on-accent
   token (§3); the two tints are color-mix() of that token rather than rgb()
   literals — mixing with transparent keeps the colour and scales the alpha. */
.creator-marquee {
  --creator-width: 200px;
  --creator-gap: 20px;
  /* --creator-count is set inline from the delivery manifest: count × (200 + 20) / 40. */
  --creator-duration: calc(var(--creator-count) * 5.5s);
  color: var(--pt-t-accent-bright);
  /* Each breakpoint's margin keeps the 6rem the removed pause row used to take, so the
     strip still sits where it did below the heading (cta-refinement, Przemek 2026-09-14). */
  margin-top: 14rem;
  padding-bottom: 3rem;
}
.creator-marquee__viewport:focus-visible {
  /* !important: main.css `button:focus { outline: none !important }` — see the
     campaign focus ring above. */
  outline: 3px solid var(--pt-t-accent-bright) !important;
  outline-offset: -4px;
}
.creator-marquee__viewport {
  width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
}
.creator-marquee__track { display: flex; width: max-content; }
.creator-marquee__group {
  display: flex;
  flex: 0 0 auto;
  align-items: flex-end;
  gap: var(--creator-gap);
  padding-right: var(--creator-gap);
}
.creator-marquee__group[aria-hidden="true"] { display: none; }
.creator-marquee__card { position: relative; isolation: isolate; width: var(--creator-width); flex: 0 0 var(--creator-width); margin: 0; }
.creator-marquee__photo {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  aspect-ratio: var(--photo-ratio);
  background: #d48a7d;
  border-radius: 5px;
}
.creator-marquee__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--photo-focal);
}
.creator-marquee__photo[data-tone="natural"] img { filter: saturate(.96) contrast(1.015); }
.creator-marquee__photo[data-tone="soft"] img { filter: saturate(.92) contrast(.98) brightness(1.025); }
.creator-marquee__photo::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .055;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='128' height='128'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Cpath fill='%23808080' filter='url(%23n)' d='M0 0h128v128H0z'/%3E%3C/svg%3E");
}
/* Editorial cover: dark lower scrim, white identity and an offset audience figure.
   Grain stays inside the sibling photo layer, below all caption typography. */
.creator-marquee__card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 5px;
  pointer-events: none;
  background: linear-gradient(to top, rgb(0 0 0 / 90%), rgb(0 0 0 / 76%) 36%, transparent 72%);
}
.creator-marquee__card .creator-marquee__caption {
  position: absolute;
  z-index: 1;
  inset: auto 12px 14px;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0 8px;
  color: #fff;
  text-shadow: 0 1px 4px rgb(0 0 0 / 25%);
  line-height: 1;
}
.creator-marquee__identity { min-width: 0; flex: 1; font-size: 18px; font-weight: 750; letter-spacing: -.045em; }
.creator-marquee__identity > span > span { display: block; }
.creator-marquee__identity::before {
  content: "";
  display: block;
  width: 23px;
  height: 3px;
  margin-bottom: 9px;
  background: var(--accent);
}
.creator-marquee__card[data-caption-size="compact"] .creator-marquee__identity { font-size: 15px; }
.creator-marquee__stat { flex: none; text-align: right; }
.creator-marquee__platform, .creator-marquee__metric { display: block; font-size: 9px; font-weight: 500; letter-spacing: .015em; }
.creator-marquee__platform { text-transform: uppercase; letter-spacing: .09em; margin-bottom: 5px; }
.creator-marquee__number { display: block; font-family: var(--font-bebas), sans-serif; font-size: 42px; line-height: .9; letter-spacing: -.02em; }
.creator-marquee__number small { display: inline-block; margin-left: 2px; font-family: var(--_font-default); font-size: 10px; letter-spacing: 0; }
.creator-marquee__metric { margin-top: 4px; }
/* Per-platform pills on their own caption row. Touch and 200px cards show them always,
   icon-only — three counted pills do not fit 200px. Pointer devices with 300px cards
   collapse the row with a 0fr grid track instead of display or visibility, so the
   links stay focusable and :focus-within can reveal them. */
.creator-marquee__socials { flex: 0 0 100%; display: grid; grid-template-rows: 1fr; margin-top: 8px; }
.creator-marquee__socials > span { display: flex; gap: 4px; min-height: 0; overflow: hidden; padding: 3px; margin: -3px; }
.creator-marquee__pill {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-width: 28px;
  height: 28px;
  padding: 0 6px;
  border-radius: 4px;
  background: rgb(255 255 255 / 14%);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 28%);
  color: #fff;
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
  text-shadow: none;
  text-decoration: none;
  white-space: nowrap;
}
.creator-marquee__pill i { font-size: 13px; }
.creator-marquee__pill small { margin-left: 2px; font-size: 8px; font-weight: 500; }
.creator-marquee__pill-count { display: none; }
a.creator-marquee__pill:hover { background: #fff; color: #111; }
a.creator-marquee__pill:focus-visible { outline: 2px solid #fff !important; outline-offset: 1px; }
@media (hover: hover) and (min-width: 768px) {
  .creator-marquee__socials { grid-template-rows: 0fr; margin-top: 0; opacity: 0; transition: grid-template-rows .25s ease, margin-top .25s ease, opacity .2s ease; }
  .creator-marquee__pill-count { display: inline; }
  .creator-marquee__card:is(:hover, :focus-within) .creator-marquee__socials { grid-template-rows: 1fr; margin-top: 10px; opacity: 1; }
  .creator-marquee__card:is(:hover, :focus-within) .creator-marquee__stat { display: none; }
  .creator-marquee__socials > span { gap: 6px; }
  .creator-marquee__pill { gap: 5px; padding: 0 8px; font-size: 11px; }
  .creator-marquee__pill i { font-size: 14px; }
  .creator-marquee__pill small { font-size: 9px; }
}
@media (prefers-reduced-motion: reduce) {
  .creator-marquee__socials { transition: none; }
}
@media (min-width: 768px) {
  .creator-marquee__card .creator-marquee__caption { inset: auto 20px 21px; gap: 0 12px; }
  .creator-marquee__identity { font-size: 27px; }
  .creator-marquee__card[data-caption-size="compact"] .creator-marquee__identity { font-size: 22px; }
  .creator-marquee__identity::before { width: 30px; margin-bottom: 12px; }
  .creator-marquee__number { font-size: 62px; }
  .creator-marquee__number small { font-size: 13px; }
  .creator-marquee__platform, .creator-marquee__metric { font-size: 11px; }
}
@media (min-width: 768px) {
  .creator-marquee { --creator-width: 300px; --creator-gap: 30px; --creator-duration: calc(var(--creator-count) * 8.25s); margin-top: 17.3rem; }
}
@media (min-width: 1200px) {
  .creator-marquee { margin-top: 17.7rem; }
}
@media (min-width: 1600px) {
  .creator-marquee { margin-top: 19rem; }
}
@media (prefers-reduced-motion: no-preference) {
  .creator-marquee[data-ready="true"] .creator-marquee__viewport { overflow-x: clip; }
  .creator-marquee[data-ready="true"] .creator-marquee__group[aria-hidden="true"] { display: flex; }
  .creator-marquee[data-ready="true"] .creator-marquee__track {
    animation: creator-photo-loop var(--creator-duration) linear infinite;
  }
  /* Keyboard focus only: a clicked pill keeps focus when its new tab is closed, and
     :focus-within would leave the strip frozen for a visitor who never pressed a key. */
  .creator-marquee:has(:focus-visible) .creator-marquee__track { animation-play-state: paused; }
}
/* Only a card under the pointer holds the strip; the space above
   shorter cards and the section padding do not. Duplicate-group cards count too. */
@media (hover: hover) {
  .creator-marquee__track:has(.creator-marquee__card:hover) { animation-play-state: paused; }
}
/* Mouse drag seeks the running strip (CreatorPhotoMarquee); the cursor only offers it where it works. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .creator-marquee[data-ready="true"] .creator-marquee__viewport { cursor: grab; }
}
.creator-marquee[data-dragging] .creator-marquee__track { animation-play-state: paused; }
.creator-marquee[data-dragging] .creator-marquee__viewport,
.creator-marquee[data-dragging] .creator-marquee__viewport * { cursor: grabbing; user-select: none; }
@keyframes creator-photo-loop { to { transform: translateX(-50%); } }

/* The vendor loader otherwise covers server-rendered CTA content forever without JS. */
body:has(.creator-marquee__nojs) .mxd-loader,
body:has(.creator-marquee__nojs) .mxd-page-transition { display: none; }

.creator-marquee__sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Four campaign posters form a single staggered composition. */
.home-campaigns .campaign-masonry { display: grid; grid-template-columns: 1.06fr 1fr; grid-template-rows: repeat(12, minmax(0, 1fr)); gap: clamp(12px, 1.5vw, 24px); aspect-ratio: 1.42; }
.home-campaigns .campaign-masonry > .mxd-project-item { min-width: 0; min-height: 0; padding: 0; margin: 0; gap: 0; }
.home-campaigns .campaign-masonry > :nth-child(1) { grid-column: 1; grid-row: 1 / 6; }
.home-campaigns .campaign-masonry > :nth-child(2) { grid-column: 2; grid-row: 1 / 8; }
.home-campaigns .campaign-masonry > :nth-child(3) { grid-column: 1; grid-row: 6 / 13; }
.home-campaigns .campaign-masonry > :nth-child(4) { grid-column: 2; grid-row: 8 / 13; }
.home-campaigns .campaign-masonry .campaign-preview { height: 100%; min-height: 0; border-radius: 0; isolation: isolate; }
.home-campaigns .campaign-masonry .campaign-cover { width: 100%; height: 100%; aspect-ratio: auto; }
.home-campaigns .campaign-masonry .campaign-brand { max-width: 380px; }
.home-campaigns .campaign-masonry .campaign-brand--burger-king, .home-campaigns .campaign-masonry .campaign-brand--suunto { max-width: 240px; }
@media (max-width: 767px) {
  .home-campaigns .campaign-masonry { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; aspect-ratio: auto; gap: 14px; }
  .home-campaigns .campaign-masonry > .mxd-project-item { grid-column: auto; grid-row: auto; aspect-ratio: 4 / 3; }
  .home-campaigns .campaign-masonry > :nth-child(1), .home-campaigns .campaign-masonry > :nth-child(4) { aspect-ratio: 3 / 2; }
}

.campaign-placeholder { position: relative; display: flex; height: 100%; min-height: 0; flex-direction: column; justify-content: space-between; overflow: hidden; padding: clamp(24px, 4vw, 64px); border-radius: 0; background: var(--accent); color: #191919; }
.campaign-placeholder::before { content: ''; position: absolute; width: 75%; aspect-ratio: 1; border: clamp(24px, 5vw, 80px) solid currentColor; border-radius: 50%; opacity: .08; right: -25%; top: -20%; pointer-events: none; }
.campaign-placeholder--1 { background: #e9e5dc; }
.campaign-placeholder--2 { background: #252525; color: var(--accent); }
.campaign-placeholder--3 { background: #c9cec1; }
.campaign-placeholder__eyebrow, .campaign-placeholder__caption { font-size: 12px; letter-spacing: .12em; text-transform: uppercase; }
.campaign-placeholder__name { position: relative; font-size: clamp(38px, 5vw, 84px); line-height: 1; font-weight: 700; letter-spacing: -.05em; }

/* --- 12. Footer (footer-refinement) ----------------------------------------
   The footer's own pieces on top of the vendor skeleton: the contact column,
   the creator slot, the viewfinder wordmark and the Good One signature. Sizes
   are the approved mock's 1440 px design units in rem (1rem = 10px).
   Grey text reads --t-medium, which is the mock's "muted" #8a8d96: the
   vendor's --t-muted (#36363c) is a rule colour at 1.6:1, never text. */

/* Contact column: its title-to-content gap is the vendor block's own 1.6rem. */
.footer-contact {
  display: flex;
  flex-direction: column;
  gap: 3rem;
}

.footer-contact__group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.footer-contact address,
.footer-contact__group a {
  margin: 0;
  font: normal 500 2rem/1.5 var(--_font-default);
  color: var(--t-bright);
  transition: color var(--_animspeed-fast) ease-in-out;
}

.footer-contact__key {
  color: var(--t-medium);
}

.footer-contact__socials {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2.2rem;
}

.footer-contact__socials a {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font: normal 700 1.4rem/1 var(--_font-accent);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
  color: var(--t-bright);
  transition: color var(--_animspeed-fast) ease-in-out;
}

.footer-contact__socials svg {
  flex: none;
  width: 1.2em;
  height: 1.2em;
  transition: transform 0.3s;
}

.no-touch .footer-contact__group a:hover,
.no-touch .footer-contact__socials a:hover {
  color: var(--accent);
}

.no-touch .footer-contact__socials a:hover svg {
  transform: translate(2px, -2px);
}

/* Creator slot: one link. Hover is gated on .no-touch like the vendor's own. */
.footer-slot {
  display: flex;
  flex-direction: column;
  gap: 3rem;
  color: inherit;
}

.footer-slot:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}

.footer-slot__strip {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 1rem;
}

.footer-slot__strip img,
.footer-slot__empty {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
}

.footer-slot__strip img {
  object-fit: cover;
  object-position: 50% 30%;
  filter: grayscale(1) contrast(1.05);
  opacity: 0.78;
  transition: filter 0.5s, opacity 0.5s, transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.no-touch .footer-slot:hover .footer-slot__strip img,
.footer-slot:focus-visible .footer-slot__strip img {
  filter: none;
  opacity: 1;
}

.no-touch .footer-slot:hover .footer-slot__strip img:nth-child(odd),
.footer-slot:focus-visible .footer-slot__strip img:nth-child(odd) {
  transform: translateY(-0.8rem);
}

.footer-slot__empty {
  position: relative;
  display: grid;
  place-items: center;
  color: var(--accent);
  background-color: color-mix(in srgb, var(--accent) 6%, transparent);
  transition: background-color 0.35s, color 0.35s;
}

.footer-slot__empty i {
  position: absolute;
  width: 1.6rem;
  height: 1.4rem;
  border: 0 solid currentColor;
}

.footer-slot__empty i:nth-of-type(1) { top: 0.8rem; left: 0.8rem; border-width: 2px 0 0 2px; }
.footer-slot__empty i:nth-of-type(2) { top: 0.8rem; right: 0.8rem; border-width: 2px 2px 0 0; }
.footer-slot__empty i:nth-of-type(3) { bottom: 0.8rem; left: 0.8rem; border-width: 0 0 2px 2px; }
.footer-slot__empty i:nth-of-type(4) { bottom: 0.8rem; right: 0.8rem; border-width: 0 2px 2px 0; }

.footer-slot__empty b {
  font: normal 700 1.5rem/1.2 var(--_font-accent);
  letter-spacing: 0.04em;
  text-align: center;
}

/* On the coral fill the ink takes the on-accent token (§3). */
.no-touch .footer-slot:hover .footer-slot__empty,
.footer-slot:focus-visible .footer-slot__empty {
  color: var(--pt-t-accent-bright);
  background-color: var(--accent);
}

.footer-slot__copy {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2.4rem;
}

.footer-slot__copy .footer-data {
  margin-bottom: 1.4rem;
}

.footer-slot__heading {
  max-width: 14ch;
  margin: 0;
  font: normal 600 4.6rem/1.05 var(--_font-default);
  letter-spacing: -0.02em;
  color: var(--t-bright);
  text-wrap: balance;
}

.footer-slot__stop {
  color: var(--accent);
}

.footer-slot__cta {
  display: inline-flex;
  align-items: center;
  gap: 1rem;
  padding-bottom: 0.8rem;
  border-bottom: 2px solid var(--accent);
  font: normal 700 1.6rem/1 var(--_font-accent);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
  color: var(--t-bright);
}

.footer-slot__cta svg {
  flex: none;
  width: 1.15em;
  height: 1.15em;
  transition: transform 0.3s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.no-touch .footer-slot:hover .footer-slot__cta svg,
.footer-slot:focus-visible .footer-slot__cta svg {
  transform: translateX(5px);
}

/* Wordmark (design.md §2): public/img/folks-wordmark.svg is the only copy of the
   outlines, used as a mask twice. The box takes the SVG's viewBox ratio, so a
   100% 100% mask is exact. --x/--y are registered so the window and the frame
   glide; FooterWordmark sets them, plus --r, once it has parked the letters. */
@property --x {
  syntax: '<percentage>';
  inherits: true;
  initial-value: 0%;
}

@property --y {
  syntax: '<percentage>';
  inherits: true;
  initial-value: 0%;
}

.footer-wordmark {
  --wordmark: url("/img/folks-wordmark.svg");
  --r: 0px;
  --ease-frame: cubic-bezier(0.65, 0, 0.35, 1);
  position: relative;
  width: 100%;
  aspect-ratio: 1184.25 / 354.75;
  container-type: inline-size;
}

.footer-wordmark__base,
.footer-wordmark__spot {
  position: absolute;
  inset: 0;
}

.footer-wordmark__base {
  background-color: #242120;
  -webkit-mask: var(--wordmark) center / 100% 100% no-repeat;
  mask: var(--wordmark) center / 100% 100% no-repeat;
}

/* Without mask-composite the window cannot be cut, and the whole portrait
   layer would show: tonal letters only. */
.footer-wordmark__spot,
.footer-wordmark__frame {
  display: none;
}

@supports (mask-composite: intersect) or (-webkit-mask-composite: source-in) {
  .footer-wordmark[data-ready] .footer-wordmark__spot {
    display: block;
    overflow: hidden;
    -webkit-mask-image:
      var(--wordmark),
      linear-gradient(90deg, transparent calc(var(--x) - var(--r)), #000 calc(var(--x) - var(--r)), #000 calc(var(--x) + var(--r)), transparent calc(var(--x) + var(--r))),
      linear-gradient(180deg, transparent calc(var(--y) - var(--r)), #000 calc(var(--y) - var(--r)), #000 calc(var(--y) + var(--r)), transparent calc(var(--y) + var(--r)));
    -webkit-mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-composite: source-in, source-in;
    mask-image:
      var(--wordmark),
      linear-gradient(90deg, transparent calc(var(--x) - var(--r)), #000 calc(var(--x) - var(--r)), #000 calc(var(--x) + var(--r)), transparent calc(var(--x) + var(--r))),
      linear-gradient(180deg, transparent calc(var(--y) - var(--r)), #000 calc(var(--y) - var(--r)), #000 calc(var(--y) + var(--r)), transparent calc(var(--y) + var(--r)));
    mask-size: 100% 100%;
    mask-repeat: no-repeat;
    mask-composite: intersect, intersect;
  }

  .footer-wordmark[data-ready] .footer-wordmark__frame {
    display: block;
  }
}

.footer-wordmark__spot img {
  position: absolute;
  max-width: none;
  height: auto;
  opacity: 0;
}

.footer-wordmark__spot img[data-on] {
  opacity: 1;
}

.footer-wordmark[data-live] {
  transition: --x 0.9s var(--ease-frame), --y 0.9s var(--ease-frame);
}

.footer-wordmark[data-live] .footer-wordmark__spot img {
  transition: opacity 0.45s, left 0.9s var(--ease-frame), top 0.9s var(--ease-frame), width 0.9s var(--ease-frame);
}

.footer-wordmark__frame {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: calc(var(--r) * 2);
  height: calc(var(--r) * 2);
  transform: translate(-50%, -50%);
  pointer-events: none;
}

/* Corner size and caption type are the mock's 26×22 / 12px against a 1320px wordmark. */
.footer-wordmark__frame i {
  position: absolute;
  width: max(11%, 8px);
  height: max(9.3%, 7px);
  border: 0 solid var(--accent);
}

.footer-wordmark__frame i:nth-of-type(1) { top: 0; left: 0; border-width: 2px 0 0 2px; }
.footer-wordmark__frame i:nth-of-type(2) { top: 0; right: 0; border-width: 2px 2px 0 0; }
.footer-wordmark__frame i:nth-of-type(3) { bottom: 0; left: 0; border-width: 0 0 2px 2px; }
.footer-wordmark__frame i:nth-of-type(4) { bottom: 0; right: 0; border-width: 0 2px 2px 0; }

.footer-wordmark__rec {
  position: absolute;
  bottom: calc(100% + max(0.5rem, 0.61cqw));
  left: 0;
  display: inline-flex;
  align-items: center;
  gap: max(0.5rem, 0.61cqw);
  font: normal 500 max(1rem, 0.91cqw)/1 var(--_font-accent);
  letter-spacing: 0.06em;
  white-space: nowrap;
  color: var(--accent);
}

.footer-wordmark[data-flip] .footer-wordmark__rec {
  right: 0;
  left: auto;
}

.footer-wordmark__light {
  width: max(0.6rem, 0.61cqw);
  height: max(0.6rem, 0.61cqw);
  border-radius: 50%;
  background-color: var(--accent);
  animation: footer-wordmark-blink 1s steps(1) infinite;
}

@keyframes footer-wordmark-blink {
  50% { opacity: 0; }
}

/* The data row (legal-pages): copyright and the legal links centred on the
   page, under the centred wordmark; the Good One signature stays bottom right.
   Three columns with equal outer tracks, so the middle one is the page's true
   centre whatever the signature's width. Below 1200px it all stacks, centred. */
.footer-legal {
  display: grid;
  grid-template-columns: 1fr;
  justify-items: center;
  align-items: end;
  gap: 2.4rem;
  padding-inline: 2rem;
  text-align: center;
}
.footer-legal__centre {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.2rem;
}
.footer-legal .footer-data {
  margin: 0;
}
.footer-legal__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 2.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.footer-legal__links a {
  text-underline-offset: 0.3em;
}
.no-touch .footer-legal__links a:hover,
.footer-legal__links a:focus-visible {
  text-decoration: underline;
}
@media only screen and (min-width: 1200px) {
  .footer-legal {
    grid-template-columns: 1fr auto 1fr;
    padding-inline: 3rem;
  }
  .footer-legal__centre {
    grid-column: 2;
  }
  .footer-legal .footer-group {
    grid-column: 3;
    justify-self: end;
  }
}

/* Group signature: "Część grupy" + the Good One mark, as on sociallama.pl. */
.footer-group {
  display: inline-flex;
  align-items: center;
  gap: 1.4rem;
}

.footer-group__label {
  font: normal 600 1.2rem/1 var(--_font-accent);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--t-medium);
}

.footer-group__mark {
  display: block;
  width: 13.3rem;
  height: auto;
  opacity: 0.85;
  transition: opacity 0.3s;
}

.no-touch .footer-group:hover .footer-group__mark,
.footer-group:focus-visible .footer-group__mark {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .footer-wordmark[data-live],
  .footer-wordmark[data-live] .footer-wordmark__spot img,
  .footer-slot__strip img,
  .footer-slot__cta svg,
  .footer-contact__socials svg {
    transition: none;
  }

  .footer-wordmark__light {
    animation: none;
  }

  .no-touch .footer-slot:hover .footer-slot__strip img:nth-child(odd),
  .footer-slot:focus-visible .footer-slot__strip img:nth-child(odd) {
    transform: none;
  }
}

/* Room above the wordmark: the vendor's Controls block ("Back to Top") used to
   supply it, and the mock's rows sit 110 design units apart. */
.mxd-footer__fw-mark {
  padding-top: 8rem;
}

@media only screen and (min-width: 1200px) {
  .mxd-footer__fw-mark {
    padding-top: 11rem;
  }
}

/* Below 1200px the slot stacks under the columns, which already carry the
   vendor's large top padding; the slot's own copy of it would double the gap. */
@media only screen and (max-width: 1199px) {
  .mxd-footer__nav02:has(> .footer-slot) {
    padding-top: 6rem;
  }
}

/* Phones: the heading keeps its lines, the CTA drops under it, and the strip's
   empty tile scales its marks down with it. */
@media only screen and (max-width: 767px) {
  .footer-slot {
    gap: 2.4rem;
  }

  .footer-slot__strip {
    gap: 0.6rem;
  }

  .footer-slot__empty i {
    width: 1rem;
    height: 0.8rem;
  }

  .footer-slot__empty i:nth-of-type(1) { top: 0.5rem; left: 0.5rem; }
  .footer-slot__empty i:nth-of-type(2) { top: 0.5rem; right: 0.5rem; }
  .footer-slot__empty i:nth-of-type(3) { bottom: 0.5rem; left: 0.5rem; }
  .footer-slot__empty i:nth-of-type(4) { bottom: 0.5rem; right: 0.5rem; }

  .footer-slot__empty b {
    font-size: 1.2rem;
  }

  .footer-slot__copy {
    flex-direction: column;
    align-items: flex-start;
    gap: 2.4rem;
  }

  .footer-slot__heading {
    max-width: none;
    font-size: 3.4rem;
  }
}

/* --- Home brand marquee ----------------------------------------------------
   Two variants off one component (app/(site)/blocks/BrandMarquee.tsx): `quiet`
   is a compact separator, `roster` two rows with the air of a section. Both sit
   between the showreel and the manifest. Every rule below is scoped to .brand-marquee, and none
   of it reaches the vendor's own marquee classes.

   The section is the marks and nothing else — no label, headline, count,
   full-list disclosure or pause control (Przemek, 2026-09-17). What separates
   the variants is therefore geometry alone: quiet is one row, close-cropped,
   with a rule handing the page to the manifest below; roster is two rows
   running against each other at a larger scale, with the air of a section.

   Geometry is stepped per breakpoint rather than fluid. Cells are sized by
   their marks, so the row's length is not something CSS can express — the
   component measures a group and sets --brand-duration from it at 30 px/s. A
   clamp() would only make that measurement churn on every resize. */
.brand-marquee {
  --brand-gap: 24px;
  --brand-height: 52px;
  /* The widest a single mark may run. Nothing else depends on it: the row's
     length, and therefore the loop's duration, is measured in the component. */
  --brand-cap: 156px;
  color: var(--t-bright);
}

/* Full-bleed on purpose: the marks run off both edges, which is what says the
   row continues. */
.brand-marquee__viewport {
  width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
}
.brand-marquee__viewport:focus-visible {
  /* !important: main.css `button:focus { outline: none !important }` — the same
     override the campaign and creator-strip focus rings need. */
  outline: 2px solid var(--accent) !important;
  outline-offset: -4px;
}
.brand-marquee__track {
  display: flex;
  width: max-content;
  /* --brand-duration is written here by the component, from the measured group
     width. The fallback only has to be a valid time so the shorthand below
     parses before the first measurement lands. */
  --brand-duration: 120s;
}
.brand-marquee__group {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: var(--brand-gap);
  /* The leading gap belongs to the group, so two groups tile at exactly 50%
     and the seam has the same spacing as every other join. */
  padding: 0 0 0 var(--brand-gap);
  margin: 0;
  list-style: none;
}
/* The repeat exists only for the loop; it is dead weight in the static list. */
.brand-marquee__group[aria-hidden="true"] { display: none; }
/* Sized by its mark, not to a fixed width. Fixed cells centre each mark in its
   own box, so the space a viewer sees between two brands is the gap plus
   whatever slack their two marks leave — Burger King's narrow emblem left twice
   the air that Kohersen's full-width word mark did. With every canvas trimmed to
   its ink, an auto-width cell makes the flex gap the actual gap between marks,
   and the rhythm is even by construction. */
.brand-marquee__cell {
  flex: 0 0 auto;
  height: var(--brand-height);
  display: flex;
  align-items: center;
}
.brand-marquee__mark {
  /* Natural width at a per-brand height. --mark-scale is that height as a
     fraction of the row's, chosen so every mark covers about the same area
     (lib/brand-marquee/brands.ts) — one shared height let ASUS and Volvo run to
     four times Burger King's width. */
  height: calc(var(--brand-height) * var(--mark-scale, 1));
  width: auto;
  /* A backstop the scaled set never reaches; it is here for a mark added
     without a scale. */
  max-width: var(--brand-cap);
  /* Suunto and Laurastar carry an ornament above the word; this lifts the word
     back onto its neighbours' line. Percent of the mark's own height. */
  translate: 0 calc(var(--mark-nudge, 0) * 1%);
  object-fit: contain;
  /* Flatten any artwork to the section's own white and keep its alpha: black
     first so a coloured mark cannot invert into a pastel, then invert. Marks
     with an opaque plate would come out as a white slab — none of the twenty-four
     has one (public/img/brands/clients/SOURCES.md). */
  filter: brightness(0) invert(1);
}
/* A brand with no authentic mark — none today, all 24 have one. Set in the page's own display face
   at the weight that reads as a logotype beside real ones, never as a caption. */
.brand-marquee__wordmark {
  /* Sized off the row rather than in rem, so it tracks every breakpoint's cell
     and lands at the ink height the real marks occupy instead of reading as a
     caption between them. */
  font: 650 calc(var(--brand-height) * .38) / 1.05 var(--_font-default);
  letter-spacing: -.035em;
  text-align: center;
  /* One line, even when the name is wider than its cell. "Unilin Panels" wraps
     on a phone otherwise and sits two lines deep between single-line marks. The
     overflow is a few pixels each side into a transparent gap, which reads as a
     wide word mark; a second line reads as a mistake. */
  white-space: nowrap;
}

/* Quiet confidence — a separator, not a section: one row and a rule that hands
   the page over to the manifest below it. */
.brand-marquee--quiet { padding: 4.4rem 0 0; }
.brand-marquee--quiet .brand-marquee__rows {
  padding-bottom: 4.4rem;
  margin: 0 3rem;
  border-bottom: 1px solid var(--st-medium);
}

/* The roster — two rows against each other, at a larger scale and with room
   around them. It sits between the showreel band and the manifest, and the
   manifest brings 13.4–17.4rem of its own top padding: the bottom here stays
   small on purpose, or the two stack into a dead zone twice the height of the
   air above the rows. */
.brand-marquee--roster { padding: 8rem 0 1.6rem; }
.brand-marquee--roster .brand-marquee__rows {
  display: grid;
  /* minmax(0, 1fr), never the default `auto`: a grid column is sized by its
     content's max-content width, and each row's track is `width: max-content`
     and ten thousand pixels wide. With `auto` the column takes that width, the
     viewport's `width: 100%` resolves against it, and the whole page gains a
     horizontal scrollbar three thousand pixels long. */
  grid-template-columns: minmax(0, 1fr);
  gap: 1.6rem;
}

@media only screen and (min-width: 768px) {
  .brand-marquee {
    --brand-gap: 34px;
    --brand-height: 62px;
    --brand-cap: 208px;
  }
  .brand-marquee--quiet { padding-top: 5.4rem; }
  .brand-marquee--quiet .brand-marquee__rows { padding-bottom: 5.4rem; margin: 0 6rem; }
  .brand-marquee--roster { padding: 10rem 0 2rem; }
  .brand-marquee--roster .brand-marquee__rows { gap: 2.4rem; }
}

@media only screen and (min-width: 1200px) {
  .brand-marquee {
    --brand-gap: 40px;
    --brand-height: 68px;
    --brand-cap: 234px;
  }
  .brand-marquee--roster {
    --brand-gap: 46px;
    --brand-height: 76px;
    --brand-cap: 264px;
  }
  .brand-marquee--quiet { padding-top: 6.4rem; }
  .brand-marquee--quiet .brand-marquee__rows { padding-bottom: 6.4rem; }
  .brand-marquee--roster { padding: 12rem 0 2.4rem; }
  .brand-marquee--roster .brand-marquee__rows { gap: 3.2rem; }
}

@media only screen and (min-width: 1600px) {
  .brand-marquee--roster {
    --brand-gap: 52px;
    --brand-height: 84px;
    --brand-cap: 300px;
  }
}

/* Everything above renders a plain, scrollable list. These are the only rules
   that make it move, and they need both a client that has mounted and a visitor
   who has not asked for less motion.

   The rows do not react to the pointer at all: no pause on hover (Przemek,
   2026-09-17), and the pause button went earlier. Keyboard focus still holds a
   row — that is not a hover effect, it is how someone tabbing through reaches a
   mark without it sliding away — and prefers-reduced-motion still stops
   everything. */
@media (prefers-reduced-motion: no-preference) {
  .brand-marquee[data-ready="true"] .brand-marquee__viewport { overflow-x: clip; }
  .brand-marquee[data-ready="true"] .brand-marquee__group[aria-hidden="true"] { display: flex; }
  .brand-marquee[data-ready="true"] .brand-marquee__track {
    /* The negative delay starts the loop part-way in, so the very first painted
       frame already has marks running off both edges instead of a tidy row
       aligned to a left margin — which is the thing that says the strip
       continues. The static list keeps its leading gap, where a margin is right. */
    animation: brand-marquee-loop var(--brand-duration) linear infinite
      calc(var(--brand-duration) / -9);
  }
  /* Every rule that modifies that animation has to out-specify it, because the
     shorthand above resets direction and play-state to their initial values on
     each element it matches. Repeating the [data-ready] ancestor is what buys
     the extra weight — dropping it silently gives back both the reverse row and
     the hover pause. */
  .brand-marquee[data-ready="true"] .brand-marquee__track[data-direction="reverse"] {
    animation-direction: reverse;
  }
  .brand-marquee[data-ready="true"] .brand-marquee__viewport:focus-visible .brand-marquee__track,
  .brand-marquee[data-ready="true"] .brand-marquee__viewport:has(:focus-visible) .brand-marquee__track {
    animation-play-state: paused;
  }
}
@keyframes brand-marquee-loop { to { transform: translateX(-50%); } }

/* --- Blog hub (blog-hub-lead) ---------------------------------------------
   `/blog/` only: a lead for the newest post, then tightened rows with a
   visible thumbnail. The approved mock is the visual contract (variant B,
   openspec/changes/blog-hub-lead). The rows keep `.mxd-blog-list__item` and
   its dividers, so the vendor hover-dim (≥1200px, hover, motion allowed)
   and hairlines still apply; everything here is under `blog-hub-`, so the
   home Blog Preview, which renders `PostListItem`, is untouched. */

/* Title block: heading, its count, and the description bottom-right. The
   count is a sibling of the heading (see blog/page.tsx), placed like a
   superscript by the grid. */
.blog-hub-title .mxd-grid-item {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: end;
}
.blog-hub-title__count {
  align-self: start;
  margin: 0.4rem 0 0 1.2rem;
  font: normal 600 1.4rem/1 var(--_font-accent);
  color: var(--accent);
}
.blog-hub-title__description {
  max-width: 40ch;
  margin: 0 0 1.2rem 6rem;
  font-size: 1.8rem;
  color: var(--t-medium);
}
@media only screen and (max-width: 767px) {
  .blog-hub-title .mxd-grid-item {
    grid-template-columns: auto 1fr;
  }
  .blog-hub-title__description {
    grid-column: 1 / -1;
    margin: 2rem 0 0;
  }
}

/* Shared mono meta line: the vendor meta face, with · between items. */
.blog-hub-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  margin: 0;
  font: normal 600 1.2rem/1.6 var(--_font-accent);
  letter-spacing: 0.05rem;
  text-transform: uppercase;
  color: var(--t-medium);
}
.blog-hub-meta b {
  font-weight: 600;
  color: var(--t-bright);
}
.blog-hub-meta > :not(:first-child)::before {
  content: "·";
  content: "·" / "";
  margin: 0 0.8rem;
}

/* Clamped text keeps its full content in the DOM; each rule below sets N. */
.blog-hub-lead__excerpt,
.blog-hub-row__title,
.blog-hub-row__excerpt {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* The lead: 16:10 cover beside the text; one link. Two columns only when
   there is a cover to put in one. */
.blog-hub-lead {
  display: grid;
  gap: clamp(2.8rem, 4vw, 7rem);
  align-items: center;
  margin-bottom: clamp(5.6rem, 7vw, 10rem);
  color: var(--t-medium);
}
@media only screen and (min-width: 768px) {
  .blog-hub-lead:has(> .blog-hub-lead__cover) {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  }
}
.blog-hub-lead__cover {
  overflow: hidden;
  border-radius: 0.6rem;
  background-color: var(--base-tint);
}
.blog-hub-lead__cover img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}
.blog-hub-lead__flag {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 1.4rem;
  margin-bottom: 1.8rem;
}
.blog-hub-lead__flag > b {
  color: var(--accent);
}
.blog-hub-lead__title {
  margin: 0;
  font: normal 600 clamp(2.6rem, 2.7vw, 4rem)/1.14 var(--_font-default);
  letter-spacing: -0.035em;
  text-wrap: balance;
  color: var(--t-bright);
}
.blog-hub-lead__excerpt {
  -webkit-line-clamp: 4;
  max-width: 54ch;
  margin: 2.2rem 0 0;
  font-size: 1.8rem;
}
/* No hover colour of its own: the card's hover opens the label's Viewfinder
   (ViewfinderHost), and a Viewfinder label keeps its text colour. */
.blog-hub-lead__cta {
  margin-top: 2.8rem;
}

/* "Wcześniejsze wpisy · N", its hairline running on to the right edge. It is
   the first row's top line: rows render only their bottom divider. */
.blog-hub-divider {
  gap: 1.4rem;
  align-items: center;
  margin-bottom: 0.6rem;
}
.blog-hub-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background-color: var(--st-muted);
}

/* Rows: meta and title | excerpt | 176px thumb, placed by area per width. */
.mxd-blog-list__item.blog-hub-row {
  padding: 3.4rem 0;
}
.blog-hub-row__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr) 176px;
  grid-template-areas:
    "meta  excerpt thumb"
    "title excerpt thumb";
  column-gap: 4.8rem;
  align-items: center;
}
.blog-hub-row .blog-hub-meta {
  grid-area: meta;
  align-self: end;
  margin-bottom: 1.2rem;
}
.blog-hub-row__title {
  grid-area: title;
  align-self: start;
  -webkit-line-clamp: 4;
  margin: 0;
  font: normal 700 clamp(2.2rem, 2.2vw, 3rem)/1.2 var(--_font-default);
  letter-spacing: -0.03em;
  text-wrap: balance;
  color: var(--t-bright);
  transition: color var(--_animspeed-medium);
}
.no-touch .blog-hub-row:hover .blog-hub-row__title {
  color: var(--accent);
}
.blog-hub-row__excerpt {
  grid-area: excerpt;
  -webkit-line-clamp: 3;
  max-width: 52ch;
  margin: 0;
  font-size: 1.6rem;
  color: var(--t-medium);
}
.blog-hub-row__thumb {
  grid-area: thumb;
  display: block;
  width: 176px;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: 0.4rem;
  background-color: var(--base-tint);
}

@media only screen and (max-width: 1199px) {
  .blog-hub-row__inner {
    grid-template-columns: minmax(0, 1fr) 150px;
    grid-template-areas:
      "meta    thumb"
      "title   thumb"
      "excerpt excerpt";
    column-gap: 2.8rem;
  }
  .blog-hub-row__excerpt {
    margin-top: 1.4rem;
  }
  .blog-hub-row__thumb {
    width: 150px;
  }
}

/* The meta line does not fit beside a thumb at this width, and wrapped it
   starts its second line with a "·". It takes the full row instead. */
@media only screen and (max-width: 767px) {
  .mxd-blog-list__item.blog-hub-row {
    padding: 2.4rem 0;
  }
  .blog-hub-row__inner {
    grid-template-columns: minmax(0, 1fr) 96px;
    grid-template-areas:
      "meta    meta"
      "title   thumb"
      "excerpt excerpt";
    column-gap: 1.6rem;
    align-items: start;
  }
  .blog-hub-row__thumb {
    width: 96px;
    aspect-ratio: 1;
  }
  .blog-hub-row__excerpt {
    -webkit-line-clamp: 2;
    margin-top: 1.2rem;
    font-size: 1.5rem;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .blog-hub-lead__cover img {
    transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1);
  }
  .no-touch .blog-hub-lead:hover .blog-hub-lead__cover img {
    transform: scale(1.03);
  }
}

/* =============================================================================
   Jak działamy — five-slide process (refresh-how-we-work, ProcessStack.tsx)
   Own markup, no vendor stack hooks. Every slide's copy sits on the homepage's
   torn paper strip over its full-bleed artwork (process-paper); the strip's
   shared rules are joined above. Flow by default — each picture pinned
   full-screen while its paper scrolls over it, height from content — which is
   also the no-JS and narrow/short layout. Wide and tall viewports stack the
   slides with native sticky once ProcessSlides has measured them (`data-fit`),
   the paper on the art's quiet left third. The breakpoints are in em so they
   follow the reader's font-size preference: large text falls back to flow
   instead of being squeezed into a pinned slide.
   ============================================================================= */
.folks-process {
  --p-bg: #e7e3de;
}
.folks-process__slides {
  margin: 0;
  padding: 0;
  list-style: none;
}
/* `clip`, not `hidden`: a rotated paper's corners must not widen a narrow page,
   and a clip is no scroll container, so the art still sticks. */
.folks-process__slide {
  position: relative;
  overflow-x: clip;
  background: var(--p-bg);
}
.folks-process__slide--coral { --p-bg: #fb654a; }
.folks-process__slide--dark { --p-bg: #1d1d1d; }
/* Pinned for its slide's length; svh, so a phone's toolbar never resizes it. */
.folks-process__art {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
}
.folks-process__art img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--folks-process-focus, 80%) center;
}
/* The paper arrives over the art's lower third. The room after it is this
   wrapper's own padding, never the slide's: a sticky element stops at its
   container's content box, so slide padding would open a band of ground
   between one slide's art and the next. Its side margins, like the paper's side
   padding, stop growing with the text size at a share of the viewport: on a
   phone at twice the text they would otherwise take most of the width. */
.folks-process__copy {
  position: relative;
  width: min(100% - min(2.8rem, 8vw), 56rem);
  margin: -36svh auto 0;
  padding-bottom: 24svh;
}
/* The tag carries copy (slide 05's is its heading), so unlike the homepage's it
   wraps rather than run off a narrow screen at a large text size. */
.folks-process .folks-strip__tag {
  max-width: calc(100% - 3.6rem);
  margin: 0;
  left: 1.8rem;
  white-space: normal;
}
/* The paper is clipped to its tear, so anything wider than it would be cut off,
   not scrolled: headings and counters are capped by the paper's width (`cqi`),
   and a word that still does not fit breaks instead. */
.folks-process .folks-strip__paper {
  container-type: inline-size;
  padding: 4.4rem min(2.4rem, 6vw) 3.6rem;
  color: var(--folks-ink);
  overflow-wrap: break-word;
}
.folks-process .folks-process__title {
  margin: 0 0 2.4rem;
  font: 800 min(clamp(3.4rem, 2.6rem + 2vw, 6rem), 15cqi)/1.04 var(--_font-default);
  letter-spacing: -.05em;
  text-wrap: balance;
  color: inherit;
}
.folks-process .folks-process__text {
  margin: 0;
  font: 500 1.6rem/1.7 var(--_font-default);
  color: inherit;
}
.folks-process .folks-process__keywords {
  margin: 2.8rem 0 0;
  padding-top: 1.4rem;
  border-top: 1px solid currentColor;
  font: 700 1.1rem/1.8 var(--_font-accent);
  letter-spacing: .06em;
  color: inherit;
}
.folks-process .folks-process__period {
  margin: 0 0 1.6rem;
  font: 500 1.3rem/1.5 var(--_font-accent);
  color: inherit;
}

/* Results counters: one subgrid column sized by an invisible final value
   (ProcessStats.tsx), so the labels hold still while the digits count. */
.folks-process__stats {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  column-gap: 1.6rem;
  row-gap: .6rem;
  margin: 0 0 2.8rem;
  padding: 0;
  list-style: none;
}
.folks-process__stat {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: baseline;
}
.folks-process__number {
  display: grid;
  font: 800 min(clamp(5rem, 3.6rem + 3.6vw, 8.8rem), 26cqi)/1 var(--_font-default);
  letter-spacing: -.06em;
  font-variant-numeric: tabular-nums;
}
.folks-process__sizer,
.folks-process__count {
  grid-area: 1 / 1;
}
.folks-process__sizer { visibility: hidden; }
.folks-process__stat-label {
  font: 600 clamp(1.6rem, 1.2rem + .5vw, 2.1rem)/1.2 var(--_font-default);
  letter-spacing: -.02em;
}
/* A narrow paper at a large text size: each label under its number. The query is
   in rem, so it follows the text size — no phone paper is this narrow at 1×. */
@container (max-width: 24rem) {
  .folks-process__stats { grid-template-columns: minmax(0, 1fr); }
  .folks-process__stat { row-gap: .2rem; }
}

@media (min-width: 37.5em) {
  .folks-process .folks-strip__tag { left: 2.4rem; }
  .folks-process .folks-strip__paper { padding: 5.2rem 4rem 4.4rem; }
  .folks-process .folks-process__text { font-size: 1.7rem; }
}

@media (min-width: 70em) and (min-height: 43.75em) {
  .folks-process__slide {
    display: flex;
    align-items: center;
    min-height: 100svh;
    overflow: clip;
  }
  .folks-process__slides[data-fit] .folks-process__slide {
    position: sticky;
    top: var(--folks-process-top, 0px);
  }
  .folks-process__art {
    position: absolute;
    inset: 0;
    height: auto;
  }
  .folks-process__art img { object-position: 70% center; }
  .folks-process__copy {
    width: min(56rem, 36vw);
    margin: 0 0 0 clamp(5rem, 6.5vw, 13rem);
    padding: 11rem 0 8rem;
  }
  .folks-process .folks-strip__paper { padding: 5.2rem 3.6rem 4.4rem; }
  /* Large screens keep the approved previews' proportions, where type scaled with the slide. */
  .folks-process .folks-process__title { font-size: clamp(4.4rem, 1.6rem + 2.5vw, 7.2rem); }
  .folks-process .folks-process__text { font-size: clamp(1.6rem, .8rem + .6vw, 2rem); }
  .folks-process .folks-process__keywords { font-size: clamp(1.1rem, .65vw, 1.4rem); }
  .folks-process .folks-process__period { font-size: clamp(1.3rem, .75vw, 1.6rem); }
  /* The results paragraph is the longest copy on the tallest slide. */
  .folks-process__slide--dark .folks-process__text { font-size: clamp(1.5rem, .7rem + .55vw, 1.8rem); }
  .folks-process__number { font-size: clamp(5.2rem, min(4.8vw, 9svh), 8.8rem); }
}

/* --- 13. Group wheel (/o-nas) ----------------------------------------------
   The Good One group wheel (openspec group-wheel, GroupWheel.tsx, mock 02
   "Ink"): six agencies orbiting a Good One hub beside the block's copy.

   Ported from sociallama-v2's own /o-nas wheel, with its two load-bearing
   choices deliberately dropped.

   1. NOT a registered `--spin`. The source animates an `@property <angle>` and
      reads it inside each element's own `transform`. That recalculates style
      for seven elements every frame, it needs `@property`, and its own CSS
      documents a production collapse on Safari < 16.4 that forced a `, 0deg`
      fallback on every read. Here the plain form does the same job: one
      rotation on a common ancestor, one reverse rotation on the child that has
      to stay upright. Both are transform-only, so they run on the compositor,
      and there is nothing left to downlevel.

   2. NOT an IntersectionObserver. A compositor-only rotation off screen costs
      next to nothing, and doing without it keeps the block a server component
      with no client JavaScript at all.

   The ring, its dots and all six seats hang off the ONE rotating node, so "each
   dot stays on the line from the hub to its agency" is structural rather than
   two animations agreeing. Nothing here takes a vendor animation class, so the
   vendor's reveal and scroll scripts have nothing to fight with.

   Every logo is a `mask` over a palette token rather than an <img>: the colour
   stays a token, and one file serves any colour. Five agencies and the hub take
   the paper token; Folks alone takes the accent — on Folks' own site the wheel
   says "you are here". A mask image that fails to load counts as transparent
   black, so a broken path makes a logo vanish silently — e2e/group-wheel.spec.ts
   asserts all seven files answer 200. */

.folks-group-wheel {
  /* Backstop only. The orbit is sized from its own column (below), so the swing
     already fits; this stops a sub-pixel overhang becoming a horizontal
     scrollbar on the document. */
  overflow: clip;
  padding-block: clamp(6rem, 8vw, 12rem);
}

.folks-group-wheel__band {
  display: flex;
  flex-direction: column;
  gap: clamp(3.2rem, 5vw, 6rem);
}

/* --- the wheel column --- */

.folks-group-wheel__wheel {
  /* A size container, so `--orbit` tracks THIS column rather than the viewport.
     The source needs `calc(0.44 * min(1240px, 100vw - 2 * safe))` to guess at
     the same number; a container query just asks. */
  container-type: inline-size;
}

.folks-group-wheel__orbit {
  /* Every radius and size below is a fraction of the square orbit box, so the
     whole system scales with this one value. The logos swing a footprint of
     about 1.14x the orbit (each reaches logo-r + half its own block from the
     centre), so 84% of the column keeps the swing inside it at every width. */
  --orbit: min(84cqw, 50rem);
  --period: 54s;
  /* The ring sits well inside the logos — the source PNG's ~0.25 proportion — so
     the dots clear each logo's inboard label. */
  --ring-r: calc(var(--orbit) * 0.25);
  --logo-r: calc(var(--orbit) * 0.42);
  --dot-size: calc(var(--orbit) * 0.026);

  position: relative;
  width: var(--orbit);
  height: var(--orbit);
  margin-inline: auto;
}

@keyframes folks-group-wheel-turn {
  to {
    transform: rotate(360deg);
  }
}

.folks-group-wheel__spin {
  position: absolute;
  inset: 0;
  animation: folks-group-wheel-turn var(--period) linear infinite;
}

/* --- the dotted ring --- */

.folks-group-wheel__ring {
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(var(--ring-r) * 2);
  height: calc(var(--ring-r) * 2);
  margin: calc(var(--ring-r) * -1);
}

/* The circle is drawn at r=50, the viewBox edge, so it lands exactly under the
   dots (both at --ring-r); `overflow: visible` keeps the round dash caps whole
   instead of clipping them at that edge. */
.folks-group-wheel__ring svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* `non-scaling-stroke`, so the ring's ink is in SCREEN pixels rather than in
   viewBox units the browser then multiplies by the ring's box.

   That box follows `--orbit`, which is only held at 50rem while the column is
   wide enough for it. Written as plain units the stroke kept its designed 1.25px
   down to a ~595px viewport and then thinned with the column — 0.69px at 390,
   0.63px at 360. The ring is the only part of the wheel that is BOTH scaled and
   drawn at 38% alpha (the coral markers shrink too, but stay full-opacity), so
   it alone fell below the threshold: each dot lost 42% of its contrast against
   the ground, and a phone showed six dots and no ring. Reported from an iPhone,
   2026-09-20.

   The dash pair is retuned to the same screen space, and to exactly what the
   desktop already rendered (0.5 x 2.5 = 1.25px stroke, 2.6 x 2.5 = 6.5px gap),
   so wide screens are unchanged to the pixel. A narrower ring now keeps the same
   dot SIZE and SPACING and simply carries fewer of them, which is what "the same
   ring, smaller" should look like. Guarded by e2e/group-wheel.spec.ts. */
.folks-group-wheel__ring circle {
  fill: none;
  stroke: color-mix(in srgb, var(--folks-paper) 38%, transparent);
  vector-effect: non-scaling-stroke;
  stroke-width: 1.25;
  stroke-linecap: round;
  stroke-dasharray: 0.25 6.5;
}

.folks-group-wheel__dot {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--dot-size);
  height: var(--dot-size);
  border-radius: 50%;
  background: var(--accent);
  transform: translate(-50%, -50%) rotate(var(--base)) translateY(calc(-1 * var(--ring-r)));
}

/* --- the six seats --- */

.folks-group-wheel__seats {
  /* A plain list, not the vendor's: no bullets, no inherited spacing. */
  margin: 0;
  padding: 0;
  list-style: none;
}

.folks-group-wheel__seat {
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(var(--orbit) * 0.3);
  /* Swing out along the spoke, then undo the base angle so the block is level
     with the page again — the parent's rotation is what is left, and
     `.folks-group-wheel__upright` takes that off. The trailing scale shrinks a
     heavier block about its OWN centre, so its position is unchanged: the two
     longest labels would otherwise reach the spoke dot at three and nine
     o'clock. */
  transform:
    translate(-50%, -50%)
    rotate(var(--base))
    translateY(calc(-1 * var(--logo-r)))
    rotate(calc(-1 * var(--base)))
    scale(var(--seat-scale, 1));
}

.folks-group-wheel__upright {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--orbit) * 0.014);
  /* The exact counter-turn of `.folks-group-wheel__spin`: same keyframes, same
     duration, same start, played backwards. The two are declared in one style
     pass and share a timeline, so they cannot come apart. */
  animation: folks-group-wheel-turn var(--period) linear infinite reverse;
}

.folks-group-wheel__logo {
  display: block;
  /* Wide wordmarks are width-limited, the tall Social Lama mark height-limited —
     the source's rule, expressed once. */
  width: min(calc(var(--orbit) * 0.26), calc(var(--orbit) * 0.09 * var(--ar)));
  aspect-ratio: var(--ar);
  background: var(--folks-paper);
  -webkit-mask: var(--mask) center / contain no-repeat;
  mask: var(--mask) center / contain no-repeat;
}

.folks-group-wheel__seat--self .folks-group-wheel__logo {
  background: var(--accent);
}

.folks-group-wheel__dash {
  width: calc(var(--orbit) * 0.05);
  height: 2px;
  background: var(--accent);
}

.folks-group-wheel__kind {
  font-family: var(--_font-accent);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  /* Never below 1rem — the root is 62.5%, so that is the spec's 10 CSS px floor. */
  font-size: clamp(1rem, 2cqw, 1.2rem);
  line-height: 1.1;
  text-align: center;
  white-space: nowrap;
  color: color-mix(in srgb, var(--folks-paper) 78%, transparent);
}

.folks-group-wheel__seat--self .folks-group-wheel__kind {
  color: var(--folks-paper);
}

/* --- the hub, which never turns --- */

.folks-group-wheel__hub {
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(var(--orbit) * 0.3);
  aspect-ratio: var(--ar);
  transform: translate(-50%, -50%);
  background: var(--folks-paper);
  -webkit-mask: var(--mask) center / contain no-repeat;
  mask: var(--mask) center / contain no-repeat;
}

/* --- motion ---------------------------------------------------------------
   The wheel does not react to the pointer at all: no pause on hover (Przemek,
   2026-09-20), which is the call already made for the brand marquee's rows
   (§"brand roster", 2026-09-17). Nothing here is focusable either — the seats
   are `role="img"` spans, not links — so there is no keyboard case to keep, the
   way that strip keeps one for a visitor tabbing to a mark.

   That leaves `prefers-reduced-motion` as the only thing that stops it. A
   visible pause control is deliberately not here: it would need a client
   component, and this block has no client JavaScript at all. If an audit asks
   for one, that is the follow-up (design §6). */

/* With the animations gone the seats rest at their base angles — the source's
   static arrangement, upright, with Good One PR at twelve o'clock. The diagram
   is complete at rest; nothing is only legible while it moves. */
@media (prefers-reduced-motion: reduce) {
  .folks-group-wheel__spin,
  .folks-group-wheel__upright {
    animation: none;
  }
}

/* --- the copy column --- */

.folks-group-wheel__copy {
  display: flex;
  flex-direction: column;
  gap: clamp(1.6rem, 1.6vw, 2.4rem);
  max-width: 46ch;
}

.folks-group-wheel__eyebrow {
  margin: 0;
  font-family: var(--_font-accent);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 1.2rem;
  color: var(--folks-paper);
}

.folks-group-wheel__heading {
  margin: 0;
  font-size: clamp(3.2rem, 1.8rem + 2vw, 5.2rem);
  line-height: 1.08;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

.folks-group-wheel__body {
  margin: 0;
  font-size: clamp(1.5rem, 0.9rem + 0.4vw, 1.7rem);
  line-height: 1.62;
  color: color-mix(in srgb, var(--folks-paper) 80%, transparent);
}

/* --- narrow screens: the orbit without labels, plus a legend ---------------
   Measured at 390px: the one-colour orbit itself fits with room to spare — the
   mono logos are narrower than the source's full-colour ones — but the labels
   fall to 8px, and raising them to a readable size makes "INFLUENCER MARKETING"
   wider than its seat at 320px. So the per-logo labels and their dashes come off
   the screen and a two-column legend follows the wheel instead.

   The labels are hidden VISUALLY, not with `display: none`: the orbit's list
   stays the one accessible list at every width, so each specialisation is still
   announced exactly once. The legend is `aria-hidden` in the markup — it is the
   same six pairs drawn a second time for sighted readers, not a second list. */

.folks-group-wheel__legend {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.6rem 2.4rem;
  margin: clamp(3.2rem, 6vw, 4.8rem) 0 0;
  padding: 0;
  list-style: none;
}

.folks-group-wheel__legend-item {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  border-top: 1px solid color-mix(in srgb, var(--folks-paper) 18%, transparent);
  padding-top: 1.2rem;
}

.folks-group-wheel__legend-name {
  font-size: 1.5rem;
  line-height: 1.2;
  color: var(--folks-paper);
}

.folks-group-wheel__legend-kind {
  font-family: var(--_font-accent);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 1rem;
  line-height: 1.3;
  color: color-mix(in srgb, var(--folks-paper) 70%, transparent);
}

@media only screen and (max-width: 1199px) {
  .folks-group-wheel__dash {
    display: none;
  }
  /* The vendor's `.visually-hidden` recipe (plugins.css), applied by width
     rather than by class — a server component cannot swap a class on a media
     query, and `display: none` would take the specialisation out of the
     accessibility tree along with it. */
  .folks-group-wheel__kind {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

/* Two columns from the vendor's desktop breakpoint up: the wheel takes the
   larger share, because its swing is wider than the orbit itself. Below it the
   band is stacked and the wheel comes first, as in the mock. */
@media only screen and (min-width: 1200px) {
  .folks-group-wheel__band {
    display: grid;
    grid-template-columns: 1.25fr 0.75fr;
    align-items: center;
    gap: clamp(4rem, 5vw, 8rem);
  }
  .folks-group-wheel__legend {
    display: none;
  }
}

/* --- 14. About: pillars and brief (/o-nas), and the channel system ----------
   The approved option 1 "Brief & papier" (openspec complete-about-editorial,
   `AboutPillars.tsx` + `AboutEditorial.tsx`): three pillars closing the hero
   and the business brief on a paper plate. The connected-channel section that
   followed them moved to `/jak-dzialamy/` as its own block (openspec
   move-system-to-how-we-work, `SystemFlow.tsx`, 14b below) and shares this
   section's type and tokens through `.folks-system-section`; the funnel is
   gone. Ported from the review mock
   (`public/proposals/o-nas/mock.css`, concept `editorial`), which is what
   Przemek approved and what `docs/mockups/o-nas/checks.json` measured.

   Three deliberate carry-overs from that mock, rather than the site's usual
   habits:

   1. Its OWN breakpoints, 1100px and 700px, not the vendor's 768/1200/1600.
      The composition was approved at these, and the mock's captures at 1440 and
      390 are the record. Moving them would change the approved rendering at
      widths nobody has looked at.
   2. Its own torn edge, not `.folks-strip` (paper-strip.ts). The strip is one
      rotated sheet clipped as a whole; this plate is square and tears only
      along its top and bottom edges — a different drawing, not a variant.
   3. `--folks-about-coral-ink` for the accent ON the paper plate. Coral #FF6251
      is 2.5:1 on paper and fails; the mock's darker #b52a20 is 5.5:1 and passes.
      The dark ground keeps the ordinary `--accent` (6.5:1, §3).

   The `[ … ]` brackets round each section label are drawn in CSS because they
   are composition, not copy: the field stores "Dlaczego my?" and an editor
   cannot lose a bracket or add a third. They are not hidden from assistive
   technology by living there — generated `content` is part of the accessible
   name (CSS-AAM) and is announced — which is why the label still reads as a
   sentence either way. */

.folks-about,
.folks-about-pillars,
.folks-system-section {
  --folks-about-muted: color-mix(in srgb, var(--folks-paper) 75%, transparent);
  --folks-about-rule: color-mix(in srgb, var(--folks-paper) 19%, transparent);
  color: var(--folks-paper);
}

/* Ink-side tokens: used only where a section paints on paper — the brief's
   plate and the system diagram — which the pillars never do. The other rules on the plate — the stamp's border and the
   goals divider — are written inline rather than tokenised, because the mock
   gives each one its own weight (40%, 33%, 27%) and collapsing them to one
   token would flatten a deliberate hierarchy. */
.folks-about,
.folks-system-section {
  --folks-about-coral-ink: #b52a20;
}

/* main.css colours and sizes bare `h2`, `h3` and `p` at (0,0,1), so without a
   rule here a heading or paragraph on the paper plate keeps the dark ground's
   near-white and vanishes. `color: inherit` is what lets one `color` on the
   plate turn all of its copy to ink.

   Two things keep that from fighting this section's own classes. `:where()`
   contributes nothing to specificity, so these stay at (0,1,0) rather than the
   (0,1,1) a bare `.folks-about p` would have — which is what silently outranked
   `.folks-about__label`, `__map-core` and `__brief-heading` before. And the
   paragraph rule matches only UNCLASSED paragraphs, the ones `Prose` and the
   system intro render, so a classed paragraph wins on specificity rather than on
   its line number inside a 600-line section. Headings are all classed, so their
   type is set on the classes below; only the margin reset is shared. */
.folks-about :where(h2, p),
.folks-about-pillars :where(h2, p),
.folks-system-section :where(h2, p) {
  margin: 0;
}

.folks-about__brief-heading,
.folks-system-section__heading {
  font: 600 clamp(3.8rem, 4.45vw, 7.2rem) / 1.07 var(--_font-default);
  letter-spacing: -0.05em;
  color: inherit;
}
.folks-about :where(p:not([class])),
.folks-system-section :where(p:not([class])) {
  font: 400 1.7rem/1.7 var(--_font-default);
  color: inherit;
}

.folks-label,
.folks-about__label,
.folks-system-section__label,
.folks-about-pillars__number {
  font: 500 1.2rem/1.5 var(--_font-accent);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: inherit;
}
.folks-label::before,
.folks-about__label::before,
.folks-system-section__label::before {
  content: "[ ";
  color: var(--bracket);
}
.folks-label::after,
.folks-about__label::after,
.folks-system-section__label::after {
  content: " ]";
  color: var(--bracket);
}

/* The manifest eyebrow (AboutManifest.tsx) was a `.btn-line` button; as a label it keeps
   that button's white and its line box (1.6rem × 1.6, 1.8rem from 768px), so the
   manifest below it, which follows at a fixed flex gap, does not move. */
.mxd-section-manifest__controls > .folks-label {
  margin: 0;
  line-height: 2.56rem;
  color: var(--t-bright);
}
@media only screen and (min-width: 768px) {
  .mxd-section-manifest__controls > .folks-label {
    line-height: 2.88rem;
  }
}

/* The two forms name their audience (dolacz/page.tsx, kontakt/page.tsx): the manifest eyebrow
   over the creators' form, a `[ Dla marek ]` label over the contact title, and on each
   page one line sending the other audience to the other form. */
.folks-form-intro {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem 4rem;
  margin-bottom: 4rem;
}
.folks-form-intro__aside {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* Row gap clears the link's REC row (20px up, 10px tall) when the link wraps under the question. */
  gap: 3.2rem 1.6rem;
  margin: 0;
  font-size: 1.6rem;
  color: var(--t-medium);
}
.kontakt-audience {
  margin: 0 0 2.4rem;
  color: var(--t-bright);
}
.kontakt-creators {
  margin-top: 5rem;
}

/* The anchored brief (#biznes) clears the header. */
.folks-about__business {
  scroll-margin-top: 11rem;
}

/* --- the pillars, inside the hero ------------------------------------------
   Part of `.folks-page-hero`, so the hero's own bottom padding and the
   manifest's `.pre-list` gap both tighten — the vendor's 16–18.4rem below the
   manifesto would leave the pillars floating a screen away from it. Written
   unconditionally so it beats the vendor's own min-width rules from here, which
   port-fixes.css is loaded after. */

.folks-page-hero--pillars {
  padding-bottom: clamp(6.5rem, 7vw, 10.5rem);
}
.folks-page-hero--pillars .mxd-section-manifest.pre-list {
  padding-bottom: 6.5rem;
}

.folks-about-pillars {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4.5rem;
}

.folks-about-pillars__item {
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  align-content: start;
  column-gap: 1rem;
  border-top: 1px solid var(--folks-about-rule);
  padding-top: 2rem;
}

.folks-about-pillars__number {
  padding-top: 0.6rem;
  color: var(--accent);
}

.folks-about-pillars__title {
  font: 600 2.6rem/1.12 var(--_font-default);
  letter-spacing: -0.04em;
}

.folks-about-pillars__body {
  grid-column: 2;
  margin-top: 1.5rem;
  max-width: 36rem;
  font: 400 1.5rem/1.65 var(--_font-default);
  color: var(--folks-about-muted);
}

/* --- the business brief, on paper ------------------------------------------ */

.folks-about__business {
  padding-bottom: 12rem;
}

.folks-about__paper {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1.12fr;
  gap: 9%;
  padding: 6.4rem;
  background: var(--folks-paper);
  color: var(--folks-ink);
}

/* Torn top and bottom edges: one 12px band of the plate's own colour, clipped to
   a zig-zag and pulled 10px outside, so the tear reads as the sheet's edge
   rather than as a border. The bottom band is the same polygon turned round. */
.folks-about__paper::before,
.folks-about__paper::after {
  content: "";
  position: absolute;
  left: 0;
  width: 100%;
  height: 1.2rem;
  background: var(--folks-paper);
  clip-path: polygon(
    0 60%, 3% 30%, 6% 65%, 10% 40%, 14% 65%, 19% 25%, 24% 60%, 30% 35%, 35% 65%,
    42% 25%, 48% 60%, 54% 20%, 61% 55%, 69% 30%, 75% 65%, 81% 40%, 88% 65%,
    94% 35%, 100% 50%, 100% 100%, 0 100%
  );
}
.folks-about__paper::before {
  top: -1rem;
}
.folks-about__paper::after {
  bottom: -1rem;
  rotate: 180deg;
}

.folks-about__brief-heading {
  margin-top: 3.2rem;
  font-size: clamp(4.2rem, 5.3vw, 8.6rem);
}

.folks-about__stamp {
  display: inline-block;
  margin-top: 6rem;
  padding: 1.2rem 0;
  border-block: 1px solid color-mix(in srgb, var(--folks-ink) 40%, transparent);
  font: 500 1.1rem/1.5 var(--_font-accent);
  letter-spacing: 0.08em;
}
/* Each stored "→" drawn as a Lucide arrow (AboutEditorial.tsx `Stamp`). */
.folks-about__stamp-arrow {
  width: 1.1em;
  height: 1.1em;
  margin-inline: 0.2em;
  vertical-align: -0.2em;
}

.folks-about__brief-copy p + p {
  margin-top: 2.4rem;
}

.folks-about__goals {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem 2rem;
  margin: 2.8rem 0 0;
  padding: 2rem 0 0;
  list-style: none;
  border-top: 1px solid color-mix(in srgb, var(--folks-ink) 27%, transparent);
  font-size: 1.2rem;
  font-weight: 650;
}
/* The goals' lead-in arrow: Lucide's `ArrowUpRight`, an inline SVG, as every
   icon on the site is — never a character. "\2197" is in Unicode's emoji set,
   so on a platform whose text fonts lack it (iOS) it falls back to the colour
   emoji font and the row grows blue arrow stickers. */
.folks-about__goals li svg {
  width: 1.2em;
  height: 1.2em;
  margin-right: 0.6rem;
  vertical-align: -0.25em;
  color: var(--folks-about-coral-ink);
}

/* --- widths --------------------------------------------------------------- */

@media only screen and (min-width: 1800px) {
  .folks-about :where(p:not([class])),
  .folks-system-section :where(p:not([class])) {
    font-size: 2rem;
  }
  .folks-about-pillars__body {
    font-size: 1.7rem;
  }
}

@media only screen and (max-width: 1100px) {
  .folks-about__paper {
    grid-template-columns: 0.85fr 1.15fr;
    gap: 4rem;
    padding: 4rem;
  }
}

@media only screen and (max-width: 700px) {
  .folks-about :where(p:not([class])),
  .folks-system-section :where(p:not([class])) {
    font-size: 1.6rem;
    line-height: 1.7;
  }
  .folks-about__brief-heading,
  .folks-system-section__heading {
    font-size: 3.9rem;
  }
  .folks-label,
  .folks-about__label,
  .folks-system-section__label,
  .folks-about-pillars__number {
    font-size: 1rem;
    letter-spacing: 0.05em;
  }

  .folks-page-hero--pillars .mxd-section-manifest.pre-list {
    padding-bottom: 4rem;
  }
  .folks-about-pillars {
    grid-template-columns: 1fr;
    gap: 2rem;
  }
  .folks-about-pillars__item {
    grid-template-columns: 3.5rem 1fr;
    gap: 0.5rem 1.2rem;
    padding-top: 1.8rem;
  }
  .folks-about-pillars__title {
    font-size: 2.4rem;
  }
  .folks-about-pillars__body {
    margin-top: 0.5rem;
    max-width: none;
    font-size: 1.4rem;
  }

  .folks-about__business {
    padding-bottom: 7.5rem;
  }
  .folks-about__paper {
    grid-template-columns: 1fr;
    gap: 2.8rem;
    padding: 3.2rem 2.4rem;
  }
  .folks-about__brief-heading {
    margin-top: 2rem;
    font-size: 4.8rem;
  }
  .folks-about__stamp {
    margin-top: 2.6rem;
    /* The mock had this at 9px; 1rem is the site's readability floor (the group
       wheel's spec states it, and it applies to a mono stamp just as much). */
    font-size: 1rem;
  }
  .folks-about__goals {
    gap: 1rem;
    font-size: 1.1rem;
  }
}

/* --- 14b. Channel system (/jak-dzialamy) -----------------------------------
   "Influencer marketing jako system" (`SystemFlow.tsx`), moved here from the
   About page's editorial block (openspec move-system-to-how-we-work) after the
   five-slide process. Its own wrapper, `.folks-system-section`, which shares
   §14's tokens, type and bracketed label through their selector lists rather
   than a copy of them, and keeps §14's own 1100px and 700px breakpoints: the
   composition was approved at those. */

/* The anchored section (#system) clears the header. */
.folks-system-section__inner {
  scroll-margin-top: 11rem;
  padding-block: 12rem 6rem;
}
.folks-system-section__label {
  margin-bottom: 3rem;
  color: var(--accent);
}

.folks-system-section__intro {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: 6rem;
  align-items: start;
}
/* The paragraph beside the heading is the section's lead, in the hero
   manifest's register (main.css `.manifest`: bold, bright, tight) at a reading
   size, one step under the heading's 600 display. The two paragraphs under the
   diagram stay body copy, in full white. Top-aligned with the heading: the lead
   is the taller of the two, and bottom alignment left a gap above the heading. */
.folks-system-section__intro > p {
  font: 600 clamp(2.2rem, 1.8vw, 2.6rem) / 1.35 var(--_font-default);
  letter-spacing: -0.03em;
  color: var(--t-bright);
}

/* The system diagram (SystemDiagram.tsx): option 3 "Przepływ treści", drawn
   on the paper plate in ink. Every mark that must read against the paper takes
   the on-paper coral (--folks-about-coral-ink, 5.5:1), not --accent (2.5:1).

   Font sizes are SVG user units, so they scale with the drawing. The desktop
   viewBox is 1200 wide; below 1100px it would draw its labels at ~7px, so the
   stacked composition takes over there, not at the page's 700px breakpoint,
   and is capped so a tablet does not blow it up to poster size. The plate has
   no side padding for the same reason — the drawing keeps its own margins, and
   every CSS px taken off its width comes off its scale. */
.folks-system {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  margin: 6rem 0;
  padding-block: 1.6rem 2rem;
  background: var(--folks-paper);
}
.folks-system__svg {
  display: block;
  width: 100%;
  height: auto;
  /* The whole drawing in the wordmark's face, like the home hero headline.
     Set once here rather than per label: SVG text inherits font-family, so the
     rules below only have to state the weight each role wants. The weights run
     500–800 against Manrope's old 400–500 — Raleway's lower cuts are markedly
     lighter, and these labels are 12.5–15px on paper. */
  font-family: var(--font-raleway), "Raleway", sans-serif;
}
.folks-system__svg--mobile {
  display: none;
}
.folks-system__branch {
  fill: none;
  stroke: #4b453c;
  stroke-opacity: 0.28;
}
.folks-system__return {
  fill: none;
  stroke: var(--folks-about-coral-ink);
  stroke-opacity: 0.5;
  stroke-dasharray: 3 6;
}
.folks-system__return-head {
  fill: none;
  stroke: var(--folks-about-coral-ink);
  stroke-opacity: 0.7;
}
.folks-system__tick,
.folks-system__sink {
  fill: var(--folks-about-coral-ink);
}
/* Sized for the NARROWEST width each drawing is shown at, not for 1440: the
   desktop viewBox is at 0.82 scale at 1101px, the phone's at 0.68 at 360px, and
   every label must still land at 10 CSS px or more. */
.folks-system__eyebrow,
.folks-system__number {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.7px;
}
.folks-system__eyebrow,
.folks-system__role,
.folks-system__feedback {
  fill: #69655e;
}
.folks-system__number {
  fill: var(--folks-about-coral-ink);
}
/* The two core words in the wordmark's face, like the home hero (§ .mxd-hero-05__headline).
   800 because that is the only Raleway weight next/font loads; asking for 500 here would
   render the same file anyway, so the weight is stated rather than implied. Tracking in em,
   not the -1.3px tuned for Manrope 500. */
.folks-system__name {
  fill: var(--folks-ink);
  font-size: 34px;
  font-weight: 800;
  letter-spacing: -0.02em;
}
.folks-system__name--sink {
  font-size: 28px;
}
.folks-system__role {
  font-size: 14px;
  font-weight: 500;
}
.folks-system__channel {
  fill: #24231f;
  font-size: 15px;
  font-weight: 600;
}
.folks-system__feedback {
  font-size: 13px;
  font-weight: 500;
}
.folks-system__feedback-arrow {
  color: #69655e;
}
/* The phone composition is drawn at 440 wide and shown as narrow as ~300 CSS
   px, so its words are set larger in its own units to stay readable there. */
.folks-system__svg--mobile :is(.folks-system__eyebrow, .folks-system__number) {
  font-size: 15px;
  letter-spacing: 0.5px;
}
.folks-system__svg--mobile :is(.folks-system__channel, .folks-system__role) {
  font-size: 15px;
}
.folks-system__svg--mobile .folks-system__name {
  font-size: 32px;
  letter-spacing: -0.8px;
}
.folks-system__svg--mobile .folks-system__feedback {
  font-size: 16px;
}
/* In the flow under the drawing rather than over it: at 390px an overlaid
   button would sit on the feedback line. */
.folks-system__pause {
  display: inline-flex;
  align-items: center;
  gap: 0.8rem;
  min-height: 4.4rem;
  margin-right: 1.6rem;
  padding: 0 1.4rem;
  border: 1px solid color-mix(in srgb, var(--folks-ink) 30%, transparent);
  background: transparent;
  color: var(--folks-ink);
  font: 500 1.1rem var(--_font-accent);
  cursor: pointer;
}
.folks-system__pause svg {
  width: 1.4rem;
  height: 1.4rem;
  color: var(--folks-about-coral-ink);
}
.folks-system__pause:focus-visible {
  outline: 2px solid var(--folks-about-coral-ink);
  outline-offset: 3px;
}

.folks-system-section__copy {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6rem;
  color: var(--t-bright);
}

@media only screen and (max-width: 1100px) {
  .folks-system-section__intro {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 3.2rem;
  }
  .folks-system-section__copy {
    gap: 2.4rem;
  }
  .folks-system__svg--desktop {
    display: none;
  }
  .folks-system__svg--mobile {
    display: block;
    max-width: 56rem;
    margin-right: auto;
  }
}

@media only screen and (max-width: 700px) {
  .folks-system-section__inner {
    padding-block: 7.5rem 6rem;
  }
  .folks-system-section__intro,
  .folks-system-section__copy {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }
  .folks-system {
    margin: 3.2rem 0;
  }
}

/* The diagram's travelling signals are the section's only motion. They go
   entirely — routes, arrows and labels stay — and the pause button goes with
   them, having nothing left to pause. Nothing here scrolls or reveals on its
   own. */
@media (prefers-reduced-motion: reduce) {
  .folks-system__signal,
  .folks-system__pause {
    display: none;
  }
}

/* --- 15. Article author box: the name is a <p> (seo-foundation) -------------
   The box's name carried the vendor's `h4` typography by being an `<h4>`, and
   an h4 directly under an article outlined h1 → h2 skips a heading level —
   the `heading-order` failure PSI reports on every post (audit §2). The
   element is now a `<p>` and the type moves onto the class, value for value
   from main.css `h4` (3rem / 3.6rem ≥768 / 4rem ≥1200), so nothing about the
   box's appearance changes. `margin: 0` restates what the h4 computed to.

   Longhand, not the `font:` shorthand main.css uses: the shorthand would also
   set `line-height`, and the block above this one in main.css pins
   `.mxd-article-author__name { line-height: 1 }` — which already beat the h4's
   own 1.2. Measured: 30/36/40px at 390/800/1440, line-height 1, before and
   after. */
.mxd-article-author__name {
  font-family: var(--_font-default);
  font-weight: 700;
  font-size: 3rem;
  letter-spacing: -0.1rem;
  color: var(--t-bright);
  margin: 0;
}
@media only screen and (min-width: 768px) {
  .mxd-article-author__name {
    font-size: 3.6rem;
  }
}
@media only screen and (min-width: 1200px) {
  .mxd-article-author__name {
    font-size: 4rem;
  }
}
